| OLD | NEW |
| 1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| 6 | 6 |
| 7 #include <setjmp.h> | 7 #include <setjmp.h> |
| 8 | 8 |
| 9 #include "codec_int.h" | 9 #include "codec_int.h" |
| 10 #include "core/include/fxcodec/fx_codec.h" | 10 #include "core/include/fxcodec/fx_codec.h" |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 }; | 67 }; |
| 68 extern "C" { | 68 extern "C" { |
| 69 static void _error_do_nothing(j_common_ptr cinfo) {} | 69 static void _error_do_nothing(j_common_ptr cinfo) {} |
| 70 }; | 70 }; |
| 71 extern "C" { | 71 extern "C" { |
| 72 static void _error_do_nothing1(j_common_ptr cinfo, int) {} | 72 static void _error_do_nothing1(j_common_ptr cinfo, int) {} |
| 73 }; | 73 }; |
| 74 extern "C" { | 74 extern "C" { |
| 75 static void _error_do_nothing2(j_common_ptr cinfo, char*) {} | 75 static void _error_do_nothing2(j_common_ptr cinfo, char*) {} |
| 76 }; | 76 }; |
| 77 #define JPEG_MARKER_EXIF (JPEG_APP0 + 1) |
| 78 #define JPEG_MARKER_ICC (JPEG_APP0 + 2) |
| 79 #define JPEG_MARKER_AUTHORTIME (JPEG_APP0 + 3) |
| 80 #define JPEG_MARKER_MAXSIZE 0xFFFF |
| 81 #define JPEG_OVERHEAD_LEN 14 |
| 82 static FX_BOOL _JpegEmbedIccProfile(j_compress_ptr cinfo, |
| 83 const uint8_t* icc_buf_ptr, |
| 84 FX_DWORD icc_length) { |
| 85 if (!icc_buf_ptr || icc_length == 0) { |
| 86 return FALSE; |
| 87 } |
| 88 FX_DWORD icc_segment_size = (JPEG_MARKER_MAXSIZE - 2 - JPEG_OVERHEAD_LEN); |
| 89 FX_DWORD icc_segment_num = (icc_length / icc_segment_size) + 1; |
| 90 if (icc_segment_num > 255) { |
| 91 return FALSE; |
| 92 } |
| 93 FX_DWORD icc_data_length = |
| 94 JPEG_OVERHEAD_LEN + (icc_segment_num > 1 ? icc_segment_size : icc_length); |
| 95 uint8_t* icc_data = FX_Alloc(uint8_t, icc_data_length); |
| 96 FXSYS_memcpy(icc_data, "\x49\x43\x43\x5f\x50\x52\x4f\x46\x49\x4c\x45\x00", |
| 97 12); |
| 98 icc_data[13] = (uint8_t)icc_segment_num; |
| 99 for (uint8_t i = 0; i < (icc_segment_num - 1); i++) { |
| 100 icc_data[12] = i + 1; |
| 101 FXSYS_memcpy(icc_data + JPEG_OVERHEAD_LEN, |
| 102 icc_buf_ptr + i * icc_segment_size, icc_segment_size); |
| 103 jpeg_write_marker(cinfo, JPEG_MARKER_ICC, icc_data, icc_data_length); |
| 104 } |
| 105 icc_data[12] = (uint8_t)icc_segment_num; |
| 106 FX_DWORD icc_size = (icc_segment_num - 1) * icc_segment_size; |
| 107 FXSYS_memcpy(icc_data + JPEG_OVERHEAD_LEN, icc_buf_ptr + icc_size, |
| 108 icc_length - icc_size); |
| 109 jpeg_write_marker(cinfo, JPEG_MARKER_ICC, icc_data, |
| 110 JPEG_OVERHEAD_LEN + icc_length - icc_size); |
| 111 FX_Free(icc_data); |
| 112 return TRUE; |
| 113 } |
| 114 extern "C" { |
| 115 static void _dest_do_nothing(j_compress_ptr cinfo) {} |
| 116 }; |
| 117 extern "C" { |
| 118 static boolean _dest_empty(j_compress_ptr cinfo) { |
| 119 return FALSE; |
| 120 } |
| 121 }; |
| 122 #define JPEG_BLOCK_SIZE 1048576 |
| 123 static void _JpegEncode(const CFX_DIBSource* pSource, |
| 124 uint8_t*& dest_buf, |
| 125 FX_STRSIZE& dest_size, |
| 126 int quality, |
| 127 const uint8_t* icc_buf, |
| 128 FX_DWORD icc_length) { |
| 129 struct jpeg_error_mgr jerr; |
| 130 jerr.error_exit = _error_do_nothing; |
| 131 jerr.emit_message = _error_do_nothing1; |
| 132 jerr.output_message = _error_do_nothing; |
| 133 jerr.format_message = _error_do_nothing2; |
| 134 jerr.reset_error_mgr = _error_do_nothing; |
| 77 | 135 |
| 78 #define JPEG_MARKER_ICC (JPEG_APP0 + 2) | 136 struct jpeg_compress_struct cinfo; |
| 79 #define JPEG_MARKER_MAXSIZE 0xFFFF | 137 memset(&cinfo, 0, sizeof(cinfo)); |
| 80 | 138 cinfo.err = &jerr; |
| 81 static bool JpegLoadInfo(const uint8_t* src_buf, | 139 jpeg_create_compress(&cinfo); |
| 82 FX_DWORD src_size, | 140 int Bpp = pSource->GetBPP() / 8; |
| 83 int* width, | 141 FX_DWORD nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1; |
| 84 int* height, | 142 FX_DWORD pitch = pSource->GetPitch(); |
| 85 int* num_components, | 143 FX_DWORD width = pdfium::base::checked_cast<FX_DWORD>(pSource->GetWidth()); |
| 86 int* bits_per_components, | 144 FX_DWORD height = pdfium::base::checked_cast<FX_DWORD>(pSource->GetHeight()); |
| 87 bool* color_transform) { | 145 FX_SAFE_DWORD safe_buf_len = width; |
| 146 safe_buf_len *= height; |
| 147 safe_buf_len *= nComponents; |
| 148 safe_buf_len += 1024; |
| 149 if (icc_length) { |
| 150 safe_buf_len += 255 * 18; |
| 151 safe_buf_len += icc_length; |
| 152 } |
| 153 FX_DWORD dest_buf_length = 0; |
| 154 if (!safe_buf_len.IsValid()) { |
| 155 dest_buf = nullptr; |
| 156 } else { |
| 157 dest_buf_length = safe_buf_len.ValueOrDie(); |
| 158 dest_buf = FX_TryAlloc(uint8_t, dest_buf_length); |
| 159 const int MIN_TRY_BUF_LEN = 1024; |
| 160 while (!dest_buf && dest_buf_length > MIN_TRY_BUF_LEN) { |
| 161 dest_buf_length >>= 1; |
| 162 dest_buf = FX_TryAlloc(uint8_t, dest_buf_length); |
| 163 } |
| 164 } |
| 165 if (!dest_buf) { |
| 166 FX_OutOfMemoryTerminate(); |
| 167 } |
| 168 struct jpeg_destination_mgr dest; |
| 169 dest.init_destination = _dest_do_nothing; |
| 170 dest.term_destination = _dest_do_nothing; |
| 171 dest.empty_output_buffer = _dest_empty; |
| 172 dest.next_output_byte = dest_buf; |
| 173 dest.free_in_buffer = dest_buf_length; |
| 174 cinfo.dest = &dest; |
| 175 cinfo.image_width = width; |
| 176 cinfo.image_height = height; |
| 177 cinfo.input_components = nComponents; |
| 178 if (nComponents == 1) { |
| 179 cinfo.in_color_space = JCS_GRAYSCALE; |
| 180 } else if (nComponents == 3) { |
| 181 cinfo.in_color_space = JCS_RGB; |
| 182 } else { |
| 183 cinfo.in_color_space = JCS_CMYK; |
| 184 } |
| 185 uint8_t* line_buf = NULL; |
| 186 if (nComponents > 1) { |
| 187 line_buf = FX_Alloc2D(uint8_t, width, nComponents); |
| 188 } |
| 189 jpeg_set_defaults(&cinfo); |
| 190 if (quality != 75) { |
| 191 jpeg_set_quality(&cinfo, quality, TRUE); |
| 192 } |
| 193 jpeg_start_compress(&cinfo, TRUE); |
| 194 _JpegEmbedIccProfile(&cinfo, icc_buf, icc_length); |
| 195 JSAMPROW row_pointer[1]; |
| 196 JDIMENSION row; |
| 197 while (cinfo.next_scanline < cinfo.image_height) { |
| 198 const uint8_t* src_scan = pSource->GetScanline(cinfo.next_scanline); |
| 199 if (nComponents > 1) { |
| 200 uint8_t* dest_scan = line_buf; |
| 201 if (nComponents == 3) { |
| 202 for (FX_DWORD i = 0; i < width; i++) { |
| 203 dest_scan[0] = src_scan[2]; |
| 204 dest_scan[1] = src_scan[1]; |
| 205 dest_scan[2] = src_scan[0]; |
| 206 dest_scan += 3; |
| 207 src_scan += Bpp; |
| 208 } |
| 209 } else { |
| 210 for (FX_DWORD i = 0; i < pitch; i++) { |
| 211 *dest_scan++ = ~*src_scan++; |
| 212 } |
| 213 } |
| 214 row_pointer[0] = line_buf; |
| 215 } else { |
| 216 row_pointer[0] = (uint8_t*)src_scan; |
| 217 } |
| 218 row = cinfo.next_scanline; |
| 219 jpeg_write_scanlines(&cinfo, row_pointer, 1); |
| 220 if (cinfo.next_scanline == row) { |
| 221 dest_buf = |
| 222 FX_Realloc(uint8_t, dest_buf, dest_buf_length + JPEG_BLOCK_SIZE); |
| 223 dest.next_output_byte = dest_buf + dest_buf_length - dest.free_in_buffer; |
| 224 dest_buf_length += JPEG_BLOCK_SIZE; |
| 225 dest.free_in_buffer += JPEG_BLOCK_SIZE; |
| 226 } |
| 227 } |
| 228 jpeg_finish_compress(&cinfo); |
| 229 jpeg_destroy_compress(&cinfo); |
| 230 FX_Free(line_buf); |
| 231 dest_size = dest_buf_length - (FX_STRSIZE)dest.free_in_buffer; |
| 232 } |
| 233 static FX_BOOL _JpegLoadInfo(const uint8_t* src_buf, |
| 234 FX_DWORD src_size, |
| 235 int& width, |
| 236 int& height, |
| 237 int& num_components, |
| 238 int& bits_per_components, |
| 239 FX_BOOL& color_transform, |
| 240 uint8_t** icc_buf_ptr, |
| 241 FX_DWORD* icc_length) { |
| 88 _JpegScanSOI(src_buf, src_size); | 242 _JpegScanSOI(src_buf, src_size); |
| 89 struct jpeg_decompress_struct cinfo; | 243 struct jpeg_decompress_struct cinfo; |
| 90 struct jpeg_error_mgr jerr; | 244 struct jpeg_error_mgr jerr; |
| 91 jerr.error_exit = _error_fatal; | 245 jerr.error_exit = _error_fatal; |
| 92 jerr.emit_message = _error_do_nothing1; | 246 jerr.emit_message = _error_do_nothing1; |
| 93 jerr.output_message = _error_do_nothing; | 247 jerr.output_message = _error_do_nothing; |
| 94 jerr.format_message = _error_do_nothing2; | 248 jerr.format_message = _error_do_nothing2; |
| 95 jerr.reset_error_mgr = _error_do_nothing; | 249 jerr.reset_error_mgr = _error_do_nothing; |
| 96 jerr.trace_level = 0; | 250 jerr.trace_level = 0; |
| 97 cinfo.err = &jerr; | 251 cinfo.err = &jerr; |
| 98 jmp_buf mark; | 252 jmp_buf mark; |
| 99 cinfo.client_data = &mark; | 253 cinfo.client_data = &mark; |
| 100 if (setjmp(mark) == -1) { | 254 if (setjmp(mark) == -1) { |
| 101 return false; | 255 return FALSE; |
| 102 } | 256 } |
| 103 jpeg_create_decompress(&cinfo); | 257 jpeg_create_decompress(&cinfo); |
| 104 struct jpeg_source_mgr src; | 258 struct jpeg_source_mgr src; |
| 105 src.init_source = _src_do_nothing; | 259 src.init_source = _src_do_nothing; |
| 106 src.term_source = _src_do_nothing; | 260 src.term_source = _src_do_nothing; |
| 107 src.skip_input_data = _src_skip_data; | 261 src.skip_input_data = _src_skip_data; |
| 108 src.fill_input_buffer = _src_fill_buffer; | 262 src.fill_input_buffer = _src_fill_buffer; |
| 109 src.resync_to_restart = _src_resync; | 263 src.resync_to_restart = _src_resync; |
| 110 src.bytes_in_buffer = src_size; | 264 src.bytes_in_buffer = src_size; |
| 111 src.next_input_byte = src_buf; | 265 src.next_input_byte = src_buf; |
| 112 cinfo.src = &src; | 266 cinfo.src = &src; |
| 113 if (setjmp(mark) == -1) { | 267 if (setjmp(mark) == -1) { |
| 114 jpeg_destroy_decompress(&cinfo); | 268 jpeg_destroy_decompress(&cinfo); |
| 115 return false; | 269 return FALSE; |
| 270 } |
| 271 if (icc_buf_ptr && icc_length) { |
| 272 jpeg_save_markers(&cinfo, JPEG_MARKER_ICC, JPEG_MARKER_MAXSIZE); |
| 116 } | 273 } |
| 117 int ret = jpeg_read_header(&cinfo, TRUE); | 274 int ret = jpeg_read_header(&cinfo, TRUE); |
| 118 if (ret != JPEG_HEADER_OK) { | 275 if (ret != JPEG_HEADER_OK) { |
| 119 jpeg_destroy_decompress(&cinfo); | 276 jpeg_destroy_decompress(&cinfo); |
| 120 return false; | 277 return FALSE; |
| 121 } | 278 } |
| 122 *width = cinfo.image_width; | 279 width = cinfo.image_width; |
| 123 *height = cinfo.image_height; | 280 height = cinfo.image_height; |
| 124 *num_components = cinfo.num_components; | 281 num_components = cinfo.num_components; |
| 125 *color_transform = | 282 color_transform = |
| 126 cinfo.jpeg_color_space == JCS_YCbCr || cinfo.jpeg_color_space == JCS_YCCK; | 283 cinfo.jpeg_color_space == JCS_YCbCr || cinfo.jpeg_color_space == JCS_YCCK; |
| 127 *bits_per_components = cinfo.data_precision; | 284 bits_per_components = cinfo.data_precision; |
| 285 if (icc_buf_ptr) { |
| 286 *icc_buf_ptr = NULL; |
| 287 } |
| 288 if (icc_length) { |
| 289 *icc_length = 0; |
| 290 } |
| 128 jpeg_destroy_decompress(&cinfo); | 291 jpeg_destroy_decompress(&cinfo); |
| 129 return true; | 292 return TRUE; |
| 130 } | 293 } |
| 131 | 294 |
| 132 class CCodec_JpegDecoder : public CCodec_ScanlineDecoder { | 295 class CCodec_JpegDecoder : public CCodec_ScanlineDecoder { |
| 133 public: | 296 public: |
| 134 CCodec_JpegDecoder(); | 297 CCodec_JpegDecoder(); |
| 135 ~CCodec_JpegDecoder() override; | 298 ~CCodec_JpegDecoder() override; |
| 136 | 299 |
| 137 FX_BOOL Create(const uint8_t* src_buf, | 300 FX_BOOL Create(const uint8_t* src_buf, |
| 138 FX_DWORD src_size, | 301 FX_DWORD src_size, |
| 139 int width, | 302 int width, |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 return NULL; | 505 return NULL; |
| 343 } | 506 } |
| 344 CCodec_JpegDecoder* pDecoder = new CCodec_JpegDecoder; | 507 CCodec_JpegDecoder* pDecoder = new CCodec_JpegDecoder; |
| 345 if (!pDecoder->Create(src_buf, src_size, width, height, nComps, | 508 if (!pDecoder->Create(src_buf, src_size, width, height, nComps, |
| 346 ColorTransform)) { | 509 ColorTransform)) { |
| 347 delete pDecoder; | 510 delete pDecoder; |
| 348 return NULL; | 511 return NULL; |
| 349 } | 512 } |
| 350 return pDecoder; | 513 return pDecoder; |
| 351 } | 514 } |
| 352 bool CCodec_JpegModule::LoadInfo(const uint8_t* src_buf, | 515 FX_BOOL CCodec_JpegModule::LoadInfo(const uint8_t* src_buf, |
| 353 FX_DWORD src_size, | 516 FX_DWORD src_size, |
| 354 int* width, | 517 int& width, |
| 355 int* height, | 518 int& height, |
| 356 int* num_components, | 519 int& num_components, |
| 357 int* bits_per_components, | 520 int& bits_per_components, |
| 358 bool* color_transform) { | 521 FX_BOOL& color_transform, |
| 359 return JpegLoadInfo(src_buf, src_size, width, height, num_components, | 522 uint8_t** icc_buf_ptr, |
| 360 bits_per_components, color_transform); | 523 FX_DWORD* icc_length) { |
| 524 return _JpegLoadInfo(src_buf, src_size, width, height, num_components, |
| 525 bits_per_components, color_transform, icc_buf_ptr, |
| 526 icc_length); |
| 361 } | 527 } |
| 528 FX_BOOL CCodec_JpegModule::Encode(const CFX_DIBSource* pSource, |
| 529 uint8_t*& dest_buf, |
| 530 FX_STRSIZE& dest_size, |
| 531 int quality, |
| 532 const uint8_t* icc_buf, |
| 533 FX_DWORD icc_length) { |
| 534 if (pSource->GetBPP() < 8 || pSource->GetPalette()) |
| 535 return FALSE; |
| 362 | 536 |
| 537 _JpegEncode(pSource, dest_buf, dest_size, quality, icc_buf, icc_length); |
| 538 return TRUE; |
| 539 } |
| 363 struct FXJPEG_Context { | 540 struct FXJPEG_Context { |
| 364 jmp_buf m_JumpMark; | 541 jmp_buf m_JumpMark; |
| 365 jpeg_decompress_struct m_Info; | 542 jpeg_decompress_struct m_Info; |
| 366 jpeg_error_mgr m_ErrMgr; | 543 jpeg_error_mgr m_ErrMgr; |
| 367 jpeg_source_mgr m_SrcMgr; | 544 jpeg_source_mgr m_SrcMgr; |
| 368 unsigned int m_SkipSize; | 545 unsigned int m_SkipSize; |
| 369 void* (*m_AllocFunc)(unsigned int); | 546 void* (*m_AllocFunc)(unsigned int); |
| 370 void (*m_FreeFunc)(void*); | 547 void (*m_FreeFunc)(void*); |
| 371 }; | 548 }; |
| 372 extern "C" { | 549 extern "C" { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 uint8_t** avail_buf_ptr) { | 656 uint8_t** avail_buf_ptr) { |
| 480 if (avail_buf_ptr) { | 657 if (avail_buf_ptr) { |
| 481 *avail_buf_ptr = NULL; | 658 *avail_buf_ptr = NULL; |
| 482 if (((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer > 0) { | 659 if (((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer > 0) { |
| 483 *avail_buf_ptr = | 660 *avail_buf_ptr = |
| 484 (uint8_t*)((FXJPEG_Context*)pContext)->m_SrcMgr.next_input_byte; | 661 (uint8_t*)((FXJPEG_Context*)pContext)->m_SrcMgr.next_input_byte; |
| 485 } | 662 } |
| 486 } | 663 } |
| 487 return (FX_DWORD)((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer; | 664 return (FX_DWORD)((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer; |
| 488 } | 665 } |
| OLD | NEW |