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