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 30namespace OHOS { 31Image::Image() : imageInfo_(nullptr), path_(nullptr), srcType_(IMG_SRC_UNKNOWN), mallocFlag_(false) {} 32 33Image::~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 48void 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 58OHOS::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 94bool 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 136bool 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 190bool 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 209bool 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 return false; 223 } 224 225 srcType_ = IMG_SRC_VARIABLE; 226 } 227 228 return true; 229} 230 231bool Image::PreParse(const char *src) 232{ 233 if (src == nullptr) { 234 return false; 235 } 236 const char* ptr = strrchr(src, '.'); 237 if (ptr == nullptr) { 238 srcType_ = IMG_SRC_UNKNOWN; 239 return false; 240 } 241 if (path_ != nullptr) { 242 UIFree(reinterpret_cast<void*>(path_)); 243 } 244 size_t strLen = strlen(src) + 1; 245 char* path = static_cast<char*>(UIMalloc(static_cast<uint32_t>(strLen))); 246 if (strcpy_s(path, strLen, src) != EOK) { 247 UIFree(reinterpret_cast<void*>(path)); 248 return false; 249 } 250 path_ = path; 251 bool isSucess = true; 252#if ENABLE_JPEG || ENABLE_PNG 253 ImageType imageType = CheckImgType(src); 254 if (imageType == IMG_PNG) { 255#if ENABLE_PNG 256 isSucess = SetPNGSrc(src); 257#endif 258 } else if (imageType == IMG_JPEG) { 259#if ENABLE_JPEG 260 isSucess = SetJPEGSrc(src); 261#endif 262 } else if (imageType == IMG_GIF) { 263 isSucess = true; 264 } else { 265 srcType_ = IMG_SRC_UNKNOWN; 266 return false; 267 } 268#endif 269 return isSucess; 270} 271 272void Image::DrawImage(BufferInfo& gfxDstBuffer, 273 const Rect& coords, 274 const Rect& mask, 275 const Style& style, 276 uint8_t opaScale) const 277{ 278 if (srcType_ == IMG_SRC_VARIABLE) { 279 DrawImage::DrawCommon(gfxDstBuffer, coords, mask, imageInfo_, style, opaScale); 280 } else if (srcType_ == IMG_SRC_FILE) { 281 DrawImage::DrawCommon(gfxDstBuffer, coords, mask, path_, style, opaScale); 282 } else { 283 GRAPHIC_LOGE("Image::DrawImage:: failed with error srctype!\n"); 284 } 285} 286 287#if ENABLE_PNG 288static inline void FreePngBytep(png_bytep** rowPointer, uint16_t size) 289{ 290 png_bytep* tmpRowPointer = *rowPointer; 291 for (uint16_t i = 0; i < size; i++) { 292 UIFree(tmpRowPointer[i]); 293 tmpRowPointer[i] = nullptr; 294 } 295 UIFree(*rowPointer); 296 *rowPointer = nullptr; 297} 298 299static inline png_bytep* MallocPngBytep(uint16_t height, uint32_t rowBytes) 300{ 301 png_bytep* rowPointer = static_cast<png_bytep*>(UIMalloc(sizeof(png_bytep) * height)); 302 if (rowPointer == nullptr) { 303 return nullptr; 304 } 305 for (uint16_t y = 0; y < height; y++) { 306 rowPointer[y] = static_cast<png_byte*>(UIMalloc(rowBytes)); 307 if (rowPointer[y] == nullptr) { 308 FreePngBytep(&rowPointer, y); 309 return nullptr; 310 } 311 } 312 return rowPointer; 313} 314 315bool Image::SetPNGSrc(const char* src) 316{ 317 srcType_ = IMG_SRC_UNKNOWN; 318 png_bytep* rowPointer = nullptr; 319 png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); 320 if (png == nullptr) { 321 return false; 322 } 323 png_infop info = png_create_info_struct(png); 324 if (info == nullptr) { 325 png_destroy_read_struct(&png, &info, nullptr); 326 return false; 327 } 328 FILE* infile = fopen(src, "rb"); 329 if (infile == nullptr) { 330 GRAPHIC_LOGE("can't open %s\n", src); 331 png_destroy_read_struct(&png, &info, nullptr); 332 return false; 333 } 334 png_init_io(png, infile); 335 png_read_info(png, info); 336 337 uint8_t pixelByteSize = DrawUtils::GetPxSizeByColorMode(ARGB8888) >> 3; // 3: Shift right 3 bits 338 uint16_t width = png_get_image_width(png, info); 339 uint16_t height = png_get_image_height(png, info); 340 uint8_t colorType = png_get_color_type(png, info); 341 uint8_t bitDepth = png_get_bit_depth(png, info); 342 uint32_t dataSize = height * width * pixelByteSize; 343 344 if ((colorType == PNG_COLOR_TYPE_GRAY) && (bitDepth < 8)) { // 8: Expand grayscale images to the full 8 bits 345 png_set_expand_gray_1_2_4_to_8(png); 346 } 347 if ((colorType == PNG_COLOR_TYPE_GRAY) || (colorType == PNG_COLOR_TYPE_GRAY_ALPHA)) { 348 png_set_gray_to_rgb(png); 349 } 350 if (colorType == PNG_COLOR_TYPE_PALETTE) { 351 png_set_palette_to_rgb(png); 352 } 353 if (bitDepth == 16) { // 16: Chop 16-bit depth images to 8-bit depth 354 png_set_strip_16(png); 355 } 356 if (png_get_valid(png, info, PNG_INFO_tRNS)) { 357 png_set_tRNS_to_alpha(png); 358 } 359 if (!(colorType & PNG_COLOR_MASK_ALPHA)) { 360 png_set_add_alpha(png, 0xFF, PNG_FILLER_AFTER); 361 } 362 png_set_interlace_handling(png); 363 png_read_update_info(png, info); 364 365 rowPointer = MallocPngBytep(height, png_get_rowbytes(png, info)); 366 if (rowPointer == nullptr) { 367 fclose(infile); 368 png_destroy_read_struct(&png, &info, nullptr); 369 return false; 370 } 371 372 png_read_image(png, rowPointer); 373 fclose(infile); 374 png_destroy_read_struct(&png, &info, nullptr); 375 376 ImageInfo* imgInfo = static_cast<ImageInfo*>(UIMalloc(sizeof(ImageInfo))); 377 if (imgInfo == nullptr) { 378 FreePngBytep(&rowPointer, height); 379 return false; 380 } 381 uint8_t* srcData = static_cast<uint8_t*>(UIMalloc(dataSize)); 382 if (srcData == nullptr) { 383 FreePngBytep(&rowPointer, height); 384 UIFree(imgInfo); 385 return false; 386 } 387 uint32_t n = 0; 388 for (uint16_t y = 0; y < height; y++) { 389 png_bytep row = rowPointer[y]; 390 for (uint16_t x = 0; x < width * pixelByteSize; x += pixelByteSize) { 391 srcData[n++] = row[x + 2]; // 2: B channel 392 srcData[n++] = row[x + 1]; // 1: G channel 393 srcData[n++] = row[x + 0]; // 0: R channel 394 srcData[n++] = row[x + 3]; // 3: Alpha channel 395 } 396 } 397 FreePngBytep(&rowPointer, height); 398 399 imgInfo->header.width = width; 400 imgInfo->header.height = height; 401 imgInfo->header.colorMode = ARGB8888; 402 imgInfo->dataSize = dataSize; 403 imgInfo->data = srcData; 404 405 ReInitImageInfo(imgInfo, true); 406 srcType_ = IMG_SRC_VARIABLE; 407 return true; 408} 409#endif 410 411#if ENABLE_JPEG 412bool Image::SetJPEGSrc(const char* src) 413{ 414 struct jpeg_decompress_struct cinfo; 415 struct jpeg_error_mgr jerr; 416 srcType_ = IMG_SRC_UNKNOWN; 417 418 FILE* infile = fopen(src, "rb"); 419 if (infile == nullptr) { 420 GRAPHIC_LOGE("can't open %s\n", src); 421 return false; 422 } 423 cinfo.err = jpeg_std_error(&jerr); 424 jpeg_create_decompress(&cinfo); 425 jpeg_stdio_src(&cinfo, infile); 426 jpeg_read_header(&cinfo, TRUE); 427 jpeg_start_decompress(&cinfo); 428 429 uint8_t pixelByteSize = DrawUtils::GetPxSizeByColorMode(ARGB8888) >> 3; // 3: Shift right 3 bits 430 uint16_t width = cinfo.output_width; 431 uint16_t height = cinfo.output_height; 432 uint32_t dataSize = width * height * pixelByteSize; 433 uint16_t rowStride = cinfo.output_width * pixelByteSize; 434 JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)(reinterpret_cast<j_common_ptr>(&cinfo), JPOOL_IMAGE, rowStride, 435 1); // 1: one-row-high array 436 ImageInfo* imgInfo = static_cast<ImageInfo*>(UIMalloc(sizeof(ImageInfo))); 437 if (imgInfo == nullptr) { 438 jpeg_finish_decompress(&cinfo); 439 jpeg_destroy_decompress(&cinfo); 440 fclose(infile); 441 return false; 442 } 443 uint8_t* srcData = static_cast<uint8_t*>(UIMalloc(dataSize)); 444 if (srcData == nullptr) { 445 jpeg_finish_decompress(&cinfo); 446 jpeg_destroy_decompress(&cinfo); 447 fclose(infile); 448 UIFree(imgInfo); 449 return false; 450 } 451 uint32_t n = 0; 452 while (cinfo.output_scanline < cinfo.output_height) { 453 jpeg_read_scanlines(&cinfo, buffer, 1); // 1: read one line each time 454 for (uint16_t x = 0; x < width * 3; x += 3) { // 3: color components per pixel 455 srcData[n++] = buffer[0][x + 2]; // 2: B channel 456 srcData[n++] = buffer[0][x + 1]; // 1: G channel 457 srcData[n++] = buffer[0][x + 0]; // 0: R channel 458 srcData[n++] = 255; // 255: set alpha channel 459 } 460 } 461 jpeg_finish_decompress(&cinfo); 462 jpeg_destroy_decompress(&cinfo); 463 fclose(infile); 464 465 imgInfo->header.width = width; 466 imgInfo->header.height = height; 467 imgInfo->header.colorMode = ARGB8888; 468 imgInfo->dataSize = dataSize; 469 imgInfo->data = srcData; 470 471 ReInitImageInfo(imgInfo, true); 472 srcType_ = IMG_SRC_VARIABLE; 473 return true; 474} 475#endif 476 477void Image::ReInitImageInfo(ImageInfo* imgInfo, bool mallocFlag) 478{ 479 if (mallocFlag_) { 480 if (imageInfo_->data != nullptr) { 481 UIFree(reinterpret_cast<void*>(const_cast<uint8_t*>(imageInfo_->data))); 482 } 483 } 484 UIFree(reinterpret_cast<void*>(const_cast<ImageInfo*>(imageInfo_))); 485 486 imageInfo_ = imgInfo; 487 mallocFlag_ = mallocFlag; 488} 489} // namespace OHOS 490