• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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