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