1 // Copyright 2014 PDFium Authors. All rights reserved.
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 <algorithm>
8
9 #include "core/include/fxcodec/fx_codec.h"
10 #include "core/include/fxge/fx_dib.h"
11 #include "codec_int.h"
12
13 extern "C" {
14 #undef FAR
15 #include "third_party/lpng_v163/png.h"
16 }
17
_png_error_data(png_structp png_ptr,png_const_charp error_msg)18 static void _png_error_data(png_structp png_ptr, png_const_charp error_msg) {
19 if (png_get_error_ptr(png_ptr)) {
20 FXSYS_strncpy((char*)png_get_error_ptr(png_ptr), error_msg,
21 PNG_ERROR_SIZE - 1);
22 }
23 longjmp(png_jmpbuf(png_ptr), 1);
24 }
_png_warning_data(png_structp png_ptr,png_const_charp error_msg)25 static void _png_warning_data(png_structp png_ptr, png_const_charp error_msg) {}
_png_load_bmp_attribute(png_structp png_ptr,png_infop info_ptr,CFX_DIBAttribute * pAttribute)26 static void _png_load_bmp_attribute(png_structp png_ptr,
27 png_infop info_ptr,
28 CFX_DIBAttribute* pAttribute) {
29 if (pAttribute) {
30 #if defined(PNG_pHYs_SUPPORTED)
31 pAttribute->m_nXDPI = png_get_x_pixels_per_meter(png_ptr, info_ptr);
32 pAttribute->m_nYDPI = png_get_y_pixels_per_meter(png_ptr, info_ptr);
33 png_uint_32 res_x, res_y;
34 int unit_type;
35 png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type);
36 switch (unit_type) {
37 case PNG_RESOLUTION_METER:
38 pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_METER;
39 break;
40 default:
41 pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_NONE;
42 }
43 #endif
44 #if defined(PNG_iCCP_SUPPORTED)
45 png_charp icc_name;
46 png_bytep icc_profile;
47 png_uint_32 icc_proflen;
48 int compress_type;
49 png_get_iCCP(png_ptr, info_ptr, &icc_name, &compress_type, &icc_profile,
50 &icc_proflen);
51 #endif
52 int bTime = 0;
53 #if defined(PNG_tIME_SUPPORTED)
54 png_timep t = NULL;
55 png_get_tIME(png_ptr, info_ptr, &t);
56 if (t) {
57 FXSYS_memset(pAttribute->m_strTime, 0, sizeof(pAttribute->m_strTime));
58 FXSYS_snprintf((FX_CHAR*)pAttribute->m_strTime,
59 sizeof(pAttribute->m_strTime), "%4d:%2d:%2d %2d:%2d:%2d",
60 t->year, t->month, t->day, t->hour, t->minute, t->second);
61 pAttribute->m_strTime[sizeof(pAttribute->m_strTime) - 1] = 0;
62 bTime = 1;
63 }
64 #endif
65 #if defined(PNG_TEXT_SUPPORTED)
66 int i;
67 FX_STRSIZE len;
68 const FX_CHAR* buf;
69 int num_text;
70 png_textp text = NULL;
71 png_get_text(png_ptr, info_ptr, &text, &num_text);
72 for (i = 0; i < num_text; i++) {
73 len = FXSYS_strlen(text[i].key);
74 buf = "Time";
75 if (!FXSYS_memcmp(buf, text[i].key, std::min(len, FXSYS_strlen(buf)))) {
76 if (!bTime) {
77 FXSYS_memset(pAttribute->m_strTime, 0, sizeof(pAttribute->m_strTime));
78 FXSYS_memcpy(
79 pAttribute->m_strTime, text[i].text,
80 std::min(sizeof(pAttribute->m_strTime) - 1, text[i].text_length));
81 }
82 } else {
83 buf = "Author";
84 if (!FXSYS_memcmp(buf, text[i].key, std::min(len, FXSYS_strlen(buf)))) {
85 pAttribute->m_strAuthor.Empty();
86 pAttribute->m_strAuthor.Load((uint8_t*)text[i].text,
87 (FX_STRSIZE)text[i].text_length);
88 }
89 }
90 }
91 #endif
92 }
93 }
94 struct FXPNG_Context {
95 png_structp png_ptr;
96 png_infop info_ptr;
97 void* parent_ptr;
98 void* child_ptr;
99
100 void* (*m_AllocFunc)(unsigned int);
101 void (*m_FreeFunc)(void*);
102 };
103 extern "C" {
_png_alloc_func(unsigned int size)104 static void* _png_alloc_func(unsigned int size) {
105 return FX_Alloc(char, size);
106 }
_png_free_func(void * p)107 static void _png_free_func(void* p) {
108 if (p != NULL) {
109 FX_Free(p);
110 }
111 }
112 };
_png_get_header_func(png_structp png_ptr,png_infop info_ptr)113 static void _png_get_header_func(png_structp png_ptr, png_infop info_ptr) {
114 FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr);
115 if (p == NULL) {
116 return;
117 }
118 CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;
119 if (pModule == NULL) {
120 return;
121 }
122 png_uint_32 width = 0, height = 0;
123 int bpc = 0, color_type = 0, color_type1 = 0, pass = 0;
124 double gamma = 1.0;
125 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bpc, &color_type, NULL,
126 NULL, NULL);
127 color_type1 = color_type;
128 if (bpc > 8) {
129 png_set_strip_16(png_ptr);
130 } else if (bpc < 8) {
131 png_set_expand_gray_1_2_4_to_8(png_ptr);
132 }
133 bpc = 8;
134 if (color_type == PNG_COLOR_TYPE_PALETTE) {
135 png_set_palette_to_rgb(png_ptr);
136 }
137 pass = png_set_interlace_handling(png_ptr);
138 if (!pModule->ReadHeaderCallback(p->child_ptr, width, height, bpc, pass,
139 &color_type, &gamma)) {
140 png_error(p->png_ptr, "Read Header Callback Error");
141 }
142 int intent;
143 if (png_get_sRGB(png_ptr, info_ptr, &intent)) {
144 png_set_gamma(png_ptr, gamma, 0.45455);
145 } else {
146 double image_gamma;
147 if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) {
148 png_set_gamma(png_ptr, gamma, image_gamma);
149 } else {
150 png_set_gamma(png_ptr, gamma, 0.45455);
151 }
152 }
153 switch (color_type) {
154 case PNG_COLOR_TYPE_GRAY:
155 case PNG_COLOR_TYPE_GRAY_ALPHA: {
156 if (color_type1 & PNG_COLOR_MASK_COLOR) {
157 png_set_rgb_to_gray(png_ptr, 1, 0.299, 0.587);
158 }
159 } break;
160 case PNG_COLOR_TYPE_PALETTE:
161 if (color_type1 != PNG_COLOR_TYPE_PALETTE) {
162 png_error(p->png_ptr, "Not Support Output Palette Now");
163 }
164 case PNG_COLOR_TYPE_RGB:
165 case PNG_COLOR_TYPE_RGB_ALPHA:
166 if (!(color_type1 & PNG_COLOR_MASK_COLOR)) {
167 png_set_gray_to_rgb(png_ptr);
168 }
169 png_set_bgr(png_ptr);
170 break;
171 }
172 if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
173 png_set_strip_alpha(png_ptr);
174 }
175 if (color_type & PNG_COLOR_MASK_ALPHA &&
176 !(color_type1 & PNG_COLOR_MASK_ALPHA)) {
177 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
178 }
179 png_read_update_info(png_ptr, info_ptr);
180 }
_png_get_end_func(png_structp png_ptr,png_infop info_ptr)181 static void _png_get_end_func(png_structp png_ptr, png_infop info_ptr) {}
_png_get_row_func(png_structp png_ptr,png_bytep new_row,png_uint_32 row_num,int pass)182 static void _png_get_row_func(png_structp png_ptr,
183 png_bytep new_row,
184 png_uint_32 row_num,
185 int pass) {
186 FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr);
187 if (p == NULL) {
188 return;
189 }
190 CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;
191 uint8_t* src_buf = NULL;
192 if (!pModule->AskScanlineBufCallback(p->child_ptr, row_num, src_buf)) {
193 png_error(png_ptr, "Ask Scanline buffer Callback Error");
194 }
195 if (src_buf != NULL) {
196 png_progressive_combine_row(png_ptr, src_buf, new_row);
197 }
198 pModule->FillScanlineBufCompletedCallback(p->child_ptr, pass, row_num);
199 }
Start(void * pModule)200 void* CCodec_PngModule::Start(void* pModule) {
201 FXPNG_Context* p = (FXPNG_Context*)FX_Alloc(uint8_t, sizeof(FXPNG_Context));
202 if (p == NULL) {
203 return NULL;
204 }
205 p->m_AllocFunc = _png_alloc_func;
206 p->m_FreeFunc = _png_free_func;
207 p->png_ptr = NULL;
208 p->info_ptr = NULL;
209 p->parent_ptr = (void*)this;
210 p->child_ptr = pModule;
211 p->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
212 if (p->png_ptr == NULL) {
213 FX_Free(p);
214 return NULL;
215 }
216 p->info_ptr = png_create_info_struct(p->png_ptr);
217 if (p->info_ptr == NULL) {
218 png_destroy_read_struct(&(p->png_ptr), (png_infopp)NULL, (png_infopp)NULL);
219 FX_Free(p);
220 return NULL;
221 }
222 if (setjmp(png_jmpbuf(p->png_ptr))) {
223 if (p != NULL) {
224 png_destroy_read_struct(&(p->png_ptr), &(p->info_ptr), (png_infopp)NULL);
225 FX_Free(p);
226 }
227 return NULL;
228 }
229 png_set_progressive_read_fn(p->png_ptr, p, _png_get_header_func,
230 _png_get_row_func, _png_get_end_func);
231 png_set_error_fn(p->png_ptr, m_szLastError, (png_error_ptr)_png_error_data,
232 (png_error_ptr)_png_warning_data);
233 return p;
234 }
Finish(void * pContext)235 void CCodec_PngModule::Finish(void* pContext) {
236 FXPNG_Context* p = (FXPNG_Context*)pContext;
237 if (p != NULL) {
238 png_destroy_read_struct(&(p->png_ptr), &(p->info_ptr), (png_infopp)NULL);
239 p->m_FreeFunc(p);
240 }
241 }
Input(void * pContext,const uint8_t * src_buf,FX_DWORD src_size,CFX_DIBAttribute * pAttribute)242 FX_BOOL CCodec_PngModule::Input(void* pContext,
243 const uint8_t* src_buf,
244 FX_DWORD src_size,
245 CFX_DIBAttribute* pAttribute) {
246 FXPNG_Context* p = (FXPNG_Context*)pContext;
247 if (setjmp(png_jmpbuf(p->png_ptr))) {
248 if (pAttribute &&
249 0 == FXSYS_strcmp(m_szLastError, "Read Header Callback Error")) {
250 _png_load_bmp_attribute(p->png_ptr, p->info_ptr, pAttribute);
251 }
252 return FALSE;
253 }
254 png_process_data(p->png_ptr, p->info_ptr, (uint8_t*)src_buf, src_size);
255 return TRUE;
256 }
257