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