Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
png_decoder.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "core/fxcodec/png/png_decoder.h"
8
9#include <setjmp.h>
10#include <string.h>
11
12#include "core/fxcodec/cfx_codec_memory.h"
13#include "core/fxcodec/fx_codec.h"
14#include "core/fxcodec/fx_codec_def.h"
15#include "core/fxcrt/unowned_ptr.h"
16
17#ifdef USE_SYSTEM_LIBPNG
18#include <png.h>
19#else
20#include "third_party/libpng/png.h"
21#endif
22
23#define PNG_ERROR_SIZE 256
24
25class CPngContext final : public ProgressiveDecoderIface::Context {
26 public:
27 explicit CPngContext(PngDecoder::Delegate* pDelegate);
28 ~CPngContext() override;
29
31 png_infop m_pInfo = nullptr;
32 UnownedPtr<PngDecoder::Delegate> const m_pDelegate;
34};
35
36extern "C" {
37
38void _png_error_data(png_structp png_ptr, png_const_charp error_msg) {
39 if (png_get_error_ptr(png_ptr)) {
40 strncpy(static_cast<char*>(png_get_error_ptr(png_ptr)), error_msg,
41 PNG_ERROR_SIZE - 1);
42 }
43
44 longjmp(png_jmpbuf(png_ptr), 1);
45}
46
47void _png_warning_data(png_structp png_ptr, png_const_charp error_msg) {}
48
49void _png_load_bmp_attribute(png_structp png_ptr,
50 png_infop info_ptr,
51 CFX_DIBAttribute* pAttribute) {
52 if (pAttribute) {
53#if defined(PNG_pHYs_SUPPORTED)
54 pAttribute->m_nXDPI = png_get_x_pixels_per_meter(png_ptr, info_ptr);
55 pAttribute->m_nYDPI = png_get_y_pixels_per_meter(png_ptr, info_ptr);
56 png_uint_32 res_x, res_y;
57 int unit_type;
58 png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type);
59 switch (unit_type) {
60 case PNG_RESOLUTION_METER:
61 pAttribute->m_wDPIUnit = CFX_DIBAttribute::kResUnitMeter;
62 break;
63 default:
64 pAttribute->m_wDPIUnit = CFX_DIBAttribute::kResUnitNone;
65 }
66#endif
67#if defined(PNG_iCCP_SUPPORTED)
68 png_charp icc_name;
69 png_bytep icc_profile;
70 png_uint_32 icc_proflen;
71 int compress_type;
72 png_get_iCCP(png_ptr, info_ptr, &icc_name, &compress_type, &icc_profile,
73 &icc_proflen);
74#endif
75#if defined(PNG_TEXT_SUPPORTED)
76 int num_text;
77 png_textp text = nullptr;
78 png_get_text(png_ptr, info_ptr, &text, &num_text);
79#endif
80 }
81}
82
83void _png_get_header_func(png_structp png_ptr, png_infop info_ptr) {
84 auto* pContext =
85 reinterpret_cast<CPngContext*>(png_get_progressive_ptr(png_ptr));
86 if (!pContext)
87 return;
88
89 png_uint_32 width = 0;
90 png_uint_32 height = 0;
91 int bpc = 0;
92 int color_type = 0;
93 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bpc, &color_type, nullptr,
94 nullptr, nullptr);
95 int color_type1 = color_type;
96 if (bpc > 8)
97 png_set_strip_16(png_ptr);
98 else if (bpc < 8)
99 png_set_expand_gray_1_2_4_to_8(png_ptr);
100
101 bpc = 8;
102 if (color_type == PNG_COLOR_TYPE_PALETTE)
103 png_set_palette_to_rgb(png_ptr);
104
105 int pass = png_set_interlace_handling(png_ptr);
106 double gamma = 1.0;
107 if (!pContext->m_pDelegate->PngReadHeader(width, height, bpc, pass,
108 &color_type, &gamma)) {
109 png_error(pContext->m_pPng, "Read Header Callback Error");
110 }
111 int intent;
112 if (png_get_sRGB(png_ptr, info_ptr, &intent)) {
113 png_set_gamma(png_ptr, gamma, 0.45455);
114 } else {
115 double image_gamma;
116 if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
117 png_set_gamma(png_ptr, gamma, image_gamma);
118 else
119 png_set_gamma(png_ptr, gamma, 0.45455);
120 }
121 switch (color_type) {
122 case PNG_COLOR_TYPE_GRAY:
123 case PNG_COLOR_TYPE_GRAY_ALPHA: {
124 if (color_type1 & PNG_COLOR_MASK_COLOR) {
125 png_set_rgb_to_gray(png_ptr, 1, 0.299, 0.587);
126 }
127 } break;
128 case PNG_COLOR_TYPE_PALETTE:
129 if (color_type1 != PNG_COLOR_TYPE_PALETTE) {
130 png_error(pContext->m_pPng, "Not Support Output Palette Now");
131 }
132 [[fallthrough]];
133 case PNG_COLOR_TYPE_RGB:
134 case PNG_COLOR_TYPE_RGB_ALPHA:
135 if (!(color_type1 & PNG_COLOR_MASK_COLOR)) {
136 png_set_gray_to_rgb(png_ptr);
137 }
138 png_set_bgr(png_ptr);
139 break;
140 }
141 if (!(color_type & PNG_COLOR_MASK_ALPHA))
142 png_set_strip_alpha(png_ptr);
143
144 if (color_type & PNG_COLOR_MASK_ALPHA &&
145 !(color_type1 & PNG_COLOR_MASK_ALPHA)) {
146 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
147 }
148 png_read_update_info(png_ptr, info_ptr);
149}
150
151void _png_get_end_func(png_structp png_ptr, png_infop info_ptr) {}
152
153void _png_get_row_func(png_structp png_ptr,
154 png_bytep new_row,
155 png_uint_32 row_num,
156 int pass) {
157 auto* pContext =
158 reinterpret_cast<CPngContext*>(png_get_progressive_ptr(png_ptr));
159 if (!pContext)
160 return;
161
162 uint8_t* src_buf;
163 if (!pContext->m_pDelegate->PngAskScanlineBuf(row_num, &src_buf))
164 png_error(png_ptr, "Ask Scanline buffer Callback Error");
165
166 if (src_buf)
167 png_progressive_combine_row(png_ptr, src_buf, new_row);
168
169 pContext->m_pDelegate->PngFillScanlineBufCompleted(pass, row_num);
170}
171
172} // extern "C"
173
174CPngContext::CPngContext(PngDecoder::Delegate* pDelegate)
176
177CPngContext::~CPngContext() {
178 png_destroy_read_struct(m_pPng ? &m_pPng : nullptr,
179 m_pInfo ? &m_pInfo : nullptr, nullptr);
180}
181
182namespace fxcodec {
183
184// static
185std::unique_ptr<ProgressiveDecoderIface::Context> PngDecoder::StartDecode(
186 Delegate* pDelegate) {
187 auto p = std::make_unique<CPngContext>(pDelegate);
188 p->m_pPng =
189 png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
190 if (!p->m_pPng)
191 return nullptr;
192
193 p->m_pInfo = png_create_info_struct(p->m_pPng);
194 if (!p->m_pInfo)
195 return nullptr;
196
197 if (setjmp(png_jmpbuf(p->m_pPng)))
198 return nullptr;
199
200 png_set_progressive_read_fn(p->m_pPng, p.get(), _png_get_header_func,
201 _png_get_row_func, _png_get_end_func);
202 png_set_error_fn(p->m_pPng, p->m_szLastError, _png_error_data,
203 _png_warning_data);
204 return p;
205}
206
207// static
209 RetainPtr<CFX_CodecMemory> codec_memory,
210 CFX_DIBAttribute* pAttribute) {
211 auto* ctx = static_cast<CPngContext*>(pContext);
212 if (setjmp(png_jmpbuf(ctx->m_pPng))) {
213 if (pAttribute &&
214 strcmp(ctx->m_szLastError, "Read Header Callback Error") == 0) {
215 _png_load_bmp_attribute(ctx->m_pPng, ctx->m_pInfo, pAttribute);
216 }
217 return false;
218 }
219 pdfium::span<uint8_t> src_buf = codec_memory->GetUnconsumedSpan();
220 png_process_data(ctx->m_pPng, ctx->m_pInfo, src_buf.data(), src_buf.size());
221 return true;
222}
223
224} // namespace fxcodec
CPngContext(PngDecoder::Delegate *pDelegate)
~CPngContext() override
char m_szLastError[PNG_ERROR_SIZE]
png_infop m_pInfo
png_structp m_pPng
UnownedPtr< PngDecoder::Delegate > const m_pDelegate
static bool ContinueDecode(ProgressiveDecoderIface::Context *pContext, RetainPtr< CFX_CodecMemory > codec_memory, CFX_DIBAttribute *pAttribute)
void _png_get_header_func(png_structp png_ptr, png_infop info_ptr)
void _png_warning_data(png_structp png_ptr, png_const_charp error_msg)
void _png_error_data(png_structp png_ptr, png_const_charp error_msg)
void _png_load_bmp_attribute(png_structp png_ptr, png_infop info_ptr, CFX_DIBAttribute *pAttribute)
void _png_get_row_func(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass)
#define PNG_ERROR_SIZE
void _png_get_end_func(png_structp png_ptr, png_infop info_ptr)