Merge to XFA: Use stdint.h types throughout PDFium.
[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, sizeof(pAttribute->m_strTime));\r
73                     FXSYS_memcpy32(pAttribute->m_strTime, text[i].text,\r
74                                    FX_MIN(sizeof(pAttribute->m_strTime) - 1, text[i].text_length));\r
75                 }\r
76             } else {\r
77                 buf = "Author";\r
78                 if (!FXSYS_memcmp32(buf, text[i].key, FX_MIN(len, FXSYS_strlen(buf)))) {\r
79                     pAttribute->m_strAuthor.Empty();\r
80                     pAttribute->m_strAuthor.Load((FX_LPBYTE)text[i].text, (FX_STRSIZE)text[i].text_length);\r
81                 }\r
82             }\r
83         }\r
84 #endif\r
85     }\r
86 }\r
87 struct FXPNG_Context {\r
88     png_structp png_ptr;\r
89     png_infop   info_ptr;\r
90     void*               parent_ptr;\r
91     void*               child_ptr;\r
92 \r
93     void*               (*m_AllocFunc)(unsigned int);\r
94     void                (*m_FreeFunc)(void*);\r
95 };\r
96 extern "C" {\r
97     static void* _png_alloc_func(unsigned int size)\r
98     {\r
99         return FX_Alloc(char, size);\r
100     }\r
101     static void  _png_free_func(void* p)\r
102     {\r
103         if(p != NULL) {\r
104             FX_Free(p);\r
105         }\r
106     }\r
107 };\r
108 static void _png_get_header_func(png_structp png_ptr, png_infop info_ptr)\r
109 {\r
110     FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr);\r
111     if(p == NULL) {\r
112         return;\r
113     }\r
114     CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;\r
115     if(pModule == NULL) {\r
116         return;\r
117     }\r
118     png_uint_32 width = 0, height = 0;\r
119     int bpc = 0, color_type = 0 , color_type1 = 0, pass = 0;\r
120     double gamma = 1.0;\r
121     png_get_IHDR(png_ptr, info_ptr, &width, &height, &bpc, &color_type, NULL, NULL, NULL);\r
122     color_type1 = color_type;\r
123     if(bpc > 8) {\r
124         png_set_strip_16(png_ptr);\r
125     } else if(bpc < 8) {\r
126         png_set_expand_gray_1_2_4_to_8(png_ptr);\r
127     }\r
128     bpc = 8;\r
129     if(color_type == PNG_COLOR_TYPE_PALETTE) {\r
130         png_set_palette_to_rgb(png_ptr);\r
131     }\r
132     pass = png_set_interlace_handling(png_ptr);\r
133     if(!pModule->ReadHeaderCallback(p->child_ptr, width, height, bpc, pass, &color_type, &gamma)) {\r
134         png_error(p->png_ptr, "Read Header Callback Error");\r
135     }\r
136     int intent;\r
137     if (png_get_sRGB(png_ptr, info_ptr, &intent)) {\r
138         png_set_gamma(png_ptr, gamma, 0.45455);\r
139     } else {\r
140         double image_gamma;\r
141         if(png_get_gAMA(png_ptr, info_ptr, &image_gamma)) {\r
142             png_set_gamma(png_ptr, gamma, image_gamma);\r
143         } else {\r
144             png_set_gamma(png_ptr, gamma, 0.45455);\r
145         }\r
146     }\r
147     switch(color_type) {\r
148         case PNG_COLOR_TYPE_GRAY:\r
149         case PNG_COLOR_TYPE_GRAY_ALPHA: {\r
150                 if(color_type1 & PNG_COLOR_MASK_COLOR) {\r
151                     png_set_rgb_to_gray(png_ptr, 1, 0.299, 0.587);\r
152                 }\r
153             }\r
154             break;\r
155         case PNG_COLOR_TYPE_PALETTE:\r
156             if(color_type1 != PNG_COLOR_TYPE_PALETTE) {\r
157                 png_error(p->png_ptr, "Not Support Output Palette Now");\r
158             }\r
159         case PNG_COLOR_TYPE_RGB:\r
160         case PNG_COLOR_TYPE_RGB_ALPHA:\r
161             if(!(color_type1 & PNG_COLOR_MASK_COLOR)) {\r
162                 png_set_gray_to_rgb(png_ptr);\r
163             }\r
164             png_set_bgr(png_ptr);\r
165             break;\r
166     }\r
167     if(!(color_type & PNG_COLOR_MASK_ALPHA)) {\r
168         png_set_strip_alpha(png_ptr);\r
169     }\r
170     if(color_type & PNG_COLOR_MASK_ALPHA && !(color_type1 & PNG_COLOR_MASK_ALPHA)) {\r
171         png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);\r
172     }\r
173     png_read_update_info(png_ptr, info_ptr);\r
174 }\r
175 static void _png_get_end_func(png_structp png_ptr, png_infop info_ptr) {}\r
176 static void _png_get_row_func(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass)\r
177 {\r
178     FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr);\r
179     if(p == NULL) {\r
180         return;\r
181     }\r
182     CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;\r
183     FX_LPBYTE src_buf = NULL;\r
184     if(!pModule->AskScanlineBufCallback(p->child_ptr, row_num, src_buf)) {\r
185         png_error(png_ptr, "Ask Scanline buffer Callback Error");\r
186     }\r
187     if(src_buf != NULL) {\r
188         png_progressive_combine_row(png_ptr, src_buf, new_row);\r
189     }\r
190     pModule->FillScanlineBufCompletedCallback(p->child_ptr, pass, row_num);\r
191 }\r
192 void* CCodec_PngModule::Start(void* pModule)\r
193 {\r
194     FXPNG_Context* p = (FXPNG_Context*)FX_Alloc(uint8_t, sizeof(FXPNG_Context));\r
195     if(p == NULL) {\r
196         return NULL;\r
197     }\r
198     p->m_AllocFunc = _png_alloc_func;\r
199     p->m_FreeFunc = _png_free_func;\r
200     p->png_ptr = NULL;\r
201     p->info_ptr = NULL;\r
202     p->parent_ptr = (void*)this;\r
203     p->child_ptr = pModule;\r
204     p->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);\r
205     if (p->png_ptr == NULL) {\r
206         FX_Free(p);\r
207         return NULL;\r
208     }\r
209     p->info_ptr = png_create_info_struct(p->png_ptr);\r
210     if (p->info_ptr == NULL) {\r
211         png_destroy_read_struct(&(p->png_ptr), (png_infopp)NULL, (png_infopp)NULL);\r
212         FX_Free(p);\r
213         return NULL;\r
214     }\r
215     if (setjmp(png_jmpbuf(p->png_ptr))) {\r
216         if(p != NULL) {\r
217             png_destroy_read_struct(&(p->png_ptr), &(p->info_ptr), (png_infopp)NULL);\r
218             FX_Free(p);\r
219         }\r
220         return NULL;\r
221     }\r
222     png_set_progressive_read_fn(p->png_ptr, p,\r
223                                 _png_get_header_func,\r
224                                 _png_get_row_func,\r
225                                 _png_get_end_func);\r
226     png_set_error_fn(p->png_ptr, m_szLastError, (png_error_ptr)_png_error_data, (png_error_ptr)_png_warning_data);\r
227     return p;\r
228 }\r
229 void CCodec_PngModule::Finish(void* pContext)\r
230 {\r
231     FXPNG_Context* p = (FXPNG_Context*)pContext;\r
232     if(p != NULL) {\r
233         png_destroy_read_struct(&(p->png_ptr), &(p->info_ptr), (png_infopp)NULL);\r
234         p->m_FreeFunc(p);\r
235     }\r
236 }\r
237 FX_BOOL CCodec_PngModule::Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_DIBAttribute* pAttribute)\r
238 {\r
239     FXPNG_Context* p = (FXPNG_Context*)pContext;\r
240     if(setjmp(png_jmpbuf(p->png_ptr))) {\r
241         if (pAttribute && 0 == FXSYS_strcmp(m_szLastError, "Read Header Callback Error")) {\r
242             _png_load_bmp_attribute(p->png_ptr, p->info_ptr, pAttribute);\r
243         }\r
244         return FALSE;\r
245     }\r
246     png_process_data(p->png_ptr, p->info_ptr, (FX_LPBYTE)src_buf, src_size);\r
247     return TRUE;\r
248 }\r