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 "common/image.h"
17 #include "common/image_decode_ability.h"
18 #include "draw/draw_image.h"
19 #include "gfx_utils/file.h"
20 #include "gfx_utils/graphic_log.h"
21 #include "imgdecode/cache_manager.h"
22 #if ENABLE_JPEG_AND_PNG
23 #include "jpeglib.h"
24 #include "png.h"
25 #endif
26 #include "securec.h"
27
28 namespace OHOS {
Image()29 Image::Image() : imageInfo_(nullptr), path_(nullptr), srcType_(IMG_SRC_UNKNOWN), mallocFlag_(false) {}
30
~Image()31 Image::~Image()
32 {
33 if (srcType_ == IMG_SRC_FILE) {
34 CacheManager::GetInstance().Close(path_);
35 }
36
37 ReInitImageInfo(nullptr, false);
38
39 if (path_ != nullptr) {
40 UIFree(reinterpret_cast<void*>(const_cast<char*>(path_)));
41 path_ = nullptr;
42 }
43 srcType_ = IMG_SRC_UNKNOWN;
44 }
45
GetHeader(ImageHeader & header) const46 void Image::GetHeader(ImageHeader& header) const
47 {
48 if ((srcType_ == IMG_SRC_VARIABLE) && (imageInfo_ != nullptr)) {
49 header = imageInfo_->header;
50 } else if ((srcType_ == IMG_SRC_FILE) && (path_ != nullptr)) {
51 CacheManager::GetInstance().GetImageHeader(path_, header);
52 }
53 }
54
55 #if ENABLE_JPEG_AND_PNG
CheckImgType(const char * src)56 Image::ImageType Image::CheckImgType(const char* src)
57 {
58 char buf[IMG_BYTES_TO_CHECK] = {0};
59 #ifdef _WIN32
60 int32_t fd = open(src, O_RDONLY | O_BINARY);
61 #else
62 int32_t fd = open(src, O_RDONLY);
63 #endif
64 if (fd < 0) {
65 GRAPHIC_LOGE("can't open %s\n", src);
66 return IMG_UNKNOWN;
67 }
68 if (read(fd, buf, IMG_BYTES_TO_CHECK) != IMG_BYTES_TO_CHECK) {
69 close(fd);
70 return IMG_UNKNOWN;
71 }
72 close(fd);
73 if (!png_sig_cmp(reinterpret_cast<png_const_bytep>(buf), 0, IMG_BYTES_TO_CHECK)) {
74 return IMG_PNG;
75 // 0xFF 0xD8: JPEG file's header
76 } else if ((static_cast<uint8_t>(buf[0]) == 0xFF) && (static_cast<uint8_t>(buf[1]) == 0xD8)) {
77 return IMG_JPEG;
78 }
79 return IMG_UNKNOWN;
80 }
81 #endif
82
SetStandardSrc(const char * src)83 bool Image::SetStandardSrc(const char* src)
84 {
85 if (src == nullptr) {
86 return false;
87 }
88 srcType_ = IMG_SRC_UNKNOWN;
89
90 const char* ptr = strrchr(src, '.');
91 if (ptr == nullptr) {
92 return false;
93 }
94
95 #if ENABLE_JPEG_AND_PNG
96 ImageType imageType = CheckImgType(src);
97 if (imageType == IMG_PNG) {
98 return SetPNGSrc(src);
99 } else if (imageType == IMG_JPEG) {
100 return SetJPEGSrc(src);
101 }
102 #endif
103
104 size_t strLen = strlen(src) + 1;
105 char* imagePath = static_cast<char*>(UIMalloc(static_cast<uint32_t>(strLen)));
106 if (imagePath == nullptr) {
107 return false;
108 }
109
110 if (strcpy_s(imagePath, strLen, src) != EOK) {
111 UIFree(reinterpret_cast<void*>(imagePath));
112 imagePath = nullptr;
113 return false;
114 }
115 path_ = imagePath;
116 srcType_ = IMG_SRC_FILE;
117 return true;
118 }
119
SetLiteSrc(const char * src)120 bool Image::SetLiteSrc(const char* src)
121 {
122 if (src == nullptr) {
123 return false;
124 }
125 srcType_ = IMG_SRC_UNKNOWN;
126
127 const char* ptr = strrchr(src, '.');
128 if (ptr == nullptr) {
129 return false;
130 }
131
132 size_t strLen = strlen(src) + 1;
133 char* imagePath = static_cast<char*>(UIMalloc(static_cast<uint32_t>(strLen)));
134 if (imagePath == nullptr) {
135 return false;
136 }
137 if (IsImgValid(ptr)) {
138 const char* suffixName = "bin";
139 if (memcpy_s(imagePath, strLen, src, strLen) != EOK) {
140 UIFree(reinterpret_cast<void*>(imagePath));
141 imagePath = nullptr;
142 return false;
143 }
144 (ptr - src + imagePath)[1] = '\0'; // remove suffix
145 if (strcat_s(imagePath, strLen, suffixName) != EOK) {
146 UIFree(reinterpret_cast<void*>(imagePath));
147 imagePath = nullptr;
148 return false;
149 }
150 } else {
151 if (memcpy_s(imagePath, strLen, src, strLen) != EOK) {
152 UIFree(reinterpret_cast<void*>(imagePath));
153 imagePath = nullptr;
154 return false;
155 }
156 }
157 path_ = imagePath;
158 srcType_ = IMG_SRC_FILE;
159 return true;
160 }
161
SetSrc(const char * src)162 bool Image::SetSrc(const char* src)
163 {
164 if (path_ != nullptr) {
165 UIFree(reinterpret_cast<void*>(const_cast<char*>(path_)));
166 path_ = nullptr;
167 }
168
169 if (src != nullptr) {
170 uint32_t imageType = ImageDecodeAbility::GetInstance().GetImageDecodeAbility();
171 if (((imageType & IMG_SUPPORT_JPEG) == IMG_SUPPORT_JPEG) ||
172 ((imageType & IMG_SUPPORT_PNG) == IMG_SUPPORT_PNG)) {
173 return SetStandardSrc(src);
174 }
175 return SetLiteSrc(src);
176 }
177 srcType_ = IMG_SRC_UNKNOWN;
178 return true;
179 }
180
SetSrc(const ImageInfo * src)181 bool Image::SetSrc(const ImageInfo* src)
182 {
183 ReInitImageInfo(nullptr, false);
184 srcType_ = IMG_SRC_UNKNOWN;
185 imageInfo_ = nullptr;
186
187 if (src != nullptr) {
188 imageInfo_ = static_cast<ImageInfo*>(UIMalloc(static_cast<uint32_t>(sizeof(ImageInfo))));
189 if (imageInfo_ == nullptr) {
190 return false;
191 }
192
193 if (memcpy_s(const_cast<ImageInfo*>(imageInfo_), sizeof(ImageInfo), src, sizeof(ImageInfo)) != EOK) {
194 return false;
195 }
196
197 srcType_ = IMG_SRC_VARIABLE;
198 }
199
200 return true;
201 }
202
DrawImage(BufferInfo & gfxDstBuffer,const Rect & coords,const Rect & mask,const Style & style,uint8_t opaScale) const203 void Image::DrawImage(BufferInfo& gfxDstBuffer,
204 const Rect& coords,
205 const Rect& mask,
206 const Style& style,
207 uint8_t opaScale) const
208 {
209 if (srcType_ == IMG_SRC_VARIABLE) {
210 DrawImage::DrawCommon(gfxDstBuffer, coords, mask, imageInfo_, style, opaScale);
211 } else if (srcType_ == IMG_SRC_FILE) {
212 DrawImage::DrawCommon(gfxDstBuffer, coords, mask, path_, style, opaScale);
213 } else {
214 GRAPHIC_LOGE("Image::DrawImage:: failed with error srctype!\n");
215 }
216 }
217
218 #if ENABLE_JPEG_AND_PNG
219
FreePngBytep(png_bytep ** rowPointer,uint16_t size)220 static inline void FreePngBytep(png_bytep** rowPointer, uint16_t size)
221 {
222 png_bytep* tmpRowPointer = *rowPointer;
223 for (uint16_t i = 0; i < size; i++) {
224 UIFree(tmpRowPointer[i]);
225 tmpRowPointer[i] = nullptr;
226 }
227 UIFree(*rowPointer);
228 *rowPointer = nullptr;
229 }
230
MallocPngBytep(uint16_t height,uint32_t rowBytes)231 static inline png_bytep* MallocPngBytep(uint16_t height, uint32_t rowBytes)
232 {
233 png_bytep* rowPointer = static_cast<png_bytep*>(UIMalloc(sizeof(png_bytep) * height));
234 if (rowPointer == nullptr) {
235 return nullptr;
236 }
237 for (uint16_t y = 0; y < height; y++) {
238 rowPointer[y] = static_cast<png_byte*>(UIMalloc(rowBytes));
239 if (rowPointer[y] == nullptr) {
240 FreePngBytep(&rowPointer, y);
241 return nullptr;
242 }
243 }
244 return rowPointer;
245 }
246
SetPNGSrc(const char * src)247 bool Image::SetPNGSrc(const char* src)
248 {
249 srcType_ = IMG_SRC_UNKNOWN;
250 FILE* infile = nullptr;
251 png_bytep* rowPointer = nullptr;
252 png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
253 if (png == nullptr) {
254 return false;
255 }
256 png_infop info = png_create_info_struct(png);
257 if (info == nullptr) {
258 png_destroy_read_struct(&png, &info, nullptr);
259 return false;
260 }
261 if ((infile = fopen(src, "rb")) == nullptr) {
262 GRAPHIC_LOGE("can't open %s\n", src);
263 png_destroy_read_struct(&png, &info, nullptr);
264 return false;
265 }
266 png_init_io(png, infile);
267 png_read_info(png, info);
268
269 uint8_t pixelByteSize = DrawUtils::GetPxSizeByColorMode(ARGB8888) >> 3; // 3: Shift right 3 bits
270 uint16_t width = png_get_image_width(png, info);
271 uint16_t height = png_get_image_height(png, info);
272 uint8_t colorType = png_get_color_type(png, info);
273 uint8_t bitDepth = png_get_bit_depth(png, info);
274 uint32_t dataSize = height * width * pixelByteSize;
275
276 if ((colorType == PNG_COLOR_TYPE_GRAY) && (bitDepth < 8)) { // 8: Expand grayscale images to the full 8 bits
277 png_set_expand_gray_1_2_4_to_8(png);
278 }
279 if ((colorType == PNG_COLOR_TYPE_GRAY) || (colorType == PNG_COLOR_TYPE_GRAY_ALPHA)) {
280 png_set_gray_to_rgb(png);
281 }
282 if (colorType == PNG_COLOR_TYPE_PALETTE) {
283 png_set_palette_to_rgb(png);
284 }
285 if (bitDepth == 16) { // 16: Chop 16-bit depth images to 8-bit depth
286 png_set_strip_16(png);
287 }
288 if (png_get_valid(png, info, PNG_INFO_tRNS)) {
289 png_set_tRNS_to_alpha(png);
290 }
291 if (!(colorType & PNG_COLOR_MASK_ALPHA)) {
292 png_set_add_alpha(png, 0xFF, PNG_FILLER_AFTER);
293 }
294 png_set_interlace_handling(png);
295 png_read_update_info(png, info);
296
297 rowPointer = MallocPngBytep(height, png_get_rowbytes(png, info));
298 if (rowPointer == nullptr) {
299 fclose(infile);
300 png_destroy_read_struct(&png, &info, nullptr);
301 return false;
302 }
303
304 png_read_image(png, rowPointer);
305 fclose(infile);
306 png_destroy_read_struct(&png, &info, nullptr);
307
308 ImageInfo* imgInfo = static_cast<ImageInfo*>(UIMalloc(sizeof(ImageInfo)));
309 if (imgInfo == nullptr) {
310 FreePngBytep(&rowPointer, height);
311 return false;
312 }
313 uint8_t* srcData = static_cast<uint8_t*>(UIMalloc(dataSize));
314 if (srcData == nullptr) {
315 FreePngBytep(&rowPointer, height);
316 UIFree(imgInfo);
317 return false;
318 }
319 uint32_t n = 0;
320 for (uint16_t y = 0; y < height; y++) {
321 png_bytep row = rowPointer[y];
322 for (uint16_t x = 0; x < width * pixelByteSize; x += pixelByteSize) {
323 srcData[n++] = row[x + 2]; // 2: B channel
324 srcData[n++] = row[x + 1]; // 1: G channel
325 srcData[n++] = row[x + 0]; // 0: R channel
326 srcData[n++] = row[x + 3]; // 3: Alpha channel
327 }
328 }
329 FreePngBytep(&rowPointer, height);
330
331 imgInfo->header.width = width;
332 imgInfo->header.height = height;
333 imgInfo->header.colorMode = ARGB8888;
334 imgInfo->dataSize = dataSize;
335 imgInfo->data = srcData;
336
337 ReInitImageInfo(imgInfo, true);
338 srcType_ = IMG_SRC_VARIABLE;
339 return true;
340 }
341
SetJPEGSrc(const char * src)342 bool Image::SetJPEGSrc(const char* src)
343 {
344 struct jpeg_decompress_struct cinfo;
345 struct jpeg_error_mgr jerr;
346 FILE* infile = nullptr;
347 srcType_ = IMG_SRC_UNKNOWN;
348
349 if ((infile = fopen(src, "rb")) == nullptr) {
350 GRAPHIC_LOGE("can't open %s\n", src);
351 return false;
352 }
353 cinfo.err = jpeg_std_error(&jerr);
354 jpeg_create_decompress(&cinfo);
355 jpeg_stdio_src(&cinfo, infile);
356 jpeg_read_header(&cinfo, TRUE);
357 jpeg_start_decompress(&cinfo);
358
359 uint8_t pixelByteSize = DrawUtils::GetPxSizeByColorMode(ARGB8888) >> 3; // 3: Shift right 3 bits
360 uint16_t width = cinfo.output_width;
361 uint16_t height = cinfo.output_height;
362 uint32_t dataSize = width * height * pixelByteSize;
363 uint16_t rowStride = cinfo.output_width * pixelByteSize;
364 JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)(reinterpret_cast<j_common_ptr>(&cinfo), JPOOL_IMAGE, rowStride,
365 1); // 1: one-row-high array
366 ImageInfo* imgInfo = static_cast<ImageInfo*>(UIMalloc(sizeof(ImageInfo)));
367 if (imgInfo == nullptr) {
368 jpeg_finish_decompress(&cinfo);
369 jpeg_destroy_decompress(&cinfo);
370 fclose(infile);
371 return false;
372 }
373 uint8_t* srcData = static_cast<uint8_t*>(UIMalloc(dataSize));
374 if (srcData == nullptr) {
375 jpeg_finish_decompress(&cinfo);
376 jpeg_destroy_decompress(&cinfo);
377 fclose(infile);
378 UIFree(imgInfo);
379 return false;
380 }
381 uint32_t n = 0;
382 while (cinfo.output_scanline < cinfo.output_height) {
383 jpeg_read_scanlines(&cinfo, buffer, 1); // 1: read one line each time
384 for (uint16_t x = 0; x < width * 3; x += 3) { // 3: color components per pixel
385 srcData[n++] = buffer[0][x + 2]; // 2: B channel
386 srcData[n++] = buffer[0][x + 1]; // 1: G channel
387 srcData[n++] = buffer[0][x + 0]; // 0: R channel
388 srcData[n++] = 255; // 255: set alpha channel
389 }
390 }
391 jpeg_finish_decompress(&cinfo);
392 jpeg_destroy_decompress(&cinfo);
393 fclose(infile);
394
395 imgInfo->header.width = width;
396 imgInfo->header.height = height;
397 imgInfo->header.colorMode = ARGB8888;
398 imgInfo->dataSize = dataSize;
399 imgInfo->data = srcData;
400
401 ReInitImageInfo(imgInfo, true);
402 srcType_ = IMG_SRC_VARIABLE;
403 return true;
404 }
405 #endif
406
ReInitImageInfo(ImageInfo * imgInfo,bool mallocFlag)407 void Image::ReInitImageInfo(ImageInfo* imgInfo, bool mallocFlag)
408 {
409 if (mallocFlag_) {
410 if (imageInfo_->data != nullptr) {
411 UIFree(reinterpret_cast<void*>(const_cast<uint8_t*>(imageInfo_->data)));
412 }
413 }
414 UIFree(reinterpret_cast<void*>(const_cast<ImageInfo*>(imageInfo_)));
415
416 imageInfo_ = imgInfo;
417 mallocFlag_ = mallocFlag;
418 }
419 } // namespace OHOS