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