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