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