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 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) 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} 96struct 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}; 104extern "C" { 105static void* _png_alloc_func(unsigned int size) { 106 return FX_Alloc(char, size); 107} 108static void _png_free_func(void* p) { 109 FX_Free(p); 110} 111}; 112static 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} 180static void _png_get_end_func(png_structp png_ptr, png_infop info_ptr) {} 181static 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 200CCodec_PngModule::CCodec_PngModule() { 201 memset(m_szLastError, 0, sizeof(m_szLastError)); 202} 203 204CCodec_PngModule::~CCodec_PngModule() {} 205 206FXPNG_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 242void 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 249bool 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