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