1/* 2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "dfx/ui_screenshot.h" 17#if ENABLE_DEBUG 18#include "iwindows_manager.h" 19#include "common/screen.h" 20#include "draw/draw_utils.h" 21#include "gfx_utils/color.h" 22#include "gfx_utils/file.h" 23#include "gfx_utils/graphic_log.h" 24#include "gfx_utils/image_info.h" 25#include "securec.h" 26 27namespace OHOS { 28class UIScreenshotListener : public IWindowsManager::ScreenshotListener { 29public: 30 UIScreenshotListener() : filePath_(nullptr) {} 31 32 virtual ~UIScreenshotListener() 33 { 34 if (filePath_ != nullptr) { 35 UIFree(reinterpret_cast<void*>(filePath_)); 36 filePath_ = nullptr; 37 } 38 } 39 40 void OnScreenshotEnd(uint8_t* virAddr, uint32_t width, uint32_t height, 41 ImagePixelFormat format, uint32_t stride) override 42 { 43 if ((virAddr == nullptr) || ((format != IMAGE_PIXEL_FORMAT_ARGB1555) && 44 (format != IMAGE_PIXEL_FORMAT_ARGB8888)) || (width == 0) || (height == 0)) { 45 return; 46 } 47 48 ImageHeader header = {0}; 49 header.colorMode = ARGB8888; 50 header.width = width; 51 header.height = height; 52 53 unlink(filePath_); 54 int32_t fd = open(filePath_, O_RDWR | O_CREAT, DEFAULT_FILE_PERMISSION); 55 UIFree(reinterpret_cast<void*>(filePath_)); 56 filePath_ = nullptr; 57 if (fd < 0) { 58 GRAPHIC_LOGE("UIScreenshotListener::OnScreenshotEnd open file failed Err!\n"); 59 return; 60 } 61 62 if (write(fd, &header, sizeof(ImageHeader)) != sizeof(ImageHeader)) { 63 GRAPHIC_LOGE("UIScreenshotListener::OnScreenshotEnd write image header failed Err!\n"); 64 close(fd); 65 return; 66 } 67 68 uint32_t row = MAX_MALLOC_SIZE / width; 69 row = (row == 0) ? 1 : row; 70 uint32_t size = row * width * sizeof(uint32_t); 71 uint32_t* argb8888Addr = static_cast<uint32_t*>(UIMalloc(size)); 72 if (argb8888Addr == nullptr) { 73 GRAPHIC_LOGE("UIScreenshotListener::OnScreenshotEnd memory allocation failed Err!"); 74 close(fd); 75 return; 76 } 77 78 while (height >= row) { 79 WriteBlockToFile(fd, argb8888Addr, virAddr, row, width, format, stride); 80 height -= row; 81 } 82 if (height != 0) { 83 WriteBlockToFile(fd, argb8888Addr, virAddr, height, width, format, stride); 84 } 85 UIFree(reinterpret_cast<void*>(argb8888Addr)); 86 close(fd); 87 } 88 89 void SetFilePath(char* path) 90 { 91 if (filePath_ != nullptr) { 92 UIFree(reinterpret_cast<void*>(filePath_)); 93 } 94 filePath_ = path; 95 } 96 97private: 98 static constexpr uint8_t DEFAULT_COLOR_SIZE = 4; 99 static constexpr uint16_t MAX_MALLOC_SIZE = 2048; // unit: 4 bytes 100 char* filePath_; 101 102 bool WriteBlockToFile(int32_t fd, uint32_t* buffer, uint8_t*& startAddr, uint32_t row, 103 uint32_t width, ImagePixelFormat format, uint32_t stride) const 104 { 105 uint32_t* argb8888Addr = buffer; 106 for (uint32_t r = 0; r < row; ++r) { 107 if (format == IMAGE_PIXEL_FORMAT_ARGB1555) { 108 uint16_t* temp = reinterpret_cast<uint16_t*>(startAddr); 109 for (uint32_t i = 0; i < width; ++i) { 110 buffer[i] = PixelFormatUtils::ARGB1555ToARGB8888(*temp++); 111 } 112 } else if (format == IMAGE_PIXEL_FORMAT_ARGB8888) { 113 if (memcpy_s(buffer, width * DEFAULT_COLOR_SIZE, startAddr, width * DEFAULT_COLOR_SIZE) != EOK) { 114 GRAPHIC_LOGE("memcpy_s error!"); 115 } 116 } 117 startAddr += stride; 118 buffer += width; 119 } 120 121 uint32_t blockSize = row * width * sizeof(uint32_t); 122 if (static_cast<uint32_t>(write(fd, argb8888Addr, blockSize)) != blockSize) { 123 GRAPHIC_LOGE("UIScreenshotListener::WriteBlockToFile wrong amount of written data Err!"); 124 return false; 125 } 126 return true; 127 } 128}; 129 130UIScreenshot::~UIScreenshot() 131{ 132 if (screenshotListener_ != nullptr) { 133 delete screenshotListener_; 134 screenshotListener_ = nullptr; 135 } 136} 137 138UIScreenshot* UIScreenshot::GetInstance() 139{ 140 static UIScreenshot instance; 141 return &instance; 142} 143 144bool UIScreenshot::ScreenshotToFile(const char* path) 145{ 146 IWindowsManager* manager = IWindowsManager::GetInstance(); 147 if (screenshotListener_ == nullptr) { 148 screenshotListener_ = new UIScreenshotListener(); 149 if (screenshotListener_ == nullptr) { 150 GRAPHIC_LOGE("UIScreenshot::ScreenshotToFile register screenshot listener failed Err!\n"); 151 return false; 152 } 153 manager->SetScreenshotListener(screenshotListener_); 154 } 155 156 const char* srcPath = (path == nullptr) ? DEFAULT_SCREENSHOT_PATH : path; 157 uint32_t pathLength = strlen(srcPath); 158 char* destPath = static_cast<char*>(UIMalloc(pathLength + 1)); 159 if (destPath == nullptr) { 160 return false; 161 } 162 163 if (memcpy_s(destPath, pathLength + 1, srcPath, pathLength) != EOK) { 164 UIFree(reinterpret_cast<void*>(destPath)); 165 return false; 166 } 167 destPath[pathLength] = '\0'; 168 screenshotListener_->SetFilePath(destPath); 169 manager->Screenshot(); 170 return true; 171} 172} // namespace OHOS 173#endif // ENABLE_DEBUG 174