• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             errno_t backRet = memset_s(outputBuffer, 0, byteCount);
245             if (backRet != EOK) {
246                 HiLog::Error(LABEL, "init output buffer fail.", backRet);
247                 free(outputBuffer);
248                 outputBuffer = nullptr;
249                 return nullptr;
250             }
251 #else
252             if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
253                 HiLog::Error(LABEL, "init output buffer fail.");
254                 free(outputBuffer);
255                 outputBuffer = nullptr;
256                 return nullptr;
257             }
258 #endif
259             context.pixelsBuffer.buffer = outputBuffer;
260             context.pixelsBuffer.bufferSize = byteCount;
261             context.pixelsBuffer.context = nullptr;
262             context.allocatorType = AllocatorType::HEAP_ALLOC;
263             context.freeFunc = nullptr;
264         }
265     }
266     return static_cast<uint8_t *>(context.pixelsBuffer.buffer);
267 }
268 
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)269 uint32_t PngDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
270 {
271     // PNG format only supports one picture decoding, index in order to Compatible animation scene.
272     context.totalProcessProgress = 0;
273     if (index >= PNG_IMAGE_NUM) {
274         HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}u.", index, PNG_IMAGE_NUM);
275         return ERR_IMAGE_INVALID_PARAMETER;
276     }
277     if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) {
278         HiLog::Error(LABEL, "Png init failed can't begin to decode.");
279         return ERR_IMAGE_INIT_ABNORMAL;
280     }
281     if (state_ != PngDecodingState::IMAGE_DECODING) {
282         HiLog::Error(LABEL, "incremental decode failed for state %{public}d.", state_);
283         return ERR_MEDIA_INVALID_OPERATION;
284     }
285 
286     pixelsData_ = AllocOutputHeapBuffer(context.decodeContext);
287     if (pixelsData_ == nullptr) {
288         HiLog::Error(LABEL, "get pixels memory fail.");
289         return ERR_IMAGE_MALLOC_ABNORMAL;
290     }
291     inputStreamPtr_->Seek(streamPosition_);
292     uint32_t ret = IncrementalReadRows(inputStreamPtr_);
293     streamPosition_ = inputStreamPtr_->Tell();
294     if (ret != SUCCESS) {
295         if (ret != ERR_IMAGE_SOURCE_DATA_INCOMPLETE) {
296             HiLog::Error(LABEL, "Incremental decode fail, ret:%{public}u", ret);
297         }
298     } else {
299         if (outputRowsNum_ != pngImageInfo_.height) {
300             HiLog::Debug(LABEL, "Incremental decode incomplete, outputRowsNum:%{public}u, height:%{public}u",
301                          outputRowsNum_, pngImageInfo_.height);
302         }
303         state_ = PngDecodingState::IMAGE_DECODED;
304     }
305     // get promote decode progress, in percentage: 0~100.
306     // DecodeHeader() has judged that pngImageInfo_.height should not be equal to 0 and returns a failure result,
307     // so here pngImageInfo_.height will not be equal to 0 in the PngDecodingState::IMAGE_DECODING state.
308     context.totalProcessProgress =
309         outputRowsNum_ == 0 ? 0 : outputRowsNum_ * ProgDecodeContext::FULL_PROGRESS / pngImageInfo_.height;
310     HiLog::Debug(LABEL, "Incremental decode progress %{public}u.", context.totalProcessProgress);
311     return ret;
312 }
313 
Reset()314 void PngDecoder::Reset()
315 {
316     inputStreamPtr_ = nullptr;
317     decodedIdat_ = false;
318     idatLength_ = 0;
319     incrementalLength_ = 0;
320     pixelsData_ = nullptr;
321     outputRowsNum_ = 0;
322     decodeHeadFlag_ = false;
323     firstRow_ = 0;
324     lastRow_ = 0;
325     interlacedComplete_ = false;
326 }
327 
328 // private interface
ConvertOriginalFormat(png_byte source,png_byte & destination)329 bool PngDecoder::ConvertOriginalFormat(png_byte source, png_byte &destination)
330 {
331     if (png_get_valid(pngStructPtr_, pngInfoPtr_, PNG_INFO_tRNS)) {
332         png_set_tRNS_to_alpha(pngStructPtr_);
333     }
334     HiLog::Info(LABEL, "color type:[%{public}d]", source);
335     switch (source) {
336         case PNG_COLOR_TYPE_PALETTE: {  // value is 3
337             png_set_palette_to_rgb(pngStructPtr_);
338             destination = PNG_COLOR_TYPE_RGB;
339             break;
340         }
341         case PNG_COLOR_TYPE_GRAY: {            // value is 0
342             if (pngImageInfo_.bitDepth < 8) {  // 8 is single pixel bit depth
343                 png_set_expand_gray_1_2_4_to_8(pngStructPtr_);
344             }
345             png_set_gray_to_rgb(pngStructPtr_);
346             destination = PNG_COLOR_TYPE_RGB;
347             break;
348         }
349         case PNG_COLOR_TYPE_GRAY_ALPHA: {  // value is 4
350             png_set_gray_to_rgb(pngStructPtr_);
351             destination = PNG_COLOR_TYPE_RGB;
352             break;
353         }
354         case PNG_COLOR_TYPE_RGB:
355         case PNG_COLOR_TYPE_RGB_ALPHA: {  // value is 6
356             destination = source;
357             break;
358         }
359         default: {
360             HiLog::Error(LABEL, "the color type:[%{public}d] libpng unsupported!", source);
361             return false;
362         }
363     }
364 
365     return true;
366 }
367 
GetDecodeFormat(PlPixelFormat format,PlPixelFormat & outputFormat,PlAlphaType & alphaType)368 uint32_t PngDecoder::GetDecodeFormat(PlPixelFormat format, PlPixelFormat &outputFormat, PlAlphaType &alphaType)
369 {
370     png_byte sourceType = png_get_color_type(pngStructPtr_, pngInfoPtr_);
371     if ((sourceType & PNG_COLOR_MASK_ALPHA) || png_get_valid(pngStructPtr_, pngInfoPtr_, PNG_INFO_tRNS)) {
372         alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
373     } else {
374         alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
375     }
376     png_byte destType = 0;
377     if (!ConvertOriginalFormat(sourceType, destType)) {
378         return ERR_IMAGE_DATA_UNSUPPORT;
379     }
380     if (format != PlPixelFormat::RGB_888 && destType == PNG_COLOR_TYPE_RGB) {
381         png_set_add_alpha(pngStructPtr_, 0xff, PNG_FILLER_AFTER);  // 0xffff add the A after RGB.
382     }
383     // only support 8 bit depth for each pixel except for RGBA_F16
384     if (format != PlPixelFormat::RGBA_F16 && pngImageInfo_.bitDepth == 16) {  // 16bit depth
385         pngImageInfo_.bitDepth = 8;  // 8bit depth
386         png_set_strip_16(pngStructPtr_);
387     }
388     ChooseFormat(format, outputFormat, destType);
389     return SUCCESS;
390 }
391 
ChooseFormat(PlPixelFormat format,PlPixelFormat & outputFormat,png_byte destType)392 void PngDecoder::ChooseFormat(PlPixelFormat format, PlPixelFormat &outputFormat,
393                               png_byte destType)
394 {
395     outputFormat = format;
396     switch (format) {
397         case PlPixelFormat::BGRA_8888: {
398             pngImageInfo_.rowDataSize = pngImageInfo_.width * 4;  // 4 is BGRA size
399             png_set_bgr(pngStructPtr_);
400             break;
401         }
402         case PlPixelFormat::ARGB_8888: {
403             png_set_swap_alpha(pngStructPtr_);
404             pngImageInfo_.rowDataSize = pngImageInfo_.width * 4;  // 4 is ARGB size
405             break;
406         }
407         case PlPixelFormat::RGB_888: {
408             if (destType == PNG_COLOR_TYPE_RGBA) {
409                 png_set_strip_alpha(pngStructPtr_);
410             }
411             pngImageInfo_.rowDataSize = pngImageInfo_.width * 3;  // 3 is RGB size
412             break;
413         }
414         case PlPixelFormat::RGBA_F16: {
415             png_set_scale_16(pngStructPtr_);
416             pngImageInfo_.rowDataSize = pngImageInfo_.width * 7;  // 7 is RRGGBBA size
417             break;
418         }
419         case PlPixelFormat::UNKNOWN:
420         case PlPixelFormat::RGBA_8888:
421         default: {
422             pngImageInfo_.rowDataSize = pngImageInfo_.width * 4;  // 4 is RGBA size
423             outputFormat = PlPixelFormat::RGBA_8888;
424             break;
425         }
426     }
427 }
428 
PngErrorExit(png_structp pngPtr,png_const_charp message)429 void PngDecoder::PngErrorExit(png_structp pngPtr, png_const_charp message)
430 {
431     if ((pngPtr == nullptr) || (message == nullptr)) {
432         HiLog::Error(LABEL, "ErrorExit png_structp or error message is null.");
433         return;
434     }
435     jmp_buf *jmpBuf = &(png_jmpbuf(pngPtr));
436     if (jmpBuf == nullptr) {
437         HiLog::Error(LABEL, "jmpBuf exception.");
438         return;
439     }
440     longjmp(*jmpBuf, SET_JUMP_VALUE);
441 }
442 
PngWarning(png_structp pngPtr,png_const_charp message)443 void PngDecoder::PngWarning(png_structp pngPtr, png_const_charp message)
444 {
445     if (message == nullptr) {
446         HiLog::Error(LABEL, "WarningExit message is null.");
447         return;
448     }
449     HiLog::Warn(LABEL, "png warn %{public}s", message);
450 }
451 
PngErrorMessage(png_structp pngPtr,png_const_charp message)452 void PngDecoder::PngErrorMessage(png_structp pngPtr, png_const_charp message)
453 {
454     if (message == nullptr) {
455         HiLog::Error(LABEL, "PngErrorMessage message is null.");
456         return;
457     }
458     HiLog::Error(LABEL, "PngErrorMessage, message:%{public}s.", message);
459 }
460 
PngWarningMessage(png_structp pngPtr,png_const_charp message)461 void PngDecoder::PngWarningMessage(png_structp pngPtr, png_const_charp message)
462 {
463     if (message == nullptr) {
464         HiLog::Error(LABEL, "PngWarningMessage message is null.");
465         return;
466     }
467     HiLog::Error(LABEL, "PngWarningMessage, message:%{public}s.", message);
468 }
469 
470 // image incremental decode Interface
ProcessData(png_structp pngStructPtr,png_infop infoStructPtr,InputDataStream * sourceStream,DataStreamBuffer streamData,size_t bufferSize,size_t totalSize)471 uint32_t PngDecoder::ProcessData(png_structp pngStructPtr, png_infop infoStructPtr, InputDataStream *sourceStream,
472                                  DataStreamBuffer streamData, size_t bufferSize, size_t totalSize)
473 {
474     if ((pngStructPtr == nullptr) || (infoStructPtr == nullptr) || (sourceStream == nullptr) || (totalSize == 0) ||
475         (bufferSize == 0)) {
476         HiLog::Error(LABEL, "ProcessData input error, totalSize:%{public}zu, bufferSize:%{public}zu.", totalSize,
477                      bufferSize);
478         return ERR_IMAGE_INVALID_PARAMETER;
479     }
480     while (totalSize > 0) {
481         size_t readSize = (bufferSize < totalSize) ? bufferSize : totalSize;
482         uint32_t ret = IncrementalRead(sourceStream, readSize, streamData);
483         if (ret != SUCCESS) {
484             HiLog::Error(LABEL, "ProcessData Read from source stream fail, readSize:%{public}zu, \
485                         bufferSize:%{public}zu, dataSize:%{public}u, totalSize:%{public}zu.",
486                          readSize, bufferSize, streamData.dataSize, totalSize);
487             return ret;
488         }
489         png_process_data(pngStructPtr, infoStructPtr, const_cast<png_bytep>(streamData.inputStreamBuffer),
490                          streamData.dataSize);
491         totalSize -= streamData.dataSize;
492     }
493     return SUCCESS;
494 }
495 
IsChunk(const png_byte * chunk,const char * flag)496 bool PngDecoder::IsChunk(const png_byte *chunk, const char *flag)
497 {
498     if (chunk == nullptr || flag == nullptr) {
499         HiLog::Error(LABEL, "IsChunk input parameter exception.");
500         return false;
501     }
502     return memcmp(chunk + CHUNK_DATA_LEN, flag, CHUNK_DATA_LEN) == 0;
503 }
504 
GetImageInfo(PngImageInfo & info)505 bool PngDecoder::GetImageInfo(PngImageInfo &info)
506 {
507     png_uint_32 origWidth = 0;
508     png_uint_32 origHeight = 0;
509     int32_t bitDepth = 0;
510     png_get_IHDR(pngStructPtr_, pngInfoPtr_, &origWidth, &origHeight, &bitDepth, nullptr, nullptr, nullptr, nullptr);
511     if ((origWidth == 0) || (origHeight == 0) || (origWidth > PNG_UINT_31_MAX) || (origHeight > PNG_UINT_31_MAX)) {
512         HiLog::Error(LABEL, "Get the png image size abnormal, width:%{public}u, height:%{public}u", origWidth,
513                      origHeight);
514         return false;
515     }
516     if (bitDepth != BITDEPTH_VALUE_1 && bitDepth != BITDEPTH_VALUE_2 && bitDepth != BITDEPTH_VALUE_4 &&
517         bitDepth != BITDEPTH_VALUE_8 && bitDepth != BITDEPTH_VALUE_16) {
518         HiLog::Error(LABEL, "Get the png image bit depth abnormal, bitDepth:%{public}d.", bitDepth);
519         return false;
520     }
521     size_t rowDataSize = png_get_rowbytes(pngStructPtr_, pngInfoPtr_);
522     if (rowDataSize == 0) {
523         HiLog::Error(LABEL, "Get the bitmap row bytes size fail.");
524         return false;
525     }
526     info.numberPasses = png_set_interlace_handling(pngStructPtr_);
527     info.width = origWidth;
528     info.height = origHeight;
529     info.bitDepth = bitDepth;
530     info.rowDataSize = rowDataSize;
531     HiLog::Info(LABEL, "GetImageInfo:width:%{public}u,height:%{public}u,bitDepth:%{public}u,numberPasses:%{public}d.",
532         origWidth, origHeight, info.bitDepth, info.numberPasses);
533     return true;
534 }
535 
IncrementalRead(InputDataStream * stream,uint32_t desiredSize,DataStreamBuffer & outData)536 uint32_t PngDecoder::IncrementalRead(InputDataStream *stream, uint32_t desiredSize, DataStreamBuffer &outData)
537 {
538     if (stream == nullptr) {
539         return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
540     }
541 
542     uint32_t curPos = stream->Tell();
543     if (!stream->Read(desiredSize, outData)) {
544         HiLog::Debug(LABEL, "read data fail.");
545         return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
546     }
547     if (outData.inputStreamBuffer == nullptr || outData.dataSize == 0) {
548         HiLog::Error(LABEL, "inputStreamBuffer is null or data size is %{public}u.", outData.dataSize);
549         return ERR_IMAGE_GET_DATA_ABNORMAL;
550     }
551     if (outData.dataSize < desiredSize) {
552         stream->Seek(curPos);
553         HiLog::Debug(LABEL, "read outdata size[%{public}u] < data size[%{public}u] and curpos:%{public}u",
554                      outData.dataSize, desiredSize, curPos);
555         return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
556     }
557     return SUCCESS;
558 }
559 
GetImageIdatSize(InputDataStream * stream)560 uint32_t PngDecoder::GetImageIdatSize(InputDataStream *stream)
561 {
562     uint32_t ret = 0;
563     DataStreamBuffer readData;
564     while (true) {
565         uint32_t preReadPos = stream->Tell();
566         ret = IncrementalRead(stream, static_cast<uint32_t>(CHUNK_SIZE), readData);
567         if (ret != SUCCESS) {
568             break;
569         }
570         png_byte *chunk = const_cast<png_byte *>(readData.inputStreamBuffer);
571         const size_t length = png_get_uint_32(chunk);
572         if (IsChunk(chunk, "IDAT")) {
573             HiLog::Debug(LABEL, "first idat Length is %{public}zu.", length);
574             idatLength_ = length;
575             return SUCCESS;
576         }
577         uint32_t afterReadPos = stream->Tell();
578         if (!stream->Seek(length + afterReadPos + CHUNK_DATA_LEN)) {
579             HiLog::Debug(LABEL, "stream current pos is %{public}u, chunk size is %{public}zu.", preReadPos, length);
580             stream->Seek(preReadPos);
581             return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
582         }
583         stream->Seek(afterReadPos);
584         png_process_data(pngStructPtr_, pngInfoPtr_, chunk, CHUNK_SIZE);
585         ret = ProcessData(pngStructPtr_, pngInfoPtr_, stream, readData, DECODE_BUFFER_SIZE, length + CHUNK_DATA_LEN);
586         if (ret != SUCCESS) {
587             break;
588         }
589     }
590     return ret;
591 }
592 
ReadIncrementalHead(InputDataStream * stream,PngImageInfo & info)593 uint32_t PngDecoder::ReadIncrementalHead(InputDataStream *stream, PngImageInfo &info)
594 {
595     if (stream == nullptr) {
596         HiLog::Error(LABEL, "read incremental head input data is null!");
597         return ERR_IMAGE_INVALID_PARAMETER;
598     }
599     uint32_t pos = stream->Tell();
600     if (!stream->Seek(PNG_HEAD_SIZE)) {
601         HiLog::Debug(LABEL, "don't enough the data to decode the image head.");
602         return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
603     }
604     stream->Seek(pos);
605     // set the exception handle
606     jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_));
607     if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) {
608         HiLog::Error(LABEL, "read incremental head PNG decode head exception.");
609         return ERR_IMAGE_DECODE_HEAD_ABNORMAL;
610     }
611 
612     DataStreamBuffer readData;
613     if (!decodeHeadFlag_) {
614         png_set_keep_unknown_chunks(pngStructPtr_, PNG_HANDLE_CHUNK_ALWAYS, (png_byte *)"", 0);
615         png_set_read_user_chunk_fn(pngStructPtr_, static_cast<png_voidp>(&ninePatch_), ReadUserChunk);
616         png_set_progressive_read_fn(pngStructPtr_, nullptr, nullptr, nullptr, nullptr);
617         uint32_t ret = IncrementalRead(stream, static_cast<uint32_t>(CHUNK_SIZE), readData);
618         if (ret != SUCCESS) {
619             return ret;
620         }
621         png_bytep head = const_cast<png_bytep>(readData.inputStreamBuffer);
622         png_process_data(pngStructPtr_, pngInfoPtr_, head, CHUNK_SIZE);
623         decodeHeadFlag_ = true;
624     }
625     uint32_t ret = GetImageIdatSize(stream);
626     if (ret != SUCCESS) {
627         HiLog::Error(LABEL, "get image idat size fail, ret:%{public}u.", ret);
628         return ret;
629     }
630     if (!GetImageInfo(info)) {
631         return ERR_IMAGE_DECODE_HEAD_ABNORMAL;
632     }
633     return SUCCESS;
634 }
635 
SaveRows(png_bytep row,png_uint_32 rowNum)636 void PngDecoder::SaveRows(png_bytep row, png_uint_32 rowNum)
637 {
638     if (rowNum != outputRowsNum_ || pngImageInfo_.height < rowNum) {
639         HiLog::Error(LABEL,
640                      "AllRowsCallback exception, rowNum:%{public}u, outputRowsNum:%{public}u, height:%{public}u.",
641                      rowNum, outputRowsNum_, pngImageInfo_.height);
642         return;
643     }
644     outputRowsNum_++;
645     uint8_t *offset = pixelsData_ + rowNum * pngImageInfo_.rowDataSize;
646     uint32_t offsetSize = (pngImageInfo_.height - rowNum) * pngImageInfo_.rowDataSize;
647     errno_t ret = memcpy_s(offset, offsetSize, row, pngImageInfo_.rowDataSize);
648     if (ret != 0) {
649         HiLog::Error(LABEL, "copy data fail, ret:%{public}d, rowDataSize:%{public}u, offsetSize:%{public}u.", ret,
650                      pngImageInfo_.rowDataSize, offsetSize);
651         return;
652     }
653 }
654 
SaveInterlacedRows(png_bytep row,png_uint_32 rowNum,int pass)655 void PngDecoder::SaveInterlacedRows(png_bytep row, png_uint_32 rowNum, int pass)
656 {
657     if (row == nullptr) {
658         HiLog::Error(LABEL, "input row is null.");
659         return;
660     }
661     if (rowNum < firstRow_ || rowNum > lastRow_ || interlacedComplete_) {
662         HiLog::Error(LABEL, "ignore this row, rowNum:%{public}u,InterlacedComplete:%{public}u.", rowNum,
663                      interlacedComplete_);
664         return;
665     }
666     png_bytep oldRow = pixelsData_ + (rowNum - firstRow_) * pngImageInfo_.rowDataSize;
667     uint64_t mollocByteCount = static_cast<uint64_t>(pngImageInfo_.rowDataSize) * pngImageInfo_.height;
668     uint64_t needByteCount = static_cast<uint64_t>(pngStructPtr_->width) * sizeof(*oldRow);
669     if (mollocByteCount < needByteCount) {
670         HiLog::Error(LABEL, "malloc byte size is(%{public}llu), but actual needs (%{public}llu)",
671                      static_cast<unsigned long long>(mollocByteCount), static_cast<unsigned long long>(needByteCount));
672         return;
673     }
674     png_progressive_combine_row(pngStructPtr_, oldRow, row);
675     if (pass == 0) {
676         // The first pass initializes all rows.
677         if (outputRowsNum_ == rowNum - firstRow_) {
678             HiLog::Error(LABEL, "rowNum(%{public}u) - firstRow(%{public}u) = outputRow(%{public}u)", rowNum, firstRow_,
679                          outputRowsNum_);
680             return;
681         }
682         outputRowsNum_++;
683     } else {
684         if (outputRowsNum_ == lastRow_ - firstRow_ + 1) {
685             HiLog::Error(LABEL, "lastRow_(%{public}u) + firstRow(%{public}u) + 1 = outputRow(%{public}u)", lastRow_,
686                          firstRow_, outputRowsNum_);
687             return;
688         }
689         if (pngImageInfo_.numberPasses - 1 == pass && rowNum == lastRow_) {
690             // Last pass, and we have read all of the rows we care about.
691             HiLog::Error(LABEL, "last pass:%{public}d, numberPasses:%{public}d, rowNum:%{public}d, lastRow:%{public}d.",
692                          pass, pngImageInfo_.numberPasses, rowNum, lastRow_);
693             interlacedComplete_ = true;
694         }
695     }
696 }
697 
GetAllRows(png_structp pngPtr,png_bytep row,png_uint_32 rowNum,int pass)698 void PngDecoder::GetAllRows(png_structp pngPtr, png_bytep row, png_uint_32 rowNum, int pass)
699 {
700     if (pngPtr == nullptr || row == nullptr) {
701         HiLog::Error(LABEL, "get decode rows exception, rowNum:%{public}u.", rowNum);
702         return;
703     }
704     PngDecoder *decoder = static_cast<PngDecoder *>(png_get_progressive_ptr(pngPtr));
705     if (decoder == nullptr) {
706         HiLog::Error(LABEL, "get all rows fail, get decoder is null.");
707         return;
708     }
709     decoder->SaveRows(row, rowNum);
710 }
711 
GetInterlacedRows(png_structp pngPtr,png_bytep row,png_uint_32 rowNum,int pass)712 void PngDecoder::GetInterlacedRows(png_structp pngPtr, png_bytep row, png_uint_32 rowNum, int pass)
713 {
714     if (pngPtr == nullptr || row == nullptr) {
715         HiLog::Debug(LABEL, "get decode rows exception, rowNum:%{public}u.", rowNum);
716         return;
717     }
718     PngDecoder *decoder = static_cast<PngDecoder *>(png_get_progressive_ptr(pngPtr));
719     if (decoder == nullptr) {
720         HiLog::Error(LABEL, "get all rows fail, get decoder is null.");
721         return;
722     }
723     decoder->SaveInterlacedRows(row, rowNum, pass);
724 }
725 
ReadUserChunk(png_structp png_ptr,png_unknown_chunkp chunk)726 int32_t PngDecoder::ReadUserChunk(png_structp png_ptr, png_unknown_chunkp chunk)
727 {
728     NinePatchListener *chunkReader = static_cast<NinePatchListener *>(png_get_user_chunk_ptr(png_ptr));
729     if (chunkReader == nullptr) {
730         HiLog::Error(LABEL, "chunk header is null.");
731         return ERR_IMAGE_DECODE_ABNORMAL;
732     }
733     return chunkReader->ReadChunk(reinterpret_cast<const char *>(chunk->name), chunk->data, chunk->size)
734                ? SUCCESS
735                : ERR_IMAGE_DECODE_ABNORMAL;
736 }
737 
PushAllToDecode(InputDataStream * stream,size_t bufferSize,size_t length)738 uint32_t PngDecoder::PushAllToDecode(InputDataStream *stream, size_t bufferSize, size_t length)
739 {
740     if (stream == nullptr || bufferSize == 0 || length == 0) {
741         HiLog::Error(LABEL, "iend process input exception, bufferSize:%{public}zu, length:%{public}zu.", bufferSize,
742                      length);
743         return ERR_IMAGE_INVALID_PARAMETER;
744     }
745     DataStreamBuffer ReadData;
746     if (ProcessData(pngStructPtr_, pngInfoPtr_, stream, ReadData, bufferSize, length) != SUCCESS) {
747         HiLog::Error(LABEL, "ProcessData return false, bufferSize:%{public}zu, length:%{public}zu.", bufferSize,
748                      length);
749         return ERR_IMAGE_DECODE_ABNORMAL;
750     }
751     bool iend = false;
752     uint32_t ret = 0;
753     while (true) {
754         // Parse chunk length and type.
755         ret = IncrementalRead(stream, CHUNK_SIZE, ReadData);
756         if (ret != SUCCESS) {
757             HiLog::Error(LABEL, "set iend mode Read chunk fail,ret:%{public}u", ret);
758             break;
759         }
760         png_byte *chunk = const_cast<png_byte *>(ReadData.inputStreamBuffer);
761         png_process_data(pngStructPtr_, pngInfoPtr_, chunk, CHUNK_SIZE);
762         if (IsChunk(chunk, "IEND")) {
763             iend = true;
764         }
765         size_t chunkLength = png_get_uint_32(chunk);
766         // Process the full chunk + CRC
767         ret = ProcessData(pngStructPtr_, pngInfoPtr_, stream, ReadData, bufferSize, chunkLength + CHUNK_DATA_LEN);
768         if (ret != SUCCESS || iend) {
769             break;
770         }
771     }
772     return ret;
773 }
774 
IncrementalReadRows(InputDataStream * stream)775 uint32_t PngDecoder::IncrementalReadRows(InputDataStream *stream)
776 {
777     if (stream == nullptr) {
778         HiLog::Error(LABEL, "input data is null!");
779         return ERR_IMAGE_GET_DATA_ABNORMAL;
780     }
781     if (idatLength_ < incrementalLength_) {
782         HiLog::Error(LABEL, "incremental len:%{public}zu > idat len:%{public}zu.", incrementalLength_, idatLength_);
783         return ERR_IMAGE_INVALID_PARAMETER;
784     }
785     // set the exception handle
786     jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_));
787     if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) {
788         HiLog::Error(LABEL, "[IncrementalReadRows]PNG decode exception.");
789         return ERR_IMAGE_DECODE_ABNORMAL;
790     }
791     // set process decode state to IDAT mode.
792     if (!decodedIdat_) {
793         if (pngImageInfo_.numberPasses == 1) {
794             png_set_progressive_read_fn(pngStructPtr_, this, nullptr, GetAllRows, nullptr);
795         } else {
796             png_set_progressive_read_fn(pngStructPtr_, this, nullptr, GetInterlacedRows, nullptr);
797             lastRow_ = pngImageInfo_.height - 1;  // decode begin to 0
798         }
799         png_byte idat[] = { 0, 0, 0, 0, 'I', 'D', 'A', 'T' };
800         png_save_uint_32(idat, idatLength_);
801         png_process_data(pngStructPtr_, pngInfoPtr_, idat, CHUNK_SIZE);
802         decodedIdat_ = true;
803         idatLength_ += CHUNK_DATA_LEN;
804     }
805     if (stream->IsStreamCompleted()) {
806         uint32_t ret = PushAllToDecode(stream, DECODE_BUFFER_SIZE, idatLength_ - incrementalLength_);
807         if (ret != SUCCESS) {
808             HiLog::Error(LABEL, "iend set fail, ret:%{public}u, idatLen:%{public}zu, incrementalLen:%{public}zu.", ret,
809                          idatLength_, incrementalLength_);
810             return ret;
811         }
812         return SUCCESS;
813     }
814     uint32_t ret = PushCurrentToDecode(stream);
815     if (ret != SUCCESS) {
816         HiLog::Error(LABEL,
817                      "push stream to decode fail, ret:%{public}u, idatLen:%{public}zu, incrementalLen:%{public}zu.",
818                      ret, idatLength_, incrementalLength_);
819         return ret;
820     }
821     return SUCCESS;
822 }
823 
PushCurrentToDecode(InputDataStream * stream)824 uint32_t PngDecoder::PushCurrentToDecode(InputDataStream *stream)
825 {
826     if (stream == nullptr) {
827         HiLog::Error(LABEL, "push current stream to decode input data is null!");
828         return ERR_IMAGE_GET_DATA_ABNORMAL;
829     }
830     if (idatLength_ == 0) {
831         HiLog::Error(LABEL, "idat Length is zero.");
832         return ERR_IMAGE_DECODE_ABNORMAL;
833     }
834 
835     DataStreamBuffer ReadData;
836     uint32_t ret = 0;
837     while (incrementalLength_ < idatLength_) {
838         const size_t targetSize = std::min(DECODE_BUFFER_SIZE, idatLength_ - incrementalLength_);
839         ret = IncrementalRead(stream, targetSize, ReadData);
840         if (ret != SUCCESS) {
841             HiLog::Debug(LABEL, "push current stream read fail, ret:%{public}u", ret);
842             return ret;
843         }
844         incrementalLength_ += ReadData.dataSize;
845         png_process_data(pngStructPtr_, pngInfoPtr_, (png_bytep)ReadData.inputStreamBuffer, ReadData.dataSize);
846     }
847 
848     while (true) {
849         ret = IncrementalRead(stream, CHUNK_SIZE, ReadData);
850         if (ret != SUCCESS) {
851             HiLog::Debug(LABEL, "set iend mode Read chunk fail,ret:%{public}u", ret);
852             break;
853         }
854         png_byte *chunk = const_cast<png_byte *>(ReadData.inputStreamBuffer);
855         png_process_data(pngStructPtr_, pngInfoPtr_, chunk, CHUNK_SIZE);
856         idatLength_ = png_get_uint_32(chunk) + CHUNK_DATA_LEN;
857         incrementalLength_ = 0;
858         while (incrementalLength_ < idatLength_) {
859             const size_t targetSize = std::min(DECODE_BUFFER_SIZE, idatLength_ - incrementalLength_);
860             ret = IncrementalRead(stream, targetSize, ReadData);
861             if (ret != SUCCESS) {
862                 HiLog::Debug(LABEL, "push current stream read fail, ret:%{public}u", ret);
863                 return ret;
864             }
865             incrementalLength_ += ReadData.dataSize;
866             png_process_data(pngStructPtr_, pngInfoPtr_, (png_bytep)ReadData.inputStreamBuffer, ReadData.dataSize);
867         }
868     }
869     return ret;
870 }
871 
DecodeHeader()872 uint32_t PngDecoder::DecodeHeader()
873 {
874     // only state PngDecodingState::SOURCE_INITED and PngDecodingState::BASE_INFO_PARSING can go in this function.
875     if (inputStreamPtr_->IsStreamCompleted()) {
876         // decode the png image header
877         inputStreamPtr_->Seek(0);
878     }
879     // incremental decode the png image header
880     if (state_ == PngDecodingState::SOURCE_INITED) {
881         inputStreamPtr_->Seek(0);
882     } else {
883         inputStreamPtr_->Seek(streamPosition_);
884     }
885     uint32_t ret = ReadIncrementalHead(inputStreamPtr_, pngImageInfo_);
886     if (ret != SUCCESS) {
887         if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) {
888             streamPosition_ = inputStreamPtr_->Tell();
889             state_ = PngDecodingState::BASE_INFO_PARSING;
890         } else {
891             state_ = PngDecodingState::SOURCE_INITED;
892             HiLog::Error(LABEL, "decode image head, ret:%{public}u.", ret);
893         }
894         return ret;
895     }
896     if (pngImageInfo_.width == 0 || pngImageInfo_.height == 0) {
897         HiLog::Error(LABEL, "get width and height fail, height:%{public}u, width:%{public}u.", pngImageInfo_.height,
898                      pngImageInfo_.width);
899         state_ = PngDecodingState::SOURCE_INITED;
900         return ERR_IMAGE_GET_DATA_ABNORMAL;
901     }
902     streamPosition_ = inputStreamPtr_->Tell();
903     state_ = PngDecodingState::BASE_INFO_PARSED;
904     return SUCCESS;
905 }
906 
ConfigInfo(const PixelDecodeOptions & opts)907 uint32_t PngDecoder::ConfigInfo(const PixelDecodeOptions &opts)
908 {
909     uint32_t ret = SUCCESS;
910     bool isComeNinePatchRGB565 = false;
911     if (ninePatch_.patch_ != nullptr) {
912         // Do not allow ninepatch decodes to 565,use RGBA_8888;
913         if (opts.desiredPixelFormat == PlPixelFormat::RGB_565) {
914             ret = GetDecodeFormat(PlPixelFormat::RGBA_8888, outputFormat_, alphaType_);
915             isComeNinePatchRGB565 = true;
916         }
917     }
918     if (!isComeNinePatchRGB565) {
919         ret = GetDecodeFormat(opts.desiredPixelFormat, outputFormat_, alphaType_);
920     }
921     if (ret != SUCCESS) {
922         HiLog::Error(LABEL, "get the color type fail.");
923         return ERR_IMAGE_DATA_ABNORMAL;
924     }
925 
926     // get the libpng interface exception.
927     jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_));
928     if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) {
929         HiLog::Error(LABEL, "config decoding info fail.");
930         return ERR_IMAGE_DATA_ABNORMAL;
931     }
932     png_read_update_info(pngStructPtr_, pngInfoPtr_);
933     return SUCCESS;
934 }
935 
DoOneTimeDecode(DecodeContext & context)936 uint32_t PngDecoder::DoOneTimeDecode(DecodeContext &context)
937 {
938     if (idatLength_ <= 0) {
939         HiLog::Error(LABEL, "normal decode the image source incomplete.");
940         return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
941     }
942     jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_));
943     if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) {
944         HiLog::Error(LABEL, "decode the image fail.");
945         return ERR_IMAGE_DECODE_ABNORMAL;
946     }
947     pixelsData_ = AllocOutputHeapBuffer(context);
948     if (pixelsData_ == nullptr) {
949         HiLog::Error(LABEL, "get pixels memory fail.");
950         return ERR_IMAGE_MALLOC_ABNORMAL;
951     }
952     inputStreamPtr_->Seek(streamPosition_);
953     uint32_t ret = IncrementalReadRows(inputStreamPtr_);
954     if (ret != SUCCESS) {
955         HiLog::Error(LABEL, "normal decode the image fail, ret:%{public}u", ret);
956         return ret;
957     }
958     streamPosition_ = inputStreamPtr_->Tell();
959     return SUCCESS;
960 }
961 
FinishOldDecompress()962 bool PngDecoder::FinishOldDecompress()
963 {
964     if (state_ < PngDecodingState::IMAGE_DECODING) {
965         return true;
966     }
967 
968     InputDataStream *temp = inputStreamPtr_;
969     Reset();
970     inputStreamPtr_ = temp;
971     // destroy the png decode struct
972     if (pngStructPtr_ != nullptr) {
973         png_infopp pngInfoPtr = pngInfoPtr_ ? &pngInfoPtr_ : nullptr;
974         png_destroy_read_struct(&pngStructPtr_, pngInfoPtr, nullptr);
975         HiLog::Debug(LABEL, "FinishOldDecompress png_destroy_read_struct");
976     }
977     state_ = PngDecodingState::SOURCE_INITED;
978     if (InitPnglib()) {
979         return true;
980     }
981     return false;
982 }
983 
InitPnglib()984 bool PngDecoder::InitPnglib()
985 {
986     // create the png decode struct
987     pngStructPtr_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, PngErrorExit, PngWarning);
988     pngInfoPtr_ = png_create_info_struct(pngStructPtr_);
989     // set the libpng exception message callback function
990     png_set_error_fn(pngStructPtr_, nullptr, PngErrorMessage, PngWarningMessage);
991     if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) {
992         HiLog::Error(LABEL, "Png lib init fail.");
993         return false;
994     }
995     return true;
996 }
997 
DealNinePatch(const PixelDecodeOptions & opts)998 void PngDecoder::DealNinePatch(const PixelDecodeOptions &opts)
999 {
1000     if (ninePatch_.patch_ != nullptr) {
1001         if (opts.desiredSize.width > 0 && opts.desiredSize.height > 0) {
1002             const float scaleX = static_cast<float>(opts.desiredSize.width) / pngImageInfo_.width;
1003             const float scaleY = static_cast<float>(opts.desiredSize.height) / pngImageInfo_.height;
1004             ninePatch_.Scale(scaleX, scaleY, opts.desiredSize.width, opts.desiredSize.height);
1005         }
1006     }
1007 }
1008 } // namespace ImagePlugin
1009 } // namespace OHOS
1010