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