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