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