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
27 namespace OHOS {
28 class UIScreenshotListener : public IWindowsManager::ScreenshotListener {
29 public:
UIScreenshotListener()30 UIScreenshotListener() : filePath_(nullptr) {}
31
~UIScreenshotListener()32 virtual ~UIScreenshotListener()
33 {
34 if (filePath_ != nullptr) {
35 UIFree(reinterpret_cast<void*>(filePath_));
36 filePath_ = nullptr;
37 }
38 }
39
OnScreenshotEnd(uint8_t * virAddr,uint32_t width,uint32_t height,ImagePixelFormat format,uint32_t stride)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
SetFilePath(char * path)89 void SetFilePath(char* path)
90 {
91 if (filePath_ != nullptr) {
92 UIFree(reinterpret_cast<void*>(filePath_));
93 }
94 filePath_ = path;
95 }
96
97 private:
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
WriteBlockToFile(int32_t fd,uint32_t * buffer,uint8_t * & startAddr,uint32_t row,uint32_t width,ImagePixelFormat format,uint32_t stride) const102 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
~UIScreenshot()130 UIScreenshot::~UIScreenshot()
131 {
132 if (screenshotListener_ != nullptr) {
133 delete screenshotListener_;
134 screenshotListener_ = nullptr;
135 }
136 }
137
GetInstance()138 UIScreenshot* UIScreenshot::GetInstance()
139 {
140 static UIScreenshot instance;
141 return &instance;
142 }
143
ScreenshotToFile(const char * path)144 bool 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