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