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