Chromium Code Reviews| 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) | 77 |
| 78 #define JPEG_MARKER_ICC (JPEG_APP0 + 2) | 78 #define JPEG_MARKER_ICC (JPEG_APP0 + 2) |
| 79 #define JPEG_MARKER_AUTHORTIME (JPEG_APP0 + 3) | |
| 80 #define JPEG_MARKER_MAXSIZE 0xFFFF | 79 #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; | |
| 135 | 80 |
| 136 struct jpeg_compress_struct cinfo; | 81 static bool JpegLoadInfo(const uint8_t* src_buf, |
| 137 memset(&cinfo, 0, sizeof(cinfo)); | 82 FX_DWORD src_size, |
| 138 cinfo.err = &jerr; | 83 int* width, |
| 139 jpeg_create_compress(&cinfo); | 84 int* height, |
| 140 int Bpp = pSource->GetBPP() / 8; | 85 int* num_components, |
| 141 FX_DWORD nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1; | 86 int* bits_per_components, |
| 142 FX_DWORD pitch = pSource->GetPitch(); | 87 bool* color_transform) { |
| 143 FX_DWORD width = pdfium::base::checked_cast<FX_DWORD>(pSource->GetWidth()); | |
| 144 FX_DWORD height = pdfium::base::checked_cast<FX_DWORD>(pSource->GetHeight()); | |
| 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) { | |
| 242 _JpegScanSOI(src_buf, src_size); | 88 _JpegScanSOI(src_buf, src_size); |
| 243 struct jpeg_decompress_struct cinfo; | 89 struct jpeg_decompress_struct cinfo; |
| 244 struct jpeg_error_mgr jerr; | 90 struct jpeg_error_mgr jerr; |
| 245 jerr.error_exit = _error_fatal; | 91 jerr.error_exit = _error_fatal; |
| 246 jerr.emit_message = _error_do_nothing1; | 92 jerr.emit_message = _error_do_nothing1; |
| 247 jerr.output_message = _error_do_nothing; | 93 jerr.output_message = _error_do_nothing; |
| 248 jerr.format_message = _error_do_nothing2; | 94 jerr.format_message = _error_do_nothing2; |
| 249 jerr.reset_error_mgr = _error_do_nothing; | 95 jerr.reset_error_mgr = _error_do_nothing; |
| 250 jerr.trace_level = 0; | 96 jerr.trace_level = 0; |
| 251 cinfo.err = &jerr; | 97 cinfo.err = &jerr; |
| 252 jmp_buf mark; | 98 jmp_buf mark; |
| 253 cinfo.client_data = &mark; | 99 cinfo.client_data = &mark; |
| 254 if (setjmp(mark) == -1) { | 100 if (setjmp(mark) == -1) { |
| 255 return FALSE; | 101 return FALSE; |
| 256 } | 102 } |
| 257 jpeg_create_decompress(&cinfo); | 103 jpeg_create_decompress(&cinfo); |
| 258 struct jpeg_source_mgr src; | 104 struct jpeg_source_mgr src; |
| 259 src.init_source = _src_do_nothing; | 105 src.init_source = _src_do_nothing; |
| 260 src.term_source = _src_do_nothing; | 106 src.term_source = _src_do_nothing; |
| 261 src.skip_input_data = _src_skip_data; | 107 src.skip_input_data = _src_skip_data; |
| 262 src.fill_input_buffer = _src_fill_buffer; | 108 src.fill_input_buffer = _src_fill_buffer; |
| 263 src.resync_to_restart = _src_resync; | 109 src.resync_to_restart = _src_resync; |
| 264 src.bytes_in_buffer = src_size; | 110 src.bytes_in_buffer = src_size; |
| 265 src.next_input_byte = src_buf; | 111 src.next_input_byte = src_buf; |
| 266 cinfo.src = &src; | 112 cinfo.src = &src; |
| 267 if (setjmp(mark) == -1) { | 113 if (setjmp(mark) == -1) { |
| 268 jpeg_destroy_decompress(&cinfo); | 114 jpeg_destroy_decompress(&cinfo); |
| 269 return FALSE; | 115 return FALSE; |
|
Oliver Chang
2015/12/22 17:35:47
since this returns bool now, change FALSE/TRUE to
Lei Zhang
2015/12/22 22:16:42
Done.
| |
| 270 } | 116 } |
| 271 if (icc_buf_ptr && icc_length) { | |
| 272 jpeg_save_markers(&cinfo, JPEG_MARKER_ICC, JPEG_MARKER_MAXSIZE); | |
| 273 } | |
| 274 int ret = jpeg_read_header(&cinfo, TRUE); | 117 int ret = jpeg_read_header(&cinfo, TRUE); |
| 275 if (ret != JPEG_HEADER_OK) { | 118 if (ret != JPEG_HEADER_OK) { |
| 276 jpeg_destroy_decompress(&cinfo); | 119 jpeg_destroy_decompress(&cinfo); |
| 277 return FALSE; | 120 return FALSE; |
|
Oliver Chang
2015/12/22 17:35:47
ditto
Lei Zhang
2015/12/22 22:16:42
Done.
| |
| 278 } | 121 } |
| 279 width = cinfo.image_width; | 122 *width = cinfo.image_width; |
| 280 height = cinfo.image_height; | 123 *height = cinfo.image_height; |
| 281 num_components = cinfo.num_components; | 124 *num_components = cinfo.num_components; |
| 282 color_transform = | 125 *color_transform = |
| 283 cinfo.jpeg_color_space == JCS_YCbCr || cinfo.jpeg_color_space == JCS_YCCK; | 126 cinfo.jpeg_color_space == JCS_YCbCr || cinfo.jpeg_color_space == JCS_YCCK; |
| 284 bits_per_components = cinfo.data_precision; | 127 *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 } | |
| 291 jpeg_destroy_decompress(&cinfo); | 128 jpeg_destroy_decompress(&cinfo); |
| 292 return TRUE; | 129 return TRUE; |
| 293 } | 130 } |
| 294 | 131 |
| 295 class CCodec_JpegDecoder : public CCodec_ScanlineDecoder { | 132 class CCodec_JpegDecoder : public CCodec_ScanlineDecoder { |
| 296 public: | 133 public: |
| 297 CCodec_JpegDecoder(); | 134 CCodec_JpegDecoder(); |
| 298 ~CCodec_JpegDecoder() override; | 135 ~CCodec_JpegDecoder() override; |
| 299 | 136 |
| 300 FX_BOOL Create(const uint8_t* src_buf, | 137 FX_BOOL Create(const uint8_t* src_buf, |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 505 return NULL; | 342 return NULL; |
| 506 } | 343 } |
| 507 CCodec_JpegDecoder* pDecoder = new CCodec_JpegDecoder; | 344 CCodec_JpegDecoder* pDecoder = new CCodec_JpegDecoder; |
| 508 if (!pDecoder->Create(src_buf, src_size, width, height, nComps, | 345 if (!pDecoder->Create(src_buf, src_size, width, height, nComps, |
| 509 ColorTransform)) { | 346 ColorTransform)) { |
| 510 delete pDecoder; | 347 delete pDecoder; |
| 511 return NULL; | 348 return NULL; |
| 512 } | 349 } |
| 513 return pDecoder; | 350 return pDecoder; |
| 514 } | 351 } |
| 515 FX_BOOL CCodec_JpegModule::LoadInfo(const uint8_t* src_buf, | 352 bool CCodec_JpegModule::LoadInfo(const uint8_t* src_buf, |
| 516 FX_DWORD src_size, | 353 FX_DWORD src_size, |
| 517 int& width, | 354 int* width, |
| 518 int& height, | 355 int* height, |
| 519 int& num_components, | 356 int* num_components, |
| 520 int& bits_per_components, | 357 int* bits_per_components, |
| 521 FX_BOOL& color_transform, | 358 bool* color_transform) { |
| 522 uint8_t** icc_buf_ptr, | 359 return JpegLoadInfo(src_buf, src_size, width, height, num_components, |
| 523 FX_DWORD* icc_length) { | 360 bits_per_components, color_transform); |
| 524 return _JpegLoadInfo(src_buf, src_size, width, height, num_components, | |
| 525 bits_per_components, color_transform, icc_buf_ptr, | |
| 526 icc_length); | |
| 527 } | 361 } |
| 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; | |
| 536 | 362 |
| 537 _JpegEncode(pSource, dest_buf, dest_size, quality, icc_buf, icc_length); | |
| 538 return TRUE; | |
| 539 } | |
| 540 struct FXJPEG_Context { | 363 struct FXJPEG_Context { |
| 541 jmp_buf m_JumpMark; | 364 jmp_buf m_JumpMark; |
| 542 jpeg_decompress_struct m_Info; | 365 jpeg_decompress_struct m_Info; |
| 543 jpeg_error_mgr m_ErrMgr; | 366 jpeg_error_mgr m_ErrMgr; |
| 544 jpeg_source_mgr m_SrcMgr; | 367 jpeg_source_mgr m_SrcMgr; |
| 545 unsigned int m_SkipSize; | 368 unsigned int m_SkipSize; |
| 546 void* (*m_AllocFunc)(unsigned int); | 369 void* (*m_AllocFunc)(unsigned int); |
| 547 void (*m_FreeFunc)(void*); | 370 void (*m_FreeFunc)(void*); |
| 548 }; | 371 }; |
| 549 extern "C" { | 372 extern "C" { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 656 uint8_t** avail_buf_ptr) { | 479 uint8_t** avail_buf_ptr) { |
| 657 if (avail_buf_ptr) { | 480 if (avail_buf_ptr) { |
| 658 *avail_buf_ptr = NULL; | 481 *avail_buf_ptr = NULL; |
| 659 if (((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer > 0) { | 482 if (((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer > 0) { |
| 660 *avail_buf_ptr = | 483 *avail_buf_ptr = |
| 661 (uint8_t*)((FXJPEG_Context*)pContext)->m_SrcMgr.next_input_byte; | 484 (uint8_t*)((FXJPEG_Context*)pContext)->m_SrcMgr.next_input_byte; |
| 662 } | 485 } |
| 663 } | 486 } |
| 664 return (FX_DWORD)((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer; | 487 return (FX_DWORD)((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer; |
| 665 } | 488 } |
| OLD | NEW |