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