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