1 /*
2 * Copyright (C) 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 "png_decoder.h"
17 #include "media_errors.h"
18 #include "pngpriv.h"
19 #include "pngstruct.h"
20 #ifndef _WIN32
21 #include "securec.h"
22 #else
23 #include "memory.h"
24 #endif
25
26 namespace OHOS {
27 namespace ImagePlugin {
28 using namespace OHOS::HiviewDFX;
29 using namespace MultimediaPlugin;
30 using namespace Media;
31 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "PngDecoder" };
32 static constexpr uint32_t PNG_IMAGE_NUM = 1;
33 static constexpr int SET_JUMP_VALUE = 1;
34 static constexpr int BITDEPTH_VALUE_1 = 1;
35 static constexpr int BITDEPTH_VALUE_2 = 2;
36 static constexpr int BITDEPTH_VALUE_4 = 4;
37 static constexpr int BITDEPTH_VALUE_8 = 8;
38 static constexpr int BITDEPTH_VALUE_16 = 16;
39 static constexpr size_t DECODE_BUFFER_SIZE = 4096;
40 static constexpr size_t CHUNK_SIZE = 8;
41 static constexpr size_t CHUNK_DATA_LEN = 4;
42 static constexpr int PNG_HEAD_SIZE = 100;
43
PngDecoder()44 PngDecoder::PngDecoder()
45 {
46 if (!InitPnglib()) {
47 HiLog::Error(LABEL, "Png decoder init failed!");
48 }
49 }
50
~PngDecoder()51 PngDecoder::~PngDecoder()
52 {
53 Reset();
54 // destroy the png decode struct
55 if (pngStructPtr_) {
56 png_infopp pngInfoPtr = pngInfoPtr_ ? &pngInfoPtr_ : nullptr;
57 png_destroy_read_struct(&pngStructPtr_, pngInfoPtr, nullptr);
58 }
59 }
60
SetSource(InputDataStream & sourceStream)61 void PngDecoder::SetSource(InputDataStream &sourceStream)
62 {
63 inputStreamPtr_ = &sourceStream;
64 state_ = PngDecodingState::SOURCE_INITED;
65 }
66
GetImageSize(uint32_t index,PlSize & size)67 uint32_t PngDecoder::GetImageSize(uint32_t index, PlSize &size)
68 {
69 // PNG format only supports one picture decoding, index in order to Compatible animation scene.
70 if (index >= PNG_IMAGE_NUM) {
71 HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}u.", index, PNG_IMAGE_NUM);
72 return ERR_IMAGE_INVALID_PARAMETER;
73 }
74 if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) {
75 HiLog::Error(LABEL, "create Png Struct or Png Info failed!");
76 return ERR_IMAGE_INIT_ABNORMAL;
77 }
78 if (state_ < PngDecodingState::SOURCE_INITED) {
79 HiLog::Error(LABEL, "get image size failed for state %{public}d.", state_);
80 return ERR_MEDIA_INVALID_OPERATION;
81 }
82 if (state_ >= PngDecodingState::BASE_INFO_PARSED) {
83 size.width = png_get_image_width(pngStructPtr_, pngInfoPtr_);
84 size.height = png_get_image_height(pngStructPtr_, pngInfoPtr_);
85 return SUCCESS;
86 }
87 // only state PngDecodingState::SOURCE_INITED and PngDecodingState::BASE_INFO_PARSING can go here.
88 uint32_t ret = DecodeHeader();
89 if (ret != SUCCESS) {
90 HiLog::Debug(LABEL, "decode header error on get image ret:%{public}u.", ret);
91 return ret;
92 }
93 size.width = png_get_image_width(pngStructPtr_, pngInfoPtr_);
94 size.height = png_get_image_height(pngStructPtr_, pngInfoPtr_);
95 return SUCCESS;
96 }
97
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)98 uint32_t PngDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
99 {
100 // PNG format only supports one picture decoding, index in order to Compatible animation scene.
101 if (index >= PNG_IMAGE_NUM) {
102 HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}u.", index, PNG_IMAGE_NUM);
103 return ERR_IMAGE_INVALID_PARAMETER;
104 }
105 if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) {
106 HiLog::Error(LABEL, "Png init fail, can't set decode option.");
107 return ERR_IMAGE_INIT_ABNORMAL;
108 }
109 if (state_ < PngDecodingState::SOURCE_INITED) {
110 HiLog::Error(LABEL, "set decode options failed for state %{public}d.", state_);
111 return ERR_MEDIA_INVALID_OPERATION;
112 }
113 if (state_ >= PngDecodingState::IMAGE_DECODING) {
114 if (!FinishOldDecompress()) {
115 HiLog::Error(LABEL, "finish old decompress fail, can't set decode option.");
116 return ERR_IMAGE_INIT_ABNORMAL;
117 }
118 }
119 if (state_ < PngDecodingState::BASE_INFO_PARSED) {
120 uint32_t ret = DecodeHeader();
121 if (ret != SUCCESS) {
122 HiLog::Error(LABEL, "decode header error on set decode options:%{public}u.", ret);
123 return ret;
124 }
125 }
126
127 DealNinePatch(opts);
128 // only state PngDecodingState::BASE_INFO_PARSED can go here.
129 uint32_t ret = ConfigInfo(opts);
130 if (ret != SUCCESS) {
131 HiLog::Error(LABEL, "config decoding failed on set decode options:%{public}u.", ret);
132 return ret;
133 }
134 info.size.width = pngImageInfo_.width;
135 info.size.height = pngImageInfo_.height;
136 info.pixelFormat = outputFormat_;
137 info.alphaType = alphaType_;
138 opts_ = opts;
139 state_ = PngDecodingState::IMAGE_DECODING;
140 return SUCCESS;
141 }
142
HasProperty(std::string key)143 bool PngDecoder::HasProperty(std::string key)
144 {
145 if (NINE_PATCH == key) {
146 return static_cast<void *>(ninePatch_.patch_) != nullptr && ninePatch_.patchSize_ != 0;
147 }
148 return false;
149 }
150
Decode(uint32_t index,DecodeContext & context)151 uint32_t PngDecoder::Decode(uint32_t index, DecodeContext &context)
152 {
153 // PNG format only supports one picture decoding, index in order to Compatible animation scene.
154 if (index >= PNG_IMAGE_NUM) {
155 HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}u.", index, PNG_IMAGE_NUM);
156 return ERR_IMAGE_INVALID_PARAMETER;
157 }
158 if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) {
159 HiLog::Error(LABEL, "Png init failed can't begin to decode.");
160 return ERR_IMAGE_INIT_ABNORMAL;
161 }
162 if (state_ < PngDecodingState::IMAGE_DECODING) {
163 HiLog::Error(LABEL, "decode failed for state %{public}d.", state_);
164 return ERR_MEDIA_INVALID_OPERATION;
165 }
166 if (state_ > PngDecodingState::IMAGE_DECODING) {
167 if (!FinishOldDecompress()) {
168 HiLog::Error(LABEL, "finish old decompress fail on decode.");
169 return ERR_IMAGE_INIT_ABNORMAL;
170 }
171 uint32_t ret = DecodeHeader();
172 if (ret != SUCCESS) {
173 HiLog::Error(LABEL, "decode header error on decode:%{public}u.", ret);
174 return ret;
175 }
176 ret = ConfigInfo(opts_);
177 if (ret != SUCCESS) {
178 HiLog::Error(LABEL, "config decoding info failed on decode:%{public}u.", ret);
179 return ret;
180 }
181 state_ = PngDecodingState::IMAGE_DECODING;
182 }
183 // only state PngDecodingState::IMAGE_DECODING can go here.
184 context.ninePatchContext.ninePatch = static_cast<void *>(ninePatch_.patch_);
185 context.ninePatchContext.patchSize = ninePatch_.patchSize_;
186 uint32_t ret = DoOneTimeDecode(context);
187 if (ret == SUCCESS) {
188 state_ = PngDecodingState::IMAGE_DECODED;
189 return SUCCESS;
190 }
191 if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE && opts_.allowPartialImage) {
192 state_ = PngDecodingState::IMAGE_PARTIAL;
193 context.ifPartialOutput = true;
194 HiLog::Error(LABEL, "this is partial image data to decode, ret:%{public}u.", ret);
195 return SUCCESS;
196 }
197 state_ = PngDecodingState::IMAGE_ERROR;
198 return ret;
199 }
200
AllocOutputHeapBuffer(DecodeContext & context)201 uint8_t *PngDecoder::AllocOutputHeapBuffer(DecodeContext &context)
202 {
203 if (context.pixelsBuffer.buffer == nullptr) {
204 uint64_t byteCount = static_cast<uint64_t>(pngImageInfo_.rowDataSize) * pngImageInfo_.height;
205 if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
206 #if !defined(_WIN32) && !defined(_APPLE)
207 int fd = AshmemCreate("PNG RawData", byteCount);
208 if (fd < 0) {
209 return nullptr;
210 }
211 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
212 if (result < 0) {
213 ::close(fd);
214 return nullptr;
215 }
216 void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
217 if (ptr == MAP_FAILED) {
218 ::close(fd);
219 return nullptr;
220 }
221 context.pixelsBuffer.buffer = ptr;
222 void *fdBuffer = new int32_t();
223 if (fdBuffer == nullptr) {
224 HiLog::Error(LABEL, "new fdBuffer fail");
225 ::munmap(ptr, byteCount);
226 ::close(fd);
227 context.pixelsBuffer.buffer = nullptr;
228 return nullptr;
229 }
230 *static_cast<int32_t *>(fdBuffer) = fd;
231 context.pixelsBuffer.context = fdBuffer;
232 context.pixelsBuffer.bufferSize = byteCount;
233 context.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
234 context.freeFunc = nullptr;
235 #endif
236 } else {
237 void *outputBuffer = malloc(byteCount);
238 if (outputBuffer == nullptr) {
239 HiLog::Error(LABEL, "alloc output buffer size:[%{public}llu] error.",
240 static_cast<unsigned long long>(byteCount));
241 return nullptr;
242 }
243 #ifdef _WIN32
244 memset(outputBuffer, 0, byteCount);
245 #else
246 if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
247 HiLog::Error(LABEL, "init output buffer fail.");
248 free(outputBuffer);
249 outputBuffer = nullptr;
250 return nullptr;
251 }
252 #endif
253 context.pixelsBuffer.buffer = outputBuffer;
254 context.pixelsBuffer.bufferSize = byteCount;
255 context.pixelsBuffer.context = nullptr;
256 context.allocatorType = AllocatorType::HEAP_ALLOC;
257 context.freeFunc = nullptr;
258 }
259 }
260 return static_cast<uint8_t *>(context.pixelsBuffer.buffer);
261 }
262
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)263 uint32_t PngDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
264 {
265 // PNG format only supports one picture decoding, index in order to Compatible animation scene.
266 context.totalProcessProgress = 0;
267 if (index >= PNG_IMAGE_NUM) {
268 HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}u.", index, PNG_IMAGE_NUM);
269 return ERR_IMAGE_INVALID_PARAMETER;
270 }
271 if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) {
272 HiLog::Error(LABEL, "Png init failed can't begin to decode.");
273 return ERR_IMAGE_INIT_ABNORMAL;
274 }
275 if (state_ != PngDecodingState::IMAGE_DECODING) {
276 HiLog::Error(LABEL, "incremental decode failed for state %{public}d.", state_);
277 return ERR_MEDIA_INVALID_OPERATION;
278 }
279
280 pixelsData_ = AllocOutputHeapBuffer(context.decodeContext);
281 if (pixelsData_ == nullptr) {
282 HiLog::Error(LABEL, "get pixels memory fail.");
283 return ERR_IMAGE_MALLOC_ABNORMAL;
284 }
285 inputStreamPtr_->Seek(streamPosition_);
286 uint32_t ret = IncrementalReadRows(inputStreamPtr_);
287 streamPosition_ = inputStreamPtr_->Tell();
288 if (ret != SUCCESS) {
289 if (ret != ERR_IMAGE_SOURCE_DATA_INCOMPLETE) {
290 HiLog::Error(LABEL, "Incremental decode fail, ret:%{public}u", ret);
291 }
292 } else {
293 if (outputRowsNum_ != pngImageInfo_.height) {
294 HiLog::Debug(LABEL, "Incremental decode incomplete, outputRowsNum:%{public}u, height:%{public}u",
295 outputRowsNum_, pngImageInfo_.height);
296 }
297 state_ = PngDecodingState::IMAGE_DECODED;
298 }
299 // get promote decode progress, in percentage: 0~100.
300 // DecodeHeader() has judged that pngImageInfo_.height should not be equal to 0 and returns a failure result,
301 // so here pngImageInfo_.height will not be equal to 0 in the PngDecodingState::IMAGE_DECODING state.
302 context.totalProcessProgress =
303 outputRowsNum_ == 0 ? 0 : outputRowsNum_ * ProgDecodeContext::FULL_PROGRESS / pngImageInfo_.height;
304 HiLog::Debug(LABEL, "Incremental decode progress %{public}u.", context.totalProcessProgress);
305 return ret;
306 }
307
Reset()308 void PngDecoder::Reset()
309 {
310 inputStreamPtr_ = nullptr;
311 decodedIdat_ = false;
312 idatLength_ = 0;
313 incrementalLength_ = 0;
314 pixelsData_ = nullptr;
315 outputRowsNum_ = 0;
316 decodeHeadFlag_ = false;
317 firstRow_ = 0;
318 lastRow_ = 0;
319 interlacedComplete_ = false;
320 }
321
322 // private interface
ConvertOriginalFormat(png_byte source,png_byte & destination)323 bool PngDecoder::ConvertOriginalFormat(png_byte source, png_byte &destination)
324 {
325 if (png_get_valid(pngStructPtr_, pngInfoPtr_, PNG_INFO_tRNS)) {
326 png_set_tRNS_to_alpha(pngStructPtr_);
327 }
328 HiLog::Info(LABEL, "color type:[%{public}d]", source);
329 switch (source) {
330 case PNG_COLOR_TYPE_PALETTE: { // value is 3
331 png_set_palette_to_rgb(pngStructPtr_);
332 destination = PNG_COLOR_TYPE_RGB;
333 break;
334 }
335 case PNG_COLOR_TYPE_GRAY: { // value is 0
336 if (pngImageInfo_.bitDepth < 8) { // 8 is single pixel bit depth
337 png_set_expand_gray_1_2_4_to_8(pngStructPtr_);
338 }
339 png_set_gray_to_rgb(pngStructPtr_);
340 destination = PNG_COLOR_TYPE_RGB;
341 break;
342 }
343 case PNG_COLOR_TYPE_GRAY_ALPHA: { // value is 4
344 png_set_gray_to_rgb(pngStructPtr_);
345 destination = PNG_COLOR_TYPE_RGB;
346 break;
347 }
348 case PNG_COLOR_TYPE_RGB:
349 case PNG_COLOR_TYPE_RGB_ALPHA: { // value is 6
350 destination = source;
351 break;
352 }
353 default: {
354 HiLog::Error(LABEL, "the color type:[%{public}d] libpng unsupported!", source);
355 return false;
356 }
357 }
358
359 return true;
360 }
361
GetDecodeFormat(PlPixelFormat format,PlPixelFormat & outputFormat,PlAlphaType & alphaType)362 uint32_t PngDecoder::GetDecodeFormat(PlPixelFormat format, PlPixelFormat &outputFormat, PlAlphaType &alphaType)
363 {
364 png_byte sourceType = png_get_color_type(pngStructPtr_, pngInfoPtr_);
365 if ((sourceType & PNG_COLOR_MASK_ALPHA) || png_get_valid(pngStructPtr_, pngInfoPtr_, PNG_INFO_tRNS)) {
366 alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
367 } else {
368 alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
369 }
370 png_byte destType = 0;
371 if (!ConvertOriginalFormat(sourceType, destType)) {
372 return ERR_IMAGE_DATA_UNSUPPORT;
373 }
374 if (format != PlPixelFormat::RGB_888 && destType == PNG_COLOR_TYPE_RGB) {
375 png_set_add_alpha(pngStructPtr_, 0xff, PNG_FILLER_AFTER); // 0xffff add the A after RGB.
376 }
377 // only support 8 bit depth for each pixel except for RGBA_F16
378 if (format != PlPixelFormat::RGBA_F16 && pngImageInfo_.bitDepth == 16) { // 16bit depth
379 pngImageInfo_.bitDepth = 8; // 8bit depth
380 png_set_strip_16(pngStructPtr_);
381 }
382 ChooseFormat(format, outputFormat, destType);
383 return SUCCESS;
384 }
385
ChooseFormat(PlPixelFormat format,PlPixelFormat & outputFormat,png_byte destType)386 void PngDecoder::ChooseFormat(PlPixelFormat format, PlPixelFormat &outputFormat,
387 png_byte destType)
388 {
389 outputFormat = format;
390 switch (format) {
391 case PlPixelFormat::BGRA_8888: {
392 pngImageInfo_.rowDataSize = pngImageInfo_.width * 4; // 4 is BGRA size
393 png_set_bgr(pngStructPtr_);
394 break;
395 }
396 case PlPixelFormat::ARGB_8888: {
397 png_set_swap_alpha(pngStructPtr_);
398 pngImageInfo_.rowDataSize = pngImageInfo_.width * 4; // 4 is ARGB size
399 break;
400 }
401 case PlPixelFormat::RGB_888: {
402 if (destType == PNG_COLOR_TYPE_RGBA) {
403 png_set_strip_alpha(pngStructPtr_);
404 }
405 pngImageInfo_.rowDataSize = pngImageInfo_.width * 3; // 3 is RGB size
406 break;
407 }
408 case PlPixelFormat::RGBA_F16: {
409 png_set_scale_16(pngStructPtr_);
410 pngImageInfo_.rowDataSize = pngImageInfo_.width * 7; // 7 is RRGGBBA size
411 break;
412 }
413 case PlPixelFormat::UNKNOWN:
414 case PlPixelFormat::RGBA_8888:
415 default: {
416 pngImageInfo_.rowDataSize = pngImageInfo_.width * 4; // 4 is RGBA size
417 outputFormat = PlPixelFormat::RGBA_8888;
418 break;
419 }
420 }
421 }
422
PngErrorExit(png_structp pngPtr,png_const_charp message)423 void PngDecoder::PngErrorExit(png_structp pngPtr, png_const_charp message)
424 {
425 if ((pngPtr == nullptr) || (message == nullptr)) {
426 HiLog::Error(LABEL, "ErrorExit png_structp or error message is null.");
427 return;
428 }
429 jmp_buf *jmpBuf = &(png_jmpbuf(pngPtr));
430 if (jmpBuf == nullptr) {
431 HiLog::Error(LABEL, "jmpBuf exception.");
432 return;
433 }
434 longjmp(*jmpBuf, SET_JUMP_VALUE);
435 }
436
PngWarning(png_structp pngPtr,png_const_charp message)437 void PngDecoder::PngWarning(png_structp pngPtr, png_const_charp message)
438 {
439 if (message == nullptr) {
440 HiLog::Error(LABEL, "WarningExit message is null.");
441 return;
442 }
443 HiLog::Warn(LABEL, "png warn %{public}s", message);
444 }
445
PngErrorMessage(png_structp pngPtr,png_const_charp message)446 void PngDecoder::PngErrorMessage(png_structp pngPtr, png_const_charp message)
447 {
448 if (message == nullptr) {
449 HiLog::Error(LABEL, "PngErrorMessage message is null.");
450 return;
451 }
452 HiLog::Error(LABEL, "PngErrorMessage, message:%{public}s.", message);
453 }
454
PngWarningMessage(png_structp pngPtr,png_const_charp message)455 void PngDecoder::PngWarningMessage(png_structp pngPtr, png_const_charp message)
456 {
457 if (message == nullptr) {
458 HiLog::Error(LABEL, "PngWarningMessage message is null.");
459 return;
460 }
461 HiLog::Error(LABEL, "PngWarningMessage, message:%{public}s.", message);
462 }
463
464 // image incremental decode Interface
ProcessData(png_structp pngStructPtr,png_infop infoStructPtr,InputDataStream * sourceStream,DataStreamBuffer streamData,size_t bufferSize,size_t totalSize)465 uint32_t PngDecoder::ProcessData(png_structp pngStructPtr, png_infop infoStructPtr, InputDataStream *sourceStream,
466 DataStreamBuffer streamData, size_t bufferSize, size_t totalSize)
467 {
468 if (pngStructPtr == nullptr || infoStructPtr == nullptr || sourceStream == nullptr || totalSize == 0 ||
469 bufferSize == 0) {
470 HiLog::Error(LABEL, "ProcessData input error, totalSize:%{public}zu, bufferSize:%{public}zu.", totalSize,
471 bufferSize);
472 return ERR_IMAGE_INVALID_PARAMETER;
473 }
474 while (totalSize > 0) {
475 size_t readSize = (bufferSize < totalSize) ? bufferSize : totalSize;
476 uint32_t ret = IncrementalRead(sourceStream, readSize, streamData);
477 if (ret != SUCCESS) {
478 HiLog::Error(LABEL, "ProcessData Read from source stream fail, readSize:%{public}zu,\
479 bufferSize:%{public}zu, dataSize:%{public}u, totalSize:%{public}zu.",
480 readSize, bufferSize, streamData.dataSize, totalSize);
481 return ret;
482 }
483 png_process_data(pngStructPtr, infoStructPtr, const_cast<png_bytep>(streamData.inputStreamBuffer),
484 streamData.dataSize);
485 totalSize -= streamData.dataSize;
486 }
487 return SUCCESS;
488 }
489
IsChunk(const png_byte * chunk,const char * flag)490 bool PngDecoder::IsChunk(const png_byte *chunk, const char *flag)
491 {
492 if (chunk == nullptr || flag == nullptr) {
493 HiLog::Error(LABEL, "IsChunk input parameter exception.");
494 return false;
495 }
496 return memcmp(chunk + CHUNK_DATA_LEN, flag, CHUNK_DATA_LEN) == 0;
497 }
498
GetImageInfo(PngImageInfo & info)499 bool PngDecoder::GetImageInfo(PngImageInfo &info)
500 {
501 png_uint_32 origWidth = 0;
502 png_uint_32 origHeight = 0;
503 int32_t bitDepth = 0;
504 png_get_IHDR(pngStructPtr_, pngInfoPtr_, &origWidth, &origHeight, &bitDepth, nullptr, nullptr, nullptr, nullptr);
505 if ((origWidth == 0) || (origHeight == 0) || (origWidth > PNG_UINT_31_MAX) || (origHeight > PNG_UINT_31_MAX)) {
506 HiLog::Error(LABEL, "Get the png image size abnormal, width:%{public}u, height:%{public}u", origWidth,
507 origHeight);
508 return false;
509 }
510 if (bitDepth != BITDEPTH_VALUE_1 && bitDepth != BITDEPTH_VALUE_2 && bitDepth != BITDEPTH_VALUE_4 &&
511 bitDepth != BITDEPTH_VALUE_8 && bitDepth != BITDEPTH_VALUE_16) {
512 HiLog::Error(LABEL, "Get the png image bit depth abnormal, bitDepth:%{public}d.", bitDepth);
513 return false;
514 }
515 size_t rowDataSize = png_get_rowbytes(pngStructPtr_, pngInfoPtr_);
516 if (rowDataSize == 0) {
517 HiLog::Error(LABEL, "Get the bitmap row bytes size fail.");
518 return false;
519 }
520 info.numberPasses = png_set_interlace_handling(pngStructPtr_);
521 info.width = origWidth;
522 info.height = origHeight;
523 info.bitDepth = bitDepth;
524 info.rowDataSize = rowDataSize;
525 HiLog::Info(LABEL, "GetImageInfo:width:%{public}u,height:%{public}u,bitDepth:%{public}u,numberPasses:%{public}d.",
526 origWidth, origHeight, info.bitDepth, info.numberPasses);
527 return true;
528 }
529
IncrementalRead(InputDataStream * stream,uint32_t desiredSize,DataStreamBuffer & outData)530 uint32_t PngDecoder::IncrementalRead(InputDataStream *stream, uint32_t desiredSize, DataStreamBuffer &outData)
531 {
532 uint32_t curPos = stream->Tell();
533 if (!stream->Read(desiredSize, outData)) {
534 HiLog::Debug(LABEL, "read data fail.");
535 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
536 }
537 if (outData.inputStreamBuffer == nullptr || outData.dataSize == 0) {
538 HiLog::Error(LABEL, "inputStreamBuffer is null or data size is %{public}u.", outData.dataSize);
539 return ERR_IMAGE_GET_DATA_ABNORMAL;
540 }
541 if (outData.dataSize < desiredSize) {
542 stream->Seek(curPos);
543 HiLog::Debug(LABEL, "read outdata size[%{public}u] < data size[%{public}u] and curpos:%{public}u",
544 outData.dataSize, desiredSize, curPos);
545 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
546 }
547 return SUCCESS;
548 }
549
GetImageIdatSize(InputDataStream * stream)550 uint32_t PngDecoder::GetImageIdatSize(InputDataStream *stream)
551 {
552 uint32_t ret = 0;
553 DataStreamBuffer readData;
554 while (true) {
555 uint32_t preReadPos = stream->Tell();
556 ret = IncrementalRead(stream, static_cast<uint32_t>(CHUNK_SIZE), readData);
557 if (ret != SUCCESS) {
558 break;
559 }
560 png_byte *chunk = const_cast<png_byte *>(readData.inputStreamBuffer);
561 const size_t length = png_get_uint_32(chunk);
562 if (IsChunk(chunk, "IDAT")) {
563 HiLog::Debug(LABEL, "first idat Length is %{public}zu.", length);
564 idatLength_ = length;
565 return SUCCESS;
566 }
567 uint32_t afterReadPos = stream->Tell();
568 if (!stream->Seek(length + afterReadPos + CHUNK_DATA_LEN)) {
569 HiLog::Debug(LABEL, "stream current pos is %{public}u, chunk size is %{public}zu.", preReadPos, length);
570 stream->Seek(preReadPos);
571 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
572 }
573 stream->Seek(afterReadPos);
574 png_process_data(pngStructPtr_, pngInfoPtr_, chunk, CHUNK_SIZE);
575 ret = ProcessData(pngStructPtr_, pngInfoPtr_, stream, readData, DECODE_BUFFER_SIZE, length + CHUNK_DATA_LEN);
576 if (ret != SUCCESS) {
577 break;
578 }
579 }
580 return ret;
581 }
582
ReadIncrementalHead(InputDataStream * stream,PngImageInfo & info)583 uint32_t PngDecoder::ReadIncrementalHead(InputDataStream *stream, PngImageInfo &info)
584 {
585 if (stream == nullptr) {
586 HiLog::Error(LABEL, "read incremental head input data is null!");
587 return ERR_IMAGE_INVALID_PARAMETER;
588 }
589 uint32_t pos = stream->Tell();
590 if (!stream->Seek(PNG_HEAD_SIZE)) {
591 HiLog::Debug(LABEL, "don't enough the data to decode the image head.");
592 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
593 }
594 stream->Seek(pos);
595 // set the exception handle
596 jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_));
597 if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) {
598 HiLog::Error(LABEL, "read incremental head PNG decode head exception.");
599 return ERR_IMAGE_DECODE_HEAD_ABNORMAL;
600 }
601
602 DataStreamBuffer readData;
603 if (!decodeHeadFlag_) {
604 png_set_keep_unknown_chunks(pngStructPtr_, PNG_HANDLE_CHUNK_ALWAYS, (png_byte *)"", 0);
605 png_set_read_user_chunk_fn(pngStructPtr_, static_cast<png_voidp>(&ninePatch_), ReadUserChunk);
606 png_set_progressive_read_fn(pngStructPtr_, nullptr, nullptr, nullptr, nullptr);
607 uint32_t ret = IncrementalRead(stream, static_cast<uint32_t>(CHUNK_SIZE), readData);
608 if (ret != SUCCESS) {
609 return ret;
610 }
611 png_bytep head = const_cast<png_bytep>(readData.inputStreamBuffer);
612 png_process_data(pngStructPtr_, pngInfoPtr_, head, CHUNK_SIZE);
613 decodeHeadFlag_ = true;
614 }
615 uint32_t ret = GetImageIdatSize(stream);
616 if (ret != SUCCESS) {
617 HiLog::Error(LABEL, "get image idat size fail, ret:%{public}u.", ret);
618 return ret;
619 }
620 if (!GetImageInfo(info)) {
621 return ERR_IMAGE_DECODE_HEAD_ABNORMAL;
622 }
623 return SUCCESS;
624 }
625
SaveRows(png_bytep row,png_uint_32 rowNum)626 void PngDecoder::SaveRows(png_bytep row, png_uint_32 rowNum)
627 {
628 if (rowNum != outputRowsNum_ || pngImageInfo_.height < rowNum) {
629 HiLog::Error(LABEL,
630 "AllRowsCallback exception, rowNum:%{public}u, outputRowsNum:%{public}u, height:%{public}u.",
631 rowNum, outputRowsNum_, pngImageInfo_.height);
632 return;
633 }
634 outputRowsNum_++;
635 uint8_t *offset = pixelsData_ + rowNum * pngImageInfo_.rowDataSize;
636 uint32_t offsetSize = (pngImageInfo_.height - rowNum) * pngImageInfo_.rowDataSize;
637 errno_t ret = memcpy_s(offset, offsetSize, row, pngImageInfo_.rowDataSize);
638 if (ret != 0) {
639 HiLog::Error(LABEL, "copy data fail, ret:%{public}d, rowDataSize:%{public}u, offsetSize:%{public}u.", ret,
640 pngImageInfo_.rowDataSize, offsetSize);
641 return;
642 }
643 }
644
SaveInterlacedRows(png_bytep row,png_uint_32 rowNum,int pass)645 void PngDecoder::SaveInterlacedRows(png_bytep row, png_uint_32 rowNum, int pass)
646 {
647 if (row == nullptr) {
648 HiLog::Error(LABEL, "input row is null.");
649 return;
650 }
651 if (rowNum < firstRow_ || rowNum > lastRow_ || interlacedComplete_) {
652 HiLog::Error(LABEL, "ignore this row, rowNum:%{public}u,InterlacedComplete:%{public}u.", rowNum,
653 interlacedComplete_);
654 return;
655 }
656 png_bytep oldRow = pixelsData_ + (rowNum - firstRow_) * pngImageInfo_.rowDataSize;
657 uint64_t mollocByteCount = static_cast<uint64_t>(pngImageInfo_.rowDataSize) * pngImageInfo_.height;
658 uint64_t needByteCount = static_cast<uint64_t>(pngStructPtr_->width) * sizeof(*oldRow);
659 if (mollocByteCount < needByteCount) {
660 HiLog::Error(LABEL, "malloc byte size is(%{public}llu), but actual needs (%{public}llu)",
661 static_cast<unsigned long long>(mollocByteCount), static_cast<unsigned long long>(needByteCount));
662 return;
663 }
664 png_progressive_combine_row(pngStructPtr_, oldRow, row);
665 if (pass == 0) {
666 // The first pass initializes all rows.
667 if (outputRowsNum_ == rowNum - firstRow_) {
668 HiLog::Error(LABEL, "rowNum(%{public}u) - firstRow(%{public}u) = outputRow(%{public}u)", rowNum, firstRow_,
669 outputRowsNum_);
670 return;
671 }
672 outputRowsNum_++;
673 } else {
674 if (outputRowsNum_ == lastRow_ - firstRow_ + 1) {
675 HiLog::Error(LABEL, "lastRow_(%{public}u) + firstRow(%{public}u) + 1 = outputRow(%{public}u)", lastRow_,
676 firstRow_, outputRowsNum_);
677 return;
678 }
679 if (pngImageInfo_.numberPasses - 1 == pass && rowNum == lastRow_) {
680 // Last pass, and we have read all of the rows we care about.
681 HiLog::Error(LABEL, "last pass:%{public}d, numberPasses:%{public}d, rowNum:%{public}d, lastRow:%{public}d.",
682 pass, pngImageInfo_.numberPasses, rowNum, lastRow_);
683 interlacedComplete_ = true;
684 }
685 }
686 }
687
GetAllRows(png_structp pngPtr,png_bytep row,png_uint_32 rowNum,int pass)688 void PngDecoder::GetAllRows(png_structp pngPtr, png_bytep row, png_uint_32 rowNum, int pass)
689 {
690 if (pngPtr == nullptr || row == nullptr) {
691 HiLog::Error(LABEL, "get decode rows exception, rowNum:%{public}u.", rowNum);
692 return;
693 }
694 PngDecoder *decoder = static_cast<PngDecoder *>(png_get_progressive_ptr(pngPtr));
695 if (decoder == nullptr) {
696 HiLog::Error(LABEL, "get all rows fail, get decoder is null.");
697 return;
698 }
699 decoder->SaveRows(row, rowNum);
700 }
701
GetInterlacedRows(png_structp pngPtr,png_bytep row,png_uint_32 rowNum,int pass)702 void PngDecoder::GetInterlacedRows(png_structp pngPtr, png_bytep row, png_uint_32 rowNum, int pass)
703 {
704 if (pngPtr == nullptr || row == nullptr) {
705 HiLog::Debug(LABEL, "get decode rows exception, rowNum:%{public}u.", rowNum);
706 return;
707 }
708 PngDecoder *decoder = static_cast<PngDecoder *>(png_get_progressive_ptr(pngPtr));
709 if (decoder == nullptr) {
710 HiLog::Error(LABEL, "get all rows fail, get decoder is null.");
711 return;
712 }
713 decoder->SaveInterlacedRows(row, rowNum, pass);
714 }
715
ReadUserChunk(png_structp png_ptr,png_unknown_chunkp chunk)716 int32_t PngDecoder::ReadUserChunk(png_structp png_ptr, png_unknown_chunkp chunk)
717 {
718 NinePatchListener *chunkReader = static_cast<NinePatchListener *>(png_get_user_chunk_ptr(png_ptr));
719 if (chunkReader == nullptr) {
720 HiLog::Error(LABEL, "chunk header is null.");
721 return ERR_IMAGE_DECODE_ABNORMAL;
722 }
723 return chunkReader->ReadChunk(reinterpret_cast<const char *>(chunk->name), chunk->data, chunk->size)
724 ? SUCCESS
725 : ERR_IMAGE_DECODE_ABNORMAL;
726 }
727
PushAllToDecode(InputDataStream * stream,size_t bufferSize,size_t length)728 uint32_t PngDecoder::PushAllToDecode(InputDataStream *stream, size_t bufferSize, size_t length)
729 {
730 if (stream == nullptr || bufferSize == 0 || length == 0) {
731 HiLog::Error(LABEL, "iend process input exception, bufferSize:%{public}zu, length:%{public}zu.", bufferSize,
732 length);
733 return ERR_IMAGE_INVALID_PARAMETER;
734 }
735 DataStreamBuffer ReadData;
736 if (ProcessData(pngStructPtr_, pngInfoPtr_, stream, ReadData, bufferSize, length) != SUCCESS) {
737 HiLog::Error(LABEL, "ProcessData return false, bufferSize:%{public}zu, length:%{public}zu.", bufferSize,
738 length);
739 return ERR_IMAGE_DECODE_ABNORMAL;
740 }
741 bool iend = false;
742 uint32_t ret = 0;
743 while (true) {
744 // Parse chunk length and type.
745 ret = IncrementalRead(stream, CHUNK_SIZE, ReadData);
746 if (ret != SUCCESS) {
747 HiLog::Error(LABEL, "set iend mode Read chunk fail,ret:%{public}u", ret);
748 break;
749 }
750 png_byte *chunk = const_cast<png_byte *>(ReadData.inputStreamBuffer);
751 png_process_data(pngStructPtr_, pngInfoPtr_, chunk, CHUNK_SIZE);
752 if (IsChunk(chunk, "IEND")) {
753 iend = true;
754 }
755 size_t chunkLength = png_get_uint_32(chunk);
756 // Process the full chunk + CRC
757 ret = ProcessData(pngStructPtr_, pngInfoPtr_, stream, ReadData, bufferSize, chunkLength + CHUNK_DATA_LEN);
758 if (ret != SUCCESS || iend) {
759 break;
760 }
761 }
762 return ret;
763 }
764
IncrementalReadRows(InputDataStream * stream)765 uint32_t PngDecoder::IncrementalReadRows(InputDataStream *stream)
766 {
767 if (stream == nullptr) {
768 HiLog::Error(LABEL, "input data is null!");
769 return ERR_IMAGE_GET_DATA_ABNORMAL;
770 }
771 if (idatLength_ < incrementalLength_) {
772 HiLog::Error(LABEL, "incremental len:%{public}zu > idat len:%{public}zu.", incrementalLength_, idatLength_);
773 return ERR_IMAGE_INVALID_PARAMETER;
774 }
775 // set the exception handle
776 jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_));
777 if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) {
778 HiLog::Error(LABEL, "[IncrementalReadRows]PNG decode exception.");
779 return ERR_IMAGE_DECODE_ABNORMAL;
780 }
781 // set process decode state to IDAT mode.
782 if (!decodedIdat_) {
783 if (pngImageInfo_.numberPasses == 1) {
784 png_set_progressive_read_fn(pngStructPtr_, this, nullptr, GetAllRows, nullptr);
785 } else {
786 png_set_progressive_read_fn(pngStructPtr_, this, nullptr, GetInterlacedRows, nullptr);
787 lastRow_ = pngImageInfo_.height - 1; // decode begin to 0
788 }
789 png_byte idat[] = { 0, 0, 0, 0, 'I', 'D', 'A', 'T' };
790 png_save_uint_32(idat, idatLength_);
791 png_process_data(pngStructPtr_, pngInfoPtr_, idat, CHUNK_SIZE);
792 decodedIdat_ = true;
793 idatLength_ += CHUNK_DATA_LEN;
794 }
795 if (stream->IsStreamCompleted()) {
796 uint32_t ret = PushAllToDecode(stream, DECODE_BUFFER_SIZE, idatLength_ - incrementalLength_);
797 if (ret != SUCCESS) {
798 HiLog::Error(LABEL, "iend set fail, ret:%{public}u, idatLen:%{public}zu, incrementalLen:%{public}zu.", ret,
799 idatLength_, incrementalLength_);
800 return ret;
801 }
802 return SUCCESS;
803 }
804 uint32_t ret = PushCurrentToDecode(stream);
805 if (ret != SUCCESS) {
806 HiLog::Error(LABEL,
807 "push stream to decode fail, ret:%{public}u, idatLen:%{public}zu, incrementalLen:%{public}zu.",
808 ret, idatLength_, incrementalLength_);
809 return ret;
810 }
811 return SUCCESS;
812 }
813
PushCurrentToDecode(InputDataStream * stream)814 uint32_t PngDecoder::PushCurrentToDecode(InputDataStream *stream)
815 {
816 if (stream == nullptr) {
817 HiLog::Error(LABEL, "push current stream to decode input data is null!");
818 return ERR_IMAGE_GET_DATA_ABNORMAL;
819 }
820 if (idatLength_ == 0) {
821 HiLog::Error(LABEL, "idat Length is zero.");
822 return ERR_IMAGE_DECODE_ABNORMAL;
823 }
824
825 DataStreamBuffer ReadData;
826 uint32_t ret = 0;
827 while (incrementalLength_ < idatLength_) {
828 const size_t targetSize = std::min(DECODE_BUFFER_SIZE, idatLength_ - incrementalLength_);
829 ret = IncrementalRead(stream, targetSize, ReadData);
830 if (ret != SUCCESS) {
831 HiLog::Debug(LABEL, "push current stream read fail, ret:%{public}u", ret);
832 return ret;
833 }
834 incrementalLength_ += ReadData.dataSize;
835 png_process_data(pngStructPtr_, pngInfoPtr_, (png_bytep)ReadData.inputStreamBuffer, ReadData.dataSize);
836 }
837
838 while (true) {
839 ret = IncrementalRead(stream, CHUNK_SIZE, ReadData);
840 if (ret != SUCCESS) {
841 HiLog::Debug(LABEL, "set iend mode Read chunk fail,ret:%{public}u", ret);
842 break;
843 }
844 png_byte *chunk = const_cast<png_byte *>(ReadData.inputStreamBuffer);
845 png_process_data(pngStructPtr_, pngInfoPtr_, chunk, CHUNK_SIZE);
846 idatLength_ = png_get_uint_32(chunk) + CHUNK_DATA_LEN;
847 incrementalLength_ = 0;
848 while (incrementalLength_ < idatLength_) {
849 const size_t targetSize = std::min(DECODE_BUFFER_SIZE, idatLength_ - incrementalLength_);
850 ret = IncrementalRead(stream, targetSize, ReadData);
851 if (ret != SUCCESS) {
852 HiLog::Debug(LABEL, "push current stream read fail, ret:%{public}u", ret);
853 return ret;
854 }
855 incrementalLength_ += ReadData.dataSize;
856 png_process_data(pngStructPtr_, pngInfoPtr_, (png_bytep)ReadData.inputStreamBuffer, ReadData.dataSize);
857 }
858 }
859 return ret;
860 }
861
DecodeHeader()862 uint32_t PngDecoder::DecodeHeader()
863 {
864 // only state PngDecodingState::SOURCE_INITED and PngDecodingState::BASE_INFO_PARSING can go in this function.
865 if (inputStreamPtr_->IsStreamCompleted()) {
866 // decode the png image header
867 inputStreamPtr_->Seek(0);
868 }
869 // incremental decode the png image header
870 if (state_ == PngDecodingState::SOURCE_INITED) {
871 inputStreamPtr_->Seek(0);
872 } else {
873 inputStreamPtr_->Seek(streamPosition_);
874 }
875 uint32_t ret = ReadIncrementalHead(inputStreamPtr_, pngImageInfo_);
876 if (ret != SUCCESS) {
877 if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) {
878 streamPosition_ = inputStreamPtr_->Tell();
879 state_ = PngDecodingState::BASE_INFO_PARSING;
880 } else {
881 state_ = PngDecodingState::SOURCE_INITED;
882 HiLog::Error(LABEL, "decode image head, ret:%{public}u.", ret);
883 }
884 return ret;
885 }
886 if (pngImageInfo_.width == 0 || pngImageInfo_.height == 0) {
887 HiLog::Error(LABEL, "get width and height fail, height:%{public}u, width:%{public}u.", pngImageInfo_.height,
888 pngImageInfo_.width);
889 state_ = PngDecodingState::SOURCE_INITED;
890 return ERR_IMAGE_GET_DATA_ABNORMAL;
891 }
892 streamPosition_ = inputStreamPtr_->Tell();
893 state_ = PngDecodingState::BASE_INFO_PARSED;
894 return SUCCESS;
895 }
896
ConfigInfo(const PixelDecodeOptions & opts)897 uint32_t PngDecoder::ConfigInfo(const PixelDecodeOptions &opts)
898 {
899 uint32_t ret = SUCCESS;
900 bool isComeNinePatchRGB565 = false;
901 if (ninePatch_.patch_ != nullptr) {
902 // Do not allow ninepatch decodes to 565,use RGBA_8888;
903 if (opts.desiredPixelFormat == PlPixelFormat::RGB_565) {
904 ret = GetDecodeFormat(PlPixelFormat::RGBA_8888, outputFormat_, alphaType_);
905 isComeNinePatchRGB565 = true;
906 }
907 }
908 if (!isComeNinePatchRGB565) {
909 ret = GetDecodeFormat(opts.desiredPixelFormat, outputFormat_, alphaType_);
910 }
911 if (ret != SUCCESS) {
912 HiLog::Error(LABEL, "get the color type fail.");
913 return ERR_IMAGE_DATA_ABNORMAL;
914 }
915
916 // get the libpng interface exception.
917 jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_));
918 if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) {
919 HiLog::Error(LABEL, "config decoding info fail.");
920 return ERR_IMAGE_DATA_ABNORMAL;
921 }
922 png_read_update_info(pngStructPtr_, pngInfoPtr_);
923 return SUCCESS;
924 }
925
DoOneTimeDecode(DecodeContext & context)926 uint32_t PngDecoder::DoOneTimeDecode(DecodeContext &context)
927 {
928 if (idatLength_ <= 0) {
929 HiLog::Error(LABEL, "normal decode the image source incomplete.");
930 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
931 }
932 jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_));
933 if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) {
934 HiLog::Error(LABEL, "decode the image fail.");
935 return ERR_IMAGE_DECODE_ABNORMAL;
936 }
937 pixelsData_ = AllocOutputHeapBuffer(context);
938 if (pixelsData_ == nullptr) {
939 HiLog::Error(LABEL, "get pixels memory fail.");
940 return ERR_IMAGE_MALLOC_ABNORMAL;
941 }
942 inputStreamPtr_->Seek(streamPosition_);
943 uint32_t ret = IncrementalReadRows(inputStreamPtr_);
944 if (ret != SUCCESS) {
945 HiLog::Error(LABEL, "normal decode the image fail, ret:%{public}u", ret);
946 return ret;
947 }
948 streamPosition_ = inputStreamPtr_->Tell();
949 return SUCCESS;
950 }
951
FinishOldDecompress()952 bool PngDecoder::FinishOldDecompress()
953 {
954 if (state_ < PngDecodingState::IMAGE_DECODING) {
955 return true;
956 }
957
958 InputDataStream *temp = inputStreamPtr_;
959 Reset();
960 inputStreamPtr_ = temp;
961 // destroy the png decode struct
962 if (pngStructPtr_ != nullptr) {
963 png_infopp pngInfoPtr = pngInfoPtr_ ? &pngInfoPtr_ : nullptr;
964 png_destroy_read_struct(&pngStructPtr_, pngInfoPtr, nullptr);
965 HiLog::Debug(LABEL, "FinishOldDecompress png_destroy_read_struct");
966 }
967 state_ = PngDecodingState::SOURCE_INITED;
968 if (InitPnglib()) {
969 return true;
970 }
971 return false;
972 }
973
InitPnglib()974 bool PngDecoder::InitPnglib()
975 {
976 // create the png decode struct
977 pngStructPtr_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, PngErrorExit, PngWarning);
978 pngInfoPtr_ = png_create_info_struct(pngStructPtr_);
979 // set the libpng exception message callback function
980 png_set_error_fn(pngStructPtr_, nullptr, PngErrorMessage, PngWarningMessage);
981 if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) {
982 HiLog::Error(LABEL, "Png lib init fail.");
983 return false;
984 }
985 return true;
986 }
987
DealNinePatch(const PixelDecodeOptions & opts)988 void PngDecoder::DealNinePatch(const PixelDecodeOptions &opts)
989 {
990 if (ninePatch_.patch_ != nullptr) {
991 if (opts.desiredSize.width > 0 && opts.desiredSize.height > 0) {
992 const float scaleX = static_cast<float>(opts.desiredSize.width) / pngImageInfo_.width;
993 const float scaleY = static_cast<float>(opts.desiredSize.height) / pngImageInfo_.height;
994 ninePatch_.Scale(scaleX, scaleY, opts.desiredSize.width, opts.desiredSize.height);
995 }
996 }
997 }
998 } // namespace ImagePlugin
999 } // namespace OHOS
1000