1e0dac50fSopenharmony_ci/*
2e0dac50fSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3e0dac50fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4e0dac50fSopenharmony_ci * you may not use this file except in compliance with the License.
5e0dac50fSopenharmony_ci * You may obtain a copy of the License at
6e0dac50fSopenharmony_ci *
7e0dac50fSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8e0dac50fSopenharmony_ci *
9e0dac50fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10e0dac50fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11e0dac50fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12e0dac50fSopenharmony_ci * See the License for the specific language governing permissions and
13e0dac50fSopenharmony_ci * limitations under the License.
14e0dac50fSopenharmony_ci */
15e0dac50fSopenharmony_ci#include "snapshot_utils.h"
16e0dac50fSopenharmony_ci
17e0dac50fSopenharmony_ci#include <cerrno>
18e0dac50fSopenharmony_ci#include <climits>
19e0dac50fSopenharmony_ci#include <cstdio>
20e0dac50fSopenharmony_ci#include <cstdlib>
21e0dac50fSopenharmony_ci#include <ctime>
22e0dac50fSopenharmony_ci#include <getopt.h>
23e0dac50fSopenharmony_ci#include <hitrace_meter.h>
24e0dac50fSopenharmony_ci#include <image_type.h>
25e0dac50fSopenharmony_ci#include <iostream>
26e0dac50fSopenharmony_ci#include <ostream>
27e0dac50fSopenharmony_ci#include <csetjmp>
28e0dac50fSopenharmony_ci#include <pixel_map.h>
29e0dac50fSopenharmony_ci#include <securec.h>
30e0dac50fSopenharmony_ci#include <string>
31e0dac50fSopenharmony_ci#include <sys/time.h>
32e0dac50fSopenharmony_ci
33e0dac50fSopenharmony_ci#include "image_packer.h"
34e0dac50fSopenharmony_ci#include "jpeglib.h"
35e0dac50fSopenharmony_ci
36e0dac50fSopenharmony_ciusing namespace OHOS::Rosen;
37e0dac50fSopenharmony_ci
38e0dac50fSopenharmony_cinamespace OHOS {
39e0dac50fSopenharmony_ciconstexpr int MAX_TIME_STR_LEN = 40;
40e0dac50fSopenharmony_ciconstexpr int YEAR_SINCE = 1900;
41e0dac50fSopenharmony_ciconstexpr int32_t RGB565_PIXEL_BYTES = 2;
42e0dac50fSopenharmony_ciconstexpr int32_t RGB888_PIXEL_BYTES = 3;
43e0dac50fSopenharmony_ciconstexpr int32_t RGBA8888_PIXEL_BYTES = 4;
44e0dac50fSopenharmony_ciconstexpr uint8_t B_INDEX = 0;
45e0dac50fSopenharmony_ciconstexpr uint8_t G_INDEX = 1;
46e0dac50fSopenharmony_ciconstexpr uint8_t R_INDEX = 2;
47e0dac50fSopenharmony_ciconstexpr uint8_t SHIFT_2_BIT = 2;
48e0dac50fSopenharmony_ciconstexpr uint8_t SHIFT_3_BIT = 3;
49e0dac50fSopenharmony_ciconstexpr uint8_t SHIFT_5_BIT = 5;
50e0dac50fSopenharmony_ciconstexpr uint8_t SHIFT_8_BIT = 8;
51e0dac50fSopenharmony_ciconstexpr uint8_t SHIFT_11_BIT = 11;
52e0dac50fSopenharmony_ciconstexpr uint8_t SHIFT_16_BIT = 16;
53e0dac50fSopenharmony_ci
54e0dac50fSopenharmony_ciconstexpr uint16_t RGB565_MASK_BLUE = 0xF800;
55e0dac50fSopenharmony_ciconstexpr uint16_t RGB565_MASK_GREEN = 0x07E0;
56e0dac50fSopenharmony_ciconstexpr uint16_t RGB565_MASK_RED = 0x001F;
57e0dac50fSopenharmony_ciconstexpr uint32_t RGBA8888_MASK_BLUE = 0x000000FF;
58e0dac50fSopenharmony_ciconstexpr uint32_t RGBA8888_MASK_GREEN = 0x0000FF00;
59e0dac50fSopenharmony_ciconstexpr uint32_t RGBA8888_MASK_RED = 0x00FF0000;
60e0dac50fSopenharmony_ci
61e0dac50fSopenharmony_ciconstexpr uint8_t PNG_PACKER_QUALITY = 100;
62e0dac50fSopenharmony_ciconstexpr uint8_t PACKER_QUALITY = 75;
63e0dac50fSopenharmony_ciconstexpr uint32_t PACKER_SUCCESS = 0;
64e0dac50fSopenharmony_cistruct MissionErrorMgr : public jpeg_error_mgr {
65e0dac50fSopenharmony_ci    jmp_buf environment;
66e0dac50fSopenharmony_ci};
67e0dac50fSopenharmony_ci
68e0dac50fSopenharmony_civoid mission_error_exit(j_common_ptr cinfo)
69e0dac50fSopenharmony_ci{
70e0dac50fSopenharmony_ci    if (cinfo == nullptr || cinfo->err == nullptr) {
71e0dac50fSopenharmony_ci        std::cout << __func__ << ": param is invalid." << std::endl;
72e0dac50fSopenharmony_ci        return;
73e0dac50fSopenharmony_ci    }
74e0dac50fSopenharmony_ci    auto err = reinterpret_cast<MissionErrorMgr*>(cinfo->err);
75e0dac50fSopenharmony_ci    longjmp(err->environment, 1);
76e0dac50fSopenharmony_ci}
77e0dac50fSopenharmony_ci
78e0dac50fSopenharmony_ciconst char *VALID_SNAPSHOT_PATH = "/data/local/tmp";
79e0dac50fSopenharmony_ciconst char *DEFAULT_SNAPSHOT_PREFIX = "/snapshot";
80e0dac50fSopenharmony_ciconst char *VALID_SNAPSHOT_SUFFIX = ".jpeg";
81e0dac50fSopenharmony_ciconst char *VALID_SNAPSHOT_PNG_SUFFIX = ".png";
82e0dac50fSopenharmony_ci
83e0dac50fSopenharmony_civoid SnapShotUtils::PrintUsage(const std::string& cmdLine)
84e0dac50fSopenharmony_ci{
85e0dac50fSopenharmony_ci    std::cout << "usage: " << cmdLine.c_str() <<
86e0dac50fSopenharmony_ci        " [-i displayId] [-f output_file] [-w width] [-h height] [-t type] [-m]" << std::endl;
87e0dac50fSopenharmony_ci}
88e0dac50fSopenharmony_ci
89e0dac50fSopenharmony_cistd::string SnapShotUtils::GenerateFileName(std::string fileType, int offset)
90e0dac50fSopenharmony_ci{
91e0dac50fSopenharmony_ci    timeval tv;
92e0dac50fSopenharmony_ci    std::string fileName = VALID_SNAPSHOT_PATH;
93e0dac50fSopenharmony_ci
94e0dac50fSopenharmony_ci    fileName += DEFAULT_SNAPSHOT_PREFIX;
95e0dac50fSopenharmony_ci    if (gettimeofday(&tv, nullptr) == 0) {
96e0dac50fSopenharmony_ci        tv.tv_sec += offset; // add offset second
97e0dac50fSopenharmony_ci        struct tm *tmVal = localtime(&tv.tv_sec);
98e0dac50fSopenharmony_ci        if (tmVal != nullptr) {
99e0dac50fSopenharmony_ci            char timeStr[MAX_TIME_STR_LEN] = { 0 };
100e0dac50fSopenharmony_ci            snprintf_s(timeStr, sizeof(timeStr), sizeof(timeStr) - 1,
101e0dac50fSopenharmony_ci                "_%04d-%02d-%02d_%02d-%02d-%02d",
102e0dac50fSopenharmony_ci                tmVal->tm_year + YEAR_SINCE, tmVal->tm_mon + 1, tmVal->tm_mday,
103e0dac50fSopenharmony_ci                tmVal->tm_hour, tmVal->tm_min, tmVal->tm_sec);
104e0dac50fSopenharmony_ci            fileName += timeStr;
105e0dac50fSopenharmony_ci        }
106e0dac50fSopenharmony_ci    }
107e0dac50fSopenharmony_ci    fileName += (fileType == "png") ? VALID_SNAPSHOT_PNG_SUFFIX : VALID_SNAPSHOT_SUFFIX;
108e0dac50fSopenharmony_ci    return fileName;
109e0dac50fSopenharmony_ci}
110e0dac50fSopenharmony_ci
111e0dac50fSopenharmony_cibool SnapShotUtils::CheckFileNameValid(const std::string& fileName, std::string fileType)
112e0dac50fSopenharmony_ci{
113e0dac50fSopenharmony_ci    std::cout << "fileType: " << fileType << std::endl;
114e0dac50fSopenharmony_ci    size_t fileMinLength = (fileType == "png") ? strlen(VALID_SNAPSHOT_PNG_SUFFIX) : strlen(VALID_SNAPSHOT_SUFFIX);
115e0dac50fSopenharmony_ci    if (fileName.length() <= fileMinLength) {
116e0dac50fSopenharmony_ci        std::cout << "error: fileName " << fileName.c_str() << " invalid, file length too short!" << std::endl;
117e0dac50fSopenharmony_ci        return false;
118e0dac50fSopenharmony_ci    }
119e0dac50fSopenharmony_ci    // check file path
120e0dac50fSopenharmony_ci    std::string fileDir = fileName;
121e0dac50fSopenharmony_ci    auto pos = fileDir.find_last_of("/");
122e0dac50fSopenharmony_ci    if (pos != std::string::npos) {
123e0dac50fSopenharmony_ci        fileDir.erase(pos + 1);
124e0dac50fSopenharmony_ci    } else {
125e0dac50fSopenharmony_ci        fileDir = "."; // current work dir
126e0dac50fSopenharmony_ci    }
127e0dac50fSopenharmony_ci    char resolvedPath[PATH_MAX] = { 0 };
128e0dac50fSopenharmony_ci    char *realPath = realpath(fileDir.c_str(), resolvedPath);
129e0dac50fSopenharmony_ci    if (realPath == nullptr) {
130e0dac50fSopenharmony_ci        std::cout << "error: fileName " << fileName.c_str() << " invalid, realpath nullptr!" << std::endl;
131e0dac50fSopenharmony_ci        return false;
132e0dac50fSopenharmony_ci    }
133e0dac50fSopenharmony_ci    if (strncmp(realPath, VALID_SNAPSHOT_PATH, strlen(VALID_SNAPSHOT_PATH)) != 0) {
134e0dac50fSopenharmony_ci        std::cout << "error: fileName " << fileName.c_str() << " invalid, realpath "
135e0dac50fSopenharmony_ci            << realPath << " must dump at dir: " << VALID_SNAPSHOT_PATH << std::endl;
136e0dac50fSopenharmony_ci        return false;
137e0dac50fSopenharmony_ci    }
138e0dac50fSopenharmony_ci
139e0dac50fSopenharmony_ci    // check file suffix
140e0dac50fSopenharmony_ci    const char *fileNameSuffix = fileName.c_str() + (fileName.length() - fileMinLength);
141e0dac50fSopenharmony_ci    const char *fileSuffix = (fileType == "png") ? VALID_SNAPSHOT_PNG_SUFFIX : VALID_SNAPSHOT_SUFFIX;
142e0dac50fSopenharmony_ci    if (strncmp(fileNameSuffix, fileSuffix, fileMinLength) == 0) {
143e0dac50fSopenharmony_ci        return true; // valid suffix
144e0dac50fSopenharmony_ci    }
145e0dac50fSopenharmony_ci    std::cout << "error: fileName " << fileName.c_str() << " invalid, suffix must be " << fileSuffix << std::endl;
146e0dac50fSopenharmony_ci    return false;
147e0dac50fSopenharmony_ci}
148e0dac50fSopenharmony_ci
149e0dac50fSopenharmony_cibool SnapShotUtils::CheckWHValid(int32_t param)
150e0dac50fSopenharmony_ci{
151e0dac50fSopenharmony_ci    return (param > 0) && (param <= DisplayManager::MAX_RESOLUTION_SIZE_SCREENSHOT);
152e0dac50fSopenharmony_ci}
153e0dac50fSopenharmony_ci
154e0dac50fSopenharmony_cibool SnapShotUtils::CheckWidthAndHeightValid(int32_t w, int32_t h)
155e0dac50fSopenharmony_ci{
156e0dac50fSopenharmony_ci    return CheckWHValid(w) && CheckWHValid(h);
157e0dac50fSopenharmony_ci}
158e0dac50fSopenharmony_ci
159e0dac50fSopenharmony_cibool SnapShotUtils::CheckParamValid(const WriteToJpegParam& param)
160e0dac50fSopenharmony_ci{
161e0dac50fSopenharmony_ci    switch (param.format) {
162e0dac50fSopenharmony_ci        case Media::PixelFormat::RGBA_8888:
163e0dac50fSopenharmony_ci            if (param.stride != param.width * RGBA8888_PIXEL_BYTES) {
164e0dac50fSopenharmony_ci                return false;
165e0dac50fSopenharmony_ci            }
166e0dac50fSopenharmony_ci            break;
167e0dac50fSopenharmony_ci        case Media::PixelFormat::RGB_565:
168e0dac50fSopenharmony_ci            if (param.stride != param.width * RGB565_PIXEL_BYTES) {
169e0dac50fSopenharmony_ci                return false;
170e0dac50fSopenharmony_ci            }
171e0dac50fSopenharmony_ci            break;
172e0dac50fSopenharmony_ci        case Media::PixelFormat::RGB_888:
173e0dac50fSopenharmony_ci            if (param.stride != param.width * RGB888_PIXEL_BYTES) {
174e0dac50fSopenharmony_ci                return false;
175e0dac50fSopenharmony_ci            }
176e0dac50fSopenharmony_ci            break;
177e0dac50fSopenharmony_ci        default:
178e0dac50fSopenharmony_ci            std::cout << __func__ << ": unsupported pixel format: " <<
179e0dac50fSopenharmony_ci                static_cast<uint32_t>(param.format) << std::endl;
180e0dac50fSopenharmony_ci            return false;
181e0dac50fSopenharmony_ci    }
182e0dac50fSopenharmony_ci    if (!CheckWidthAndHeightValid(param.width, param.height)) {
183e0dac50fSopenharmony_ci        return false;
184e0dac50fSopenharmony_ci    }
185e0dac50fSopenharmony_ci    if (param.data == nullptr) {
186e0dac50fSopenharmony_ci        return false;
187e0dac50fSopenharmony_ci    }
188e0dac50fSopenharmony_ci    return true;
189e0dac50fSopenharmony_ci}
190e0dac50fSopenharmony_ci
191e0dac50fSopenharmony_cibool SnapShotUtils::RGBA8888ToRGB888(const uint8_t* rgba8888Buf, uint8_t* rgb888Buf, int32_t size)
192e0dac50fSopenharmony_ci{
193e0dac50fSopenharmony_ci    if (rgba8888Buf == nullptr || rgb888Buf == nullptr || size <= 0) {
194e0dac50fSopenharmony_ci        std::cout << __func__ << ": params are invalid." << std::endl;
195e0dac50fSopenharmony_ci        return false;
196e0dac50fSopenharmony_ci    }
197e0dac50fSopenharmony_ci    const uint32_t* rgba8888 = reinterpret_cast<const uint32_t*>(rgba8888Buf);
198e0dac50fSopenharmony_ci    for (int32_t i = 0; i < size; i++) {
199e0dac50fSopenharmony_ci        rgb888Buf[i * RGB888_PIXEL_BYTES + R_INDEX] = (rgba8888[i] & RGBA8888_MASK_RED) >> SHIFT_16_BIT;
200e0dac50fSopenharmony_ci        rgb888Buf[i * RGB888_PIXEL_BYTES + G_INDEX] = (rgba8888[i] & RGBA8888_MASK_GREEN) >> SHIFT_8_BIT;
201e0dac50fSopenharmony_ci        rgb888Buf[i * RGB888_PIXEL_BYTES + B_INDEX] = rgba8888[i] & RGBA8888_MASK_BLUE;
202e0dac50fSopenharmony_ci    }
203e0dac50fSopenharmony_ci    return true;
204e0dac50fSopenharmony_ci}
205e0dac50fSopenharmony_ci
206e0dac50fSopenharmony_cibool SnapShotUtils::RGB565ToRGB888(const uint8_t* rgb565Buf, uint8_t* rgb888Buf, int32_t size)
207e0dac50fSopenharmony_ci{
208e0dac50fSopenharmony_ci    if (rgb565Buf == nullptr || rgb888Buf == nullptr || size <= 0) {
209e0dac50fSopenharmony_ci        std::cout << __func__ << ": params are invalid." << std::endl;
210e0dac50fSopenharmony_ci        return false;
211e0dac50fSopenharmony_ci    }
212e0dac50fSopenharmony_ci    const uint16_t* rgb565 = reinterpret_cast<const uint16_t*>(rgb565Buf);
213e0dac50fSopenharmony_ci    for (int32_t i = 0; i < size; i++) {
214e0dac50fSopenharmony_ci        rgb888Buf[i * RGB888_PIXEL_BYTES + R_INDEX] = (rgb565[i] & RGB565_MASK_RED);
215e0dac50fSopenharmony_ci        rgb888Buf[i * RGB888_PIXEL_BYTES + G_INDEX] = (rgb565[i] & RGB565_MASK_GREEN) >> SHIFT_5_BIT;
216e0dac50fSopenharmony_ci        rgb888Buf[i * RGB888_PIXEL_BYTES + B_INDEX] = (rgb565[i] & RGB565_MASK_BLUE) >> SHIFT_11_BIT;
217e0dac50fSopenharmony_ci        rgb888Buf[i * RGB888_PIXEL_BYTES + R_INDEX] <<= SHIFT_3_BIT;
218e0dac50fSopenharmony_ci        rgb888Buf[i * RGB888_PIXEL_BYTES + G_INDEX] <<= SHIFT_2_BIT;
219e0dac50fSopenharmony_ci        rgb888Buf[i * RGB888_PIXEL_BYTES + B_INDEX] <<= SHIFT_3_BIT;
220e0dac50fSopenharmony_ci    }
221e0dac50fSopenharmony_ci    return true;
222e0dac50fSopenharmony_ci}
223e0dac50fSopenharmony_ci
224e0dac50fSopenharmony_ci// The method will NOT release file.
225e0dac50fSopenharmony_cibool SnapShotUtils::WriteRgb888ToJpeg(FILE* file, uint32_t width, uint32_t height, const uint8_t* data)
226e0dac50fSopenharmony_ci{
227e0dac50fSopenharmony_ci    if (data == nullptr) {
228e0dac50fSopenharmony_ci        std::cout << "error: data error, nullptr!" << std::endl;
229e0dac50fSopenharmony_ci        return false;
230e0dac50fSopenharmony_ci    }
231e0dac50fSopenharmony_ci
232e0dac50fSopenharmony_ci    if (file == nullptr) {
233e0dac50fSopenharmony_ci        std::cout << "error: file is null" << std::endl;
234e0dac50fSopenharmony_ci        return false;
235e0dac50fSopenharmony_ci    }
236e0dac50fSopenharmony_ci
237e0dac50fSopenharmony_ci    struct jpeg_compress_struct jpeg;
238e0dac50fSopenharmony_ci    struct MissionErrorMgr jerr;
239e0dac50fSopenharmony_ci    jpeg.err = jpeg_std_error(&jerr);
240e0dac50fSopenharmony_ci    jerr.error_exit = mission_error_exit;
241e0dac50fSopenharmony_ci    if (setjmp(jerr.environment)) {
242e0dac50fSopenharmony_ci        jpeg_destroy_compress(&jpeg);
243e0dac50fSopenharmony_ci        std::cout << "error: lib jpeg exit with error!" << std::endl;
244e0dac50fSopenharmony_ci        return false;
245e0dac50fSopenharmony_ci    }
246e0dac50fSopenharmony_ci
247e0dac50fSopenharmony_ci    jpeg_create_compress(&jpeg);
248e0dac50fSopenharmony_ci    jpeg.image_width = width;
249e0dac50fSopenharmony_ci    jpeg.image_height = height;
250e0dac50fSopenharmony_ci    jpeg.input_components = RGB888_PIXEL_BYTES;
251e0dac50fSopenharmony_ci    jpeg.in_color_space = JCS_RGB;
252e0dac50fSopenharmony_ci    jpeg_set_defaults(&jpeg);
253e0dac50fSopenharmony_ci
254e0dac50fSopenharmony_ci    constexpr int32_t quality = 75;
255e0dac50fSopenharmony_ci    jpeg_set_quality(&jpeg, quality, TRUE);
256e0dac50fSopenharmony_ci
257e0dac50fSopenharmony_ci    jpeg_stdio_dest(&jpeg, file);
258e0dac50fSopenharmony_ci    jpeg_start_compress(&jpeg, TRUE);
259e0dac50fSopenharmony_ci    JSAMPROW rowPointer[1];
260e0dac50fSopenharmony_ci    for (uint32_t i = 0; i < jpeg.image_height; i++) {
261e0dac50fSopenharmony_ci        rowPointer[0] = const_cast<uint8_t *>(data + i * jpeg.image_width * RGB888_PIXEL_BYTES);
262e0dac50fSopenharmony_ci        (void)jpeg_write_scanlines(&jpeg, rowPointer, 1);
263e0dac50fSopenharmony_ci    }
264e0dac50fSopenharmony_ci
265e0dac50fSopenharmony_ci    jpeg_finish_compress(&jpeg);
266e0dac50fSopenharmony_ci    jpeg_destroy_compress(&jpeg);
267e0dac50fSopenharmony_ci    return true;
268e0dac50fSopenharmony_ci}
269e0dac50fSopenharmony_ci
270e0dac50fSopenharmony_cibool SnapShotUtils::WriteToJpeg(const std::string& fileName, const WriteToJpegParam& param)
271e0dac50fSopenharmony_ci{
272e0dac50fSopenharmony_ci    bool ret = false;
273e0dac50fSopenharmony_ci    if (!CheckFileNameValid(fileName)) {
274e0dac50fSopenharmony_ci        return ret;
275e0dac50fSopenharmony_ci    }
276e0dac50fSopenharmony_ci    if (!CheckParamValid(param)) {
277e0dac50fSopenharmony_ci        std::cout << "error: invalid param." << std::endl;
278e0dac50fSopenharmony_ci        return ret;
279e0dac50fSopenharmony_ci    }
280e0dac50fSopenharmony_ci    HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "snapshot:WriteToJpeg(%s)", fileName.c_str());
281e0dac50fSopenharmony_ci
282e0dac50fSopenharmony_ci    FILE *file = fopen(fileName.c_str(), "wb");
283e0dac50fSopenharmony_ci    if (file == nullptr) {
284e0dac50fSopenharmony_ci        std::cout << "error: open file [" << fileName.c_str() << "] error, " << errno << "!" << std::endl;
285e0dac50fSopenharmony_ci        return ret;
286e0dac50fSopenharmony_ci    }
287e0dac50fSopenharmony_ci    std::cout << "snapshot: pixel format is: " << static_cast<uint32_t>(param.format) << std::endl;
288e0dac50fSopenharmony_ci    if (param.format == Media::PixelFormat::RGBA_8888) {
289e0dac50fSopenharmony_ci        int32_t rgb888Size = param.stride * param.height * RGB888_PIXEL_BYTES / RGBA8888_PIXEL_BYTES;
290e0dac50fSopenharmony_ci        uint8_t *rgb888 = new uint8_t[rgb888Size];
291e0dac50fSopenharmony_ci        ret = RGBA8888ToRGB888(param.data, rgb888, rgb888Size / RGB888_PIXEL_BYTES);
292e0dac50fSopenharmony_ci        if (ret) {
293e0dac50fSopenharmony_ci            std::cout << "snapshot: convert rgba8888 to rgb888 successfully." << std::endl;
294e0dac50fSopenharmony_ci            ret = WriteRgb888ToJpeg(file, param.width, param.height, rgb888);
295e0dac50fSopenharmony_ci        }
296e0dac50fSopenharmony_ci        delete[] rgb888;
297e0dac50fSopenharmony_ci    } else if (param.format == Media::PixelFormat::RGB_565) {
298e0dac50fSopenharmony_ci        int32_t rgb888Size = param.stride * param.height * RGB888_PIXEL_BYTES / RGB565_PIXEL_BYTES;
299e0dac50fSopenharmony_ci        uint8_t *rgb888 = new uint8_t[rgb888Size];
300e0dac50fSopenharmony_ci        ret = RGB565ToRGB888(param.data, rgb888, rgb888Size / RGB888_PIXEL_BYTES);
301e0dac50fSopenharmony_ci        if (ret) {
302e0dac50fSopenharmony_ci            std::cout << "snapshot: convert rgb565 to rgb888 successfully." << std::endl;
303e0dac50fSopenharmony_ci            ret = WriteRgb888ToJpeg(file, param.width, param.height, rgb888);
304e0dac50fSopenharmony_ci        }
305e0dac50fSopenharmony_ci        delete[] rgb888;
306e0dac50fSopenharmony_ci    } else if (param.format == Media::PixelFormat::RGB_888) {
307e0dac50fSopenharmony_ci        ret = WriteRgb888ToJpeg(file, param.width, param.height, param.data);
308e0dac50fSopenharmony_ci    } else {
309e0dac50fSopenharmony_ci        std::cout << "snapshot: invalid pixel format." << std::endl;
310e0dac50fSopenharmony_ci    }
311e0dac50fSopenharmony_ci    if (fclose(file) != 0) {
312e0dac50fSopenharmony_ci        std::cout << "error: close file failed!" << std::endl;
313e0dac50fSopenharmony_ci        ret = false;
314e0dac50fSopenharmony_ci    }
315e0dac50fSopenharmony_ci    return ret;
316e0dac50fSopenharmony_ci}
317e0dac50fSopenharmony_ci
318e0dac50fSopenharmony_cibool SnapShotUtils::WriteToJpeg(int fd, const WriteToJpegParam& param)
319e0dac50fSopenharmony_ci{
320e0dac50fSopenharmony_ci    bool ret = false;
321e0dac50fSopenharmony_ci    if (!CheckParamValid(param)) {
322e0dac50fSopenharmony_ci        std::cout << "error: invalid param." << std::endl;
323e0dac50fSopenharmony_ci        return ret;
324e0dac50fSopenharmony_ci    }
325e0dac50fSopenharmony_ci
326e0dac50fSopenharmony_ci    FILE *file = fdopen(fd, "wb");
327e0dac50fSopenharmony_ci    if (file == nullptr) {
328e0dac50fSopenharmony_ci        return ret;
329e0dac50fSopenharmony_ci    }
330e0dac50fSopenharmony_ci    std::cout << "snapshot: pixel format is: " << static_cast<uint32_t>(param.format) << std::endl;
331e0dac50fSopenharmony_ci    if (param.format == Media::PixelFormat::RGBA_8888) {
332e0dac50fSopenharmony_ci        int32_t rgb888Size = param.stride * param.height * RGB888_PIXEL_BYTES / RGBA8888_PIXEL_BYTES;
333e0dac50fSopenharmony_ci        uint8_t *rgb888 = new uint8_t[rgb888Size];
334e0dac50fSopenharmony_ci        ret = RGBA8888ToRGB888(param.data, rgb888, rgb888Size / RGB888_PIXEL_BYTES);
335e0dac50fSopenharmony_ci        if (ret) {
336e0dac50fSopenharmony_ci            std::cout << "snapshot: convert rgba8888 to rgb888 successfully." << std::endl;
337e0dac50fSopenharmony_ci            ret = WriteRgb888ToJpeg(file, param.width, param.height, rgb888);
338e0dac50fSopenharmony_ci        }
339e0dac50fSopenharmony_ci        delete[] rgb888;
340e0dac50fSopenharmony_ci    } else if (param.format == Media::PixelFormat::RGB_565) {
341e0dac50fSopenharmony_ci        int32_t rgb888Size = param.stride * param.height * RGB888_PIXEL_BYTES / RGB565_PIXEL_BYTES;
342e0dac50fSopenharmony_ci        uint8_t *rgb888 = new uint8_t[rgb888Size];
343e0dac50fSopenharmony_ci        ret = RGB565ToRGB888(param.data, rgb888, rgb888Size / RGB888_PIXEL_BYTES);
344e0dac50fSopenharmony_ci        if (ret) {
345e0dac50fSopenharmony_ci            std::cout << "snapshot: convert rgb565 to rgb888 successfully." << std::endl;
346e0dac50fSopenharmony_ci            ret = WriteRgb888ToJpeg(file, param.width, param.height, rgb888);
347e0dac50fSopenharmony_ci        }
348e0dac50fSopenharmony_ci        delete[] rgb888;
349e0dac50fSopenharmony_ci    } else if (param.format == Media::PixelFormat::RGB_888) {
350e0dac50fSopenharmony_ci        ret = WriteRgb888ToJpeg(file, param.width, param.height, param.data);
351e0dac50fSopenharmony_ci    } else {
352e0dac50fSopenharmony_ci        std::cout << "snapshot: invalid pixel format." << std::endl;
353e0dac50fSopenharmony_ci    }
354e0dac50fSopenharmony_ci    if (fclose(file) != 0) {
355e0dac50fSopenharmony_ci        std::cout << "error: close file failed!" << std::endl;
356e0dac50fSopenharmony_ci        ret = false;
357e0dac50fSopenharmony_ci    }
358e0dac50fSopenharmony_ci    return ret;
359e0dac50fSopenharmony_ci}
360e0dac50fSopenharmony_ci
361e0dac50fSopenharmony_cibool SnapShotUtils::SaveSnapShot(const std::string& fileName, Media::PixelMap& pixelMap, std::string fileType)
362e0dac50fSopenharmony_ci{
363e0dac50fSopenharmony_ci    OHOS::Media::ImagePacker imagePacker;
364e0dac50fSopenharmony_ci    OHOS::Media::PackOption option;
365e0dac50fSopenharmony_ci    option.format = (fileType == "png") ? "image/png" : "image/jpeg";
366e0dac50fSopenharmony_ci    option.quality = (fileType == "png") ? PNG_PACKER_QUALITY : PACKER_QUALITY;
367e0dac50fSopenharmony_ci    option.numberHint = 1;
368e0dac50fSopenharmony_ci    std::set<std::string> formats;
369e0dac50fSopenharmony_ci    auto ret = imagePacker.GetSupportedFormats(formats);
370e0dac50fSopenharmony_ci    if (ret) {
371e0dac50fSopenharmony_ci        std::cout << "error: get supported formats error" << std::endl;
372e0dac50fSopenharmony_ci        return false;
373e0dac50fSopenharmony_ci    }
374e0dac50fSopenharmony_ci
375e0dac50fSopenharmony_ci    imagePacker.StartPacking(fileName, option);
376e0dac50fSopenharmony_ci    imagePacker.AddImage(pixelMap);
377e0dac50fSopenharmony_ci    int64_t packedSize = 0;
378e0dac50fSopenharmony_ci    uint32_t res = imagePacker.FinalizePacking(packedSize);
379e0dac50fSopenharmony_ci    if (res != PACKER_SUCCESS) {
380e0dac50fSopenharmony_ci        std::cout << "error:FinalizePacking error" << std::endl;
381e0dac50fSopenharmony_ci        return false;
382e0dac50fSopenharmony_ci    }
383e0dac50fSopenharmony_ci    return true;
384e0dac50fSopenharmony_ci}
385e0dac50fSopenharmony_ci
386e0dac50fSopenharmony_cibool SnapShotUtils::WriteToJpegWithPixelMap(const std::string& fileName, Media::PixelMap& pixelMap)
387e0dac50fSopenharmony_ci{
388e0dac50fSopenharmony_ci    if (pixelMap.GetAllocatorType() == Media::AllocatorType::DMA_ALLOC) {
389e0dac50fSopenharmony_ci        return SaveSnapShot(fileName, pixelMap);
390e0dac50fSopenharmony_ci    }
391e0dac50fSopenharmony_ci    WriteToJpegParam param;
392e0dac50fSopenharmony_ci    param.width = static_cast<uint32_t>(pixelMap.GetWidth());
393e0dac50fSopenharmony_ci    param.height = static_cast<uint32_t>(pixelMap.GetHeight());
394e0dac50fSopenharmony_ci    param.data = pixelMap.GetPixels();
395e0dac50fSopenharmony_ci    param.stride = static_cast<uint32_t>(pixelMap.GetRowBytes());
396e0dac50fSopenharmony_ci    param.format = pixelMap.GetPixelFormat();
397e0dac50fSopenharmony_ci    return SnapShotUtils::WriteToJpeg(fileName, param);
398e0dac50fSopenharmony_ci}
399e0dac50fSopenharmony_ci
400e0dac50fSopenharmony_cibool SnapShotUtils::WriteToJpegWithPixelMap(int fd, Media::PixelMap& pixelMap)
401e0dac50fSopenharmony_ci{
402e0dac50fSopenharmony_ci    WriteToJpegParam param;
403e0dac50fSopenharmony_ci    param.width = static_cast<uint32_t>(pixelMap.GetWidth());
404e0dac50fSopenharmony_ci    param.height = static_cast<uint32_t>(pixelMap.GetHeight());
405e0dac50fSopenharmony_ci    param.data = pixelMap.GetPixels();
406e0dac50fSopenharmony_ci    param.stride = static_cast<uint32_t>(pixelMap.GetRowBytes());
407e0dac50fSopenharmony_ci    param.format = pixelMap.GetPixelFormat();
408e0dac50fSopenharmony_ci    return SnapShotUtils::WriteToJpeg(fd, param);
409e0dac50fSopenharmony_ci}
410e0dac50fSopenharmony_ci
411e0dac50fSopenharmony_cibool SnapShotUtils::ProcessDisplayId(Rosen::DisplayId& displayId, bool isDisplayIdSet)
412e0dac50fSopenharmony_ci{
413e0dac50fSopenharmony_ci    if (!isDisplayIdSet) {
414e0dac50fSopenharmony_ci        displayId = DisplayManager::GetInstance().GetDefaultDisplayId();
415e0dac50fSopenharmony_ci    } else {
416e0dac50fSopenharmony_ci        bool validFlag = false;
417e0dac50fSopenharmony_ci        auto displayIds = DisplayManager::GetInstance().GetAllDisplayIds();
418e0dac50fSopenharmony_ci        for (auto id : displayIds) {
419e0dac50fSopenharmony_ci            if (displayId == id) {
420e0dac50fSopenharmony_ci                validFlag = true;
421e0dac50fSopenharmony_ci                break;
422e0dac50fSopenharmony_ci            }
423e0dac50fSopenharmony_ci        }
424e0dac50fSopenharmony_ci        if (!validFlag) {
425e0dac50fSopenharmony_ci            std::cout << "error: displayId " << static_cast<int64_t>(displayId) << " invalid!" << std::endl;
426e0dac50fSopenharmony_ci            std::cout << "tips: supported displayIds:" << std::endl;
427e0dac50fSopenharmony_ci            for (auto dispId : displayIds) {
428e0dac50fSopenharmony_ci                std::cout << "\t" << dispId << std::endl;
429e0dac50fSopenharmony_ci            }
430e0dac50fSopenharmony_ci            return false;
431e0dac50fSopenharmony_ci        }
432e0dac50fSopenharmony_ci    }
433e0dac50fSopenharmony_ci    return true;
434e0dac50fSopenharmony_ci}
435e0dac50fSopenharmony_ci
436e0dac50fSopenharmony_cibool SnapShotUtils::ProcessArgs(int argc, char* const argv[], CmdArguments& cmdArguments)
437e0dac50fSopenharmony_ci{
438e0dac50fSopenharmony_ci    int opt = 0;
439e0dac50fSopenharmony_ci    const struct option longOption[] = {
440e0dac50fSopenharmony_ci        { "id", required_argument, nullptr, 'i' },
441e0dac50fSopenharmony_ci        { "width", required_argument, nullptr, 'w' },
442e0dac50fSopenharmony_ci        { "height", required_argument, nullptr, 'h' },
443e0dac50fSopenharmony_ci        { "file", required_argument, nullptr, 'f' },
444e0dac50fSopenharmony_ci        { "type", required_argument, nullptr, 't' },
445e0dac50fSopenharmony_ci        { "help", required_argument, nullptr, 'm' },
446e0dac50fSopenharmony_ci        { nullptr, 0, nullptr, 0 }
447e0dac50fSopenharmony_ci    };
448e0dac50fSopenharmony_ci    while ((opt = getopt_long(argc, argv, "i:w:h:f:t:m", longOption, nullptr)) != -1) {
449e0dac50fSopenharmony_ci        switch (opt) {
450e0dac50fSopenharmony_ci            case 'i': // display id
451e0dac50fSopenharmony_ci                cmdArguments.displayId = static_cast<DisplayId>(atoll(optarg));
452e0dac50fSopenharmony_ci                cmdArguments.isDisplayIdSet = true;
453e0dac50fSopenharmony_ci                break;
454e0dac50fSopenharmony_ci            case 'w': // output width
455e0dac50fSopenharmony_ci                cmdArguments.width = atoi(optarg);
456e0dac50fSopenharmony_ci                cmdArguments.isWidthSet = true;
457e0dac50fSopenharmony_ci                break;
458e0dac50fSopenharmony_ci            case 'h': // output height
459e0dac50fSopenharmony_ci                cmdArguments.height = atoi(optarg);
460e0dac50fSopenharmony_ci                cmdArguments.isHeightSet = true;
461e0dac50fSopenharmony_ci                break;
462e0dac50fSopenharmony_ci            case 'f': // output file name
463e0dac50fSopenharmony_ci                cmdArguments.fileName = optarg;
464e0dac50fSopenharmony_ci                break;
465e0dac50fSopenharmony_ci            case 't': // output file type
466e0dac50fSopenharmony_ci                cmdArguments.fileType = optarg;
467e0dac50fSopenharmony_ci                break;
468e0dac50fSopenharmony_ci            case 'm': // help
469e0dac50fSopenharmony_ci            default:
470e0dac50fSopenharmony_ci                SnapShotUtils::PrintUsage(argv[0]);
471e0dac50fSopenharmony_ci                return false;
472e0dac50fSopenharmony_ci        }
473e0dac50fSopenharmony_ci    }
474e0dac50fSopenharmony_ci
475e0dac50fSopenharmony_ci    if (!ProcessDisplayId(cmdArguments.displayId, cmdArguments.isDisplayIdSet)) {
476e0dac50fSopenharmony_ci        return false;
477e0dac50fSopenharmony_ci    }
478e0dac50fSopenharmony_ci
479e0dac50fSopenharmony_ci    if (cmdArguments.fileName == "") {
480e0dac50fSopenharmony_ci        cmdArguments.fileName = GenerateFileName(cmdArguments.fileType);
481e0dac50fSopenharmony_ci        std::cout << "process: set filename to " << cmdArguments.fileName.c_str() << std::endl;
482e0dac50fSopenharmony_ci    }
483e0dac50fSopenharmony_ci
484e0dac50fSopenharmony_ci    // check fileName
485e0dac50fSopenharmony_ci    if (!SnapShotUtils::CheckFileNameValid(cmdArguments.fileName, cmdArguments.fileType)) {
486e0dac50fSopenharmony_ci        std::cout << "error: filename " << cmdArguments.fileName.c_str() << " invalid!" << std::endl;
487e0dac50fSopenharmony_ci        return false;
488e0dac50fSopenharmony_ci    }
489e0dac50fSopenharmony_ci    return true;
490e0dac50fSopenharmony_ci}
491e0dac50fSopenharmony_ci}
492