blob: d3e24cd9ea4ae3a69235e8965fb2f0442f29a3f0 [file] [log] [blame]
Lei Zhang94293682016-01-27 18:27:56 -08001// 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
Tom Sepez73c9f3b2017-02-27 10:12:59 -08007#include "core/fxcodec/codec/ccodec_pngmodule.h"
8
Lei Zhang94293682016-01-27 18:27:56 -08009#include <algorithm>
10
Dan Sinclair764ec512016-03-14 13:35:12 -040011#include "core/fxcodec/codec/codec_int.h"
dsinclair8a4e2862016-09-29 13:43:30 -070012#include "core/fxcodec/fx_codec.h"
dsinclair74a34fc2016-09-29 16:41:42 -070013#include "core/fxge/fx_dib.h"
Lei Zhang94293682016-01-27 18:27:56 -080014
15extern "C" {
16#undef FAR
17#include "third_party/libpng16/png.h"
18}
19
20static 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}
27static void _png_warning_data(png_structp png_ptr, png_const_charp error_msg) {}
28static 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)
thestig4997b222016-06-07 10:46:22 -070056 png_timep t = nullptr;
Lei Zhang94293682016-01-27 18:27:56 -080057 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,
weili12367cb2016-06-03 11:22:16 -070061 sizeof(pAttribute->m_strTime), "%4u:%2u:%2u %2u:%2u:%2u",
Lei Zhang94293682016-01-27 18:27:56 -080062 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;
thestig4997b222016-06-07 10:46:22 -070072 png_textp text = nullptr;
Lei Zhang94293682016-01-27 18:27:56 -080073 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)))) {
tsepezf1722902016-04-08 12:13:50 -070087 pAttribute->m_strAuthor =
88 CFX_ByteString(reinterpret_cast<uint8_t*>(text[i].text),
89 static_cast<FX_STRSIZE>(text[i].text_length));
Lei Zhang94293682016-01-27 18:27:56 -080090 }
91 }
92 }
93#endif
94 }
95}
96struct FXPNG_Context {
97 png_structp png_ptr;
98 png_infop info_ptr;
99 void* parent_ptr;
100 void* child_ptr;
101
102 void* (*m_AllocFunc)(unsigned int);
103 void (*m_FreeFunc)(void*);
104};
105extern "C" {
106static void* _png_alloc_func(unsigned int size) {
107 return FX_Alloc(char, size);
108}
109static void _png_free_func(void* p) {
Lei Zhang5eca3052016-02-22 20:32:21 -0800110 FX_Free(p);
Lei Zhang94293682016-01-27 18:27:56 -0800111}
112};
113static 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);
thestig4997b222016-06-07 10:46:22 -0700115 if (!p)
Lei Zhang94293682016-01-27 18:27:56 -0800116 return;
thestig4997b222016-06-07 10:46:22 -0700117
Lei Zhang94293682016-01-27 18:27:56 -0800118 CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;
thestig4997b222016-06-07 10:46:22 -0700119 if (!pModule)
Lei Zhang94293682016-01-27 18:27:56 -0800120 return;
thestig4997b222016-06-07 10:46:22 -0700121
Lei Zhang94293682016-01-27 18:27:56 -0800122 png_uint_32 width = 0, height = 0;
123 int bpc = 0, color_type = 0, color_type1 = 0, pass = 0;
124 double gamma = 1.0;
thestig4997b222016-06-07 10:46:22 -0700125 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bpc, &color_type, nullptr,
126 nullptr, nullptr);
Lei Zhang94293682016-01-27 18:27:56 -0800127 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}
181static void _png_get_end_func(png_structp png_ptr, png_infop info_ptr) {}
182static 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);
thestig4997b222016-06-07 10:46:22 -0700187 if (!p)
Lei Zhang94293682016-01-27 18:27:56 -0800188 return;
thestig4997b222016-06-07 10:46:22 -0700189
Lei Zhang94293682016-01-27 18:27:56 -0800190 CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;
thestig4997b222016-06-07 10:46:22 -0700191 uint8_t* src_buf = nullptr;
Lei Zhang94293682016-01-27 18:27:56 -0800192 if (!pModule->AskScanlineBufCallback(p->child_ptr, row_num, src_buf)) {
193 png_error(png_ptr, "Ask Scanline buffer Callback Error");
194 }
Lei Zhang5eca3052016-02-22 20:32:21 -0800195 if (src_buf) {
Lei Zhang94293682016-01-27 18:27:56 -0800196 png_progressive_combine_row(png_ptr, src_buf, new_row);
197 }
198 pModule->FillScanlineBufCompletedCallback(p->child_ptr, pass, row_num);
199}
dsinclaird55e11e2016-04-12 11:21:22 -0700200
201FXPNG_Context* CCodec_PngModule::Start(void* pModule) {
tsepezdd1bfe42017-01-16 06:07:54 -0800202 FXPNG_Context* p = FX_Alloc(FXPNG_Context, 1);
dsinclaird55e11e2016-04-12 11:21:22 -0700203 if (!p)
204 return nullptr;
205
Lei Zhang94293682016-01-27 18:27:56 -0800206 p->m_AllocFunc = _png_alloc_func;
207 p->m_FreeFunc = _png_free_func;
dsinclaird55e11e2016-04-12 11:21:22 -0700208 p->png_ptr = nullptr;
209 p->info_ptr = nullptr;
Lei Zhang94293682016-01-27 18:27:56 -0800210 p->parent_ptr = (void*)this;
211 p->child_ptr = pModule;
dsinclaird55e11e2016-04-12 11:21:22 -0700212 p->png_ptr =
213 png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
214 if (!p->png_ptr) {
Lei Zhang94293682016-01-27 18:27:56 -0800215 FX_Free(p);
dsinclaird55e11e2016-04-12 11:21:22 -0700216 return nullptr;
Lei Zhang94293682016-01-27 18:27:56 -0800217 }
218 p->info_ptr = png_create_info_struct(p->png_ptr);
dsinclaird55e11e2016-04-12 11:21:22 -0700219 if (!p->info_ptr) {
220 png_destroy_read_struct(&(p->png_ptr), nullptr, nullptr);
Lei Zhang94293682016-01-27 18:27:56 -0800221 FX_Free(p);
dsinclaird55e11e2016-04-12 11:21:22 -0700222 return nullptr;
Lei Zhang94293682016-01-27 18:27:56 -0800223 }
224 if (setjmp(png_jmpbuf(p->png_ptr))) {
Lei Zhang5eca3052016-02-22 20:32:21 -0800225 if (p) {
dsinclaird55e11e2016-04-12 11:21:22 -0700226 png_destroy_read_struct(&(p->png_ptr), &(p->info_ptr), nullptr);
Lei Zhang94293682016-01-27 18:27:56 -0800227 FX_Free(p);
228 }
dsinclaird55e11e2016-04-12 11:21:22 -0700229 return nullptr;
Lei Zhang94293682016-01-27 18:27:56 -0800230 }
231 png_set_progressive_read_fn(p->png_ptr, p, _png_get_header_func,
232 _png_get_row_func, _png_get_end_func);
233 png_set_error_fn(p->png_ptr, m_szLastError, (png_error_ptr)_png_error_data,
234 (png_error_ptr)_png_warning_data);
235 return p;
236}
dsinclaird55e11e2016-04-12 11:21:22 -0700237
238void CCodec_PngModule::Finish(FXPNG_Context* ctx) {
239 if (ctx) {
240 png_destroy_read_struct(&(ctx->png_ptr), &(ctx->info_ptr), nullptr);
241 ctx->m_FreeFunc(ctx);
Lei Zhang94293682016-01-27 18:27:56 -0800242 }
243}
dsinclaird55e11e2016-04-12 11:21:22 -0700244
tsepez12f3e4a2016-11-02 15:17:29 -0700245bool CCodec_PngModule::Input(FXPNG_Context* ctx,
246 const uint8_t* src_buf,
247 uint32_t src_size,
248 CFX_DIBAttribute* pAttribute) {
dsinclaird55e11e2016-04-12 11:21:22 -0700249 if (setjmp(png_jmpbuf(ctx->png_ptr))) {
Lei Zhang94293682016-01-27 18:27:56 -0800250 if (pAttribute &&
251 0 == FXSYS_strcmp(m_szLastError, "Read Header Callback Error")) {
dsinclaird55e11e2016-04-12 11:21:22 -0700252 _png_load_bmp_attribute(ctx->png_ptr, ctx->info_ptr, pAttribute);
Lei Zhang94293682016-01-27 18:27:56 -0800253 }
tsepez12f3e4a2016-11-02 15:17:29 -0700254 return false;
Lei Zhang94293682016-01-27 18:27:56 -0800255 }
dsinclaird55e11e2016-04-12 11:21:22 -0700256 png_process_data(ctx->png_ptr, ctx->info_ptr, (uint8_t*)src_buf, src_size);
tsepez12f3e4a2016-11-02 15:17:29 -0700257 return true;
Lei Zhang94293682016-01-27 18:27:56 -0800258}