| OLD | NEW |
| (Empty) |
| 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 <setjmp.h> | |
| 8 | |
| 9 #include "core/include/fxcodec/fx_codec.h" | |
| 10 #include "core/include/fxcrt/fx_safe_types.h" | |
| 11 #include "core/include/fxge/fx_dib.h" | |
| 12 #include "core/src/fxcodec/codec/codec_int.h" | |
| 13 | |
| 14 extern "C" { | |
| 15 #undef FAR | |
| 16 #if defined(USE_SYSTEM_LIBJPEG) | |
| 17 #include <jpeglib.h> | |
| 18 #elif defined(USE_LIBJPEG_TURBO) | |
| 19 #include "third_party/libjpeg_turbo/jpeglib.h" | |
| 20 #else | |
| 21 #include "third_party/libjpeg/jpeglib.h" | |
| 22 #endif | |
| 23 } | |
| 24 | |
| 25 extern "C" { | |
| 26 static void _JpegScanSOI(const uint8_t*& src_buf, FX_DWORD& src_size) { | |
| 27 if (src_size == 0) { | |
| 28 return; | |
| 29 } | |
| 30 FX_DWORD offset = 0; | |
| 31 while (offset < src_size - 1) { | |
| 32 if (src_buf[offset] == 0xff && src_buf[offset + 1] == 0xd8) { | |
| 33 src_buf += offset; | |
| 34 src_size -= offset; | |
| 35 return; | |
| 36 } | |
| 37 offset++; | |
| 38 } | |
| 39 } | |
| 40 }; | |
| 41 extern "C" { | |
| 42 static void _src_do_nothing(struct jpeg_decompress_struct* cinfo) {} | |
| 43 }; | |
| 44 extern "C" { | |
| 45 static void _error_fatal(j_common_ptr cinfo) { | |
| 46 longjmp(*(jmp_buf*)cinfo->client_data, -1); | |
| 47 } | |
| 48 }; | |
| 49 extern "C" { | |
| 50 static void _src_skip_data(struct jpeg_decompress_struct* cinfo, long num) { | |
| 51 if (num > (long)cinfo->src->bytes_in_buffer) { | |
| 52 _error_fatal((j_common_ptr)cinfo); | |
| 53 } | |
| 54 cinfo->src->next_input_byte += num; | |
| 55 cinfo->src->bytes_in_buffer -= num; | |
| 56 } | |
| 57 }; | |
| 58 extern "C" { | |
| 59 static boolean _src_fill_buffer(j_decompress_ptr cinfo) { | |
| 60 return 0; | |
| 61 } | |
| 62 }; | |
| 63 extern "C" { | |
| 64 static boolean _src_resync(j_decompress_ptr cinfo, int desired) { | |
| 65 return 0; | |
| 66 } | |
| 67 }; | |
| 68 extern "C" { | |
| 69 static void _error_do_nothing(j_common_ptr cinfo) {} | |
| 70 }; | |
| 71 extern "C" { | |
| 72 static void _error_do_nothing1(j_common_ptr cinfo, int) {} | |
| 73 }; | |
| 74 extern "C" { | |
| 75 static void _error_do_nothing2(j_common_ptr cinfo, char*) {} | |
| 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; | |
| 135 | |
| 136 struct jpeg_compress_struct cinfo; | |
| 137 memset(&cinfo, 0, sizeof(cinfo)); | |
| 138 cinfo.err = &jerr; | |
| 139 jpeg_create_compress(&cinfo); | |
| 140 int Bpp = pSource->GetBPP() / 8; | |
| 141 FX_DWORD nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1; | |
| 142 FX_DWORD pitch = pSource->GetPitch(); | |
| 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 | |
| 234 #ifdef PDF_ENABLE_XFA | |
| 235 static void _JpegLoadAttribute(struct jpeg_decompress_struct* pInfo, | |
| 236 CFX_DIBAttribute* pAttribute) { | |
| 237 if (pInfo == NULL || pAttribute == NULL) { | |
| 238 return; | |
| 239 } | |
| 240 if (pAttribute) { | |
| 241 pAttribute->m_nXDPI = pInfo->X_density; | |
| 242 pAttribute->m_nYDPI = pInfo->Y_density; | |
| 243 pAttribute->m_wDPIUnit = pInfo->density_unit; | |
| 244 } | |
| 245 } | |
| 246 #endif // PDF_ENABLE_XFA | |
| 247 | |
| 248 static FX_BOOL _JpegLoadInfo(const uint8_t* src_buf, | |
| 249 FX_DWORD src_size, | |
| 250 int& width, | |
| 251 int& height, | |
| 252 int& num_components, | |
| 253 int& bits_per_components, | |
| 254 FX_BOOL& color_transform, | |
| 255 uint8_t** icc_buf_ptr, | |
| 256 FX_DWORD* icc_length) { | |
| 257 _JpegScanSOI(src_buf, src_size); | |
| 258 struct jpeg_decompress_struct cinfo; | |
| 259 struct jpeg_error_mgr jerr; | |
| 260 jerr.error_exit = _error_fatal; | |
| 261 jerr.emit_message = _error_do_nothing1; | |
| 262 jerr.output_message = _error_do_nothing; | |
| 263 jerr.format_message = _error_do_nothing2; | |
| 264 jerr.reset_error_mgr = _error_do_nothing; | |
| 265 jerr.trace_level = 0; | |
| 266 cinfo.err = &jerr; | |
| 267 jmp_buf mark; | |
| 268 cinfo.client_data = &mark; | |
| 269 if (setjmp(mark) == -1) { | |
| 270 return FALSE; | |
| 271 } | |
| 272 jpeg_create_decompress(&cinfo); | |
| 273 struct jpeg_source_mgr src; | |
| 274 src.init_source = _src_do_nothing; | |
| 275 src.term_source = _src_do_nothing; | |
| 276 src.skip_input_data = _src_skip_data; | |
| 277 src.fill_input_buffer = _src_fill_buffer; | |
| 278 src.resync_to_restart = _src_resync; | |
| 279 src.bytes_in_buffer = src_size; | |
| 280 src.next_input_byte = src_buf; | |
| 281 cinfo.src = &src; | |
| 282 if (setjmp(mark) == -1) { | |
| 283 jpeg_destroy_decompress(&cinfo); | |
| 284 return FALSE; | |
| 285 } | |
| 286 if (icc_buf_ptr && icc_length) { | |
| 287 jpeg_save_markers(&cinfo, JPEG_MARKER_ICC, JPEG_MARKER_MAXSIZE); | |
| 288 } | |
| 289 int ret = jpeg_read_header(&cinfo, TRUE); | |
| 290 if (ret != JPEG_HEADER_OK) { | |
| 291 jpeg_destroy_decompress(&cinfo); | |
| 292 return FALSE; | |
| 293 } | |
| 294 width = cinfo.image_width; | |
| 295 height = cinfo.image_height; | |
| 296 num_components = cinfo.num_components; | |
| 297 color_transform = | |
| 298 cinfo.jpeg_color_space == JCS_YCbCr || cinfo.jpeg_color_space == JCS_YCCK; | |
| 299 bits_per_components = cinfo.data_precision; | |
| 300 if (icc_buf_ptr) { | |
| 301 *icc_buf_ptr = NULL; | |
| 302 } | |
| 303 if (icc_length) { | |
| 304 *icc_length = 0; | |
| 305 } | |
| 306 jpeg_destroy_decompress(&cinfo); | |
| 307 return TRUE; | |
| 308 } | |
| 309 | |
| 310 class CCodec_JpegDecoder : public CCodec_ScanlineDecoder { | |
| 311 public: | |
| 312 CCodec_JpegDecoder(); | |
| 313 ~CCodec_JpegDecoder() override; | |
| 314 | |
| 315 FX_BOOL Create(const uint8_t* src_buf, | |
| 316 FX_DWORD src_size, | |
| 317 int width, | |
| 318 int height, | |
| 319 int nComps, | |
| 320 FX_BOOL ColorTransform); | |
| 321 void Destroy() { delete this; } | |
| 322 | |
| 323 // CCodec_ScanlineDecoder | |
| 324 void v_DownScale(int dest_width, int dest_height) override; | |
| 325 FX_BOOL v_Rewind() override; | |
| 326 uint8_t* v_GetNextLine() override; | |
| 327 FX_DWORD GetSrcOffset() override; | |
| 328 | |
| 329 FX_BOOL InitDecode(); | |
| 330 | |
| 331 jmp_buf m_JmpBuf; | |
| 332 struct jpeg_decompress_struct cinfo; | |
| 333 struct jpeg_error_mgr jerr; | |
| 334 struct jpeg_source_mgr src; | |
| 335 const uint8_t* m_SrcBuf; | |
| 336 FX_DWORD m_SrcSize; | |
| 337 uint8_t* m_pScanlineBuf; | |
| 338 | |
| 339 FX_BOOL m_bInited; | |
| 340 FX_BOOL m_bStarted; | |
| 341 FX_BOOL m_bJpegTransform; | |
| 342 | |
| 343 protected: | |
| 344 FX_DWORD m_nDefaultScaleDenom; | |
| 345 }; | |
| 346 | |
| 347 CCodec_JpegDecoder::CCodec_JpegDecoder() { | |
| 348 m_pScanlineBuf = NULL; | |
| 349 m_DownScale = 1; | |
| 350 m_bStarted = FALSE; | |
| 351 m_bInited = FALSE; | |
| 352 FXSYS_memset(&cinfo, 0, sizeof(cinfo)); | |
| 353 FXSYS_memset(&jerr, 0, sizeof(jerr)); | |
| 354 FXSYS_memset(&src, 0, sizeof(src)); | |
| 355 m_nDefaultScaleDenom = 1; | |
| 356 } | |
| 357 CCodec_JpegDecoder::~CCodec_JpegDecoder() { | |
| 358 FX_Free(m_pScanlineBuf); | |
| 359 if (m_bInited) { | |
| 360 jpeg_destroy_decompress(&cinfo); | |
| 361 } | |
| 362 } | |
| 363 FX_BOOL CCodec_JpegDecoder::InitDecode() { | |
| 364 cinfo.err = &jerr; | |
| 365 cinfo.client_data = &m_JmpBuf; | |
| 366 if (setjmp(m_JmpBuf) == -1) { | |
| 367 return FALSE; | |
| 368 } | |
| 369 jpeg_create_decompress(&cinfo); | |
| 370 m_bInited = TRUE; | |
| 371 cinfo.src = &src; | |
| 372 src.bytes_in_buffer = m_SrcSize; | |
| 373 src.next_input_byte = m_SrcBuf; | |
| 374 if (setjmp(m_JmpBuf) == -1) { | |
| 375 jpeg_destroy_decompress(&cinfo); | |
| 376 m_bInited = FALSE; | |
| 377 return FALSE; | |
| 378 } | |
| 379 cinfo.image_width = m_OrigWidth; | |
| 380 cinfo.image_height = m_OrigHeight; | |
| 381 int ret = jpeg_read_header(&cinfo, TRUE); | |
| 382 if (ret != JPEG_HEADER_OK) { | |
| 383 return FALSE; | |
| 384 } | |
| 385 if (cinfo.saw_Adobe_marker) { | |
| 386 m_bJpegTransform = TRUE; | |
| 387 } | |
| 388 if (cinfo.num_components == 3 && !m_bJpegTransform) { | |
| 389 cinfo.out_color_space = cinfo.jpeg_color_space; | |
| 390 } | |
| 391 m_OrigWidth = cinfo.image_width; | |
| 392 m_OrigHeight = cinfo.image_height; | |
| 393 m_OutputWidth = m_OrigWidth; | |
| 394 m_OutputHeight = m_OrigHeight; | |
| 395 m_nDefaultScaleDenom = cinfo.scale_denom; | |
| 396 return TRUE; | |
| 397 } | |
| 398 FX_BOOL CCodec_JpegDecoder::Create(const uint8_t* src_buf, | |
| 399 FX_DWORD src_size, | |
| 400 int width, | |
| 401 int height, | |
| 402 int nComps, | |
| 403 FX_BOOL ColorTransform) { | |
| 404 _JpegScanSOI(src_buf, src_size); | |
| 405 m_SrcBuf = src_buf; | |
| 406 m_SrcSize = src_size; | |
| 407 jerr.error_exit = _error_fatal; | |
| 408 jerr.emit_message = _error_do_nothing1; | |
| 409 jerr.output_message = _error_do_nothing; | |
| 410 jerr.format_message = _error_do_nothing2; | |
| 411 jerr.reset_error_mgr = _error_do_nothing; | |
| 412 src.init_source = _src_do_nothing; | |
| 413 src.term_source = _src_do_nothing; | |
| 414 src.skip_input_data = _src_skip_data; | |
| 415 src.fill_input_buffer = _src_fill_buffer; | |
| 416 src.resync_to_restart = _src_resync; | |
| 417 m_bJpegTransform = ColorTransform; | |
| 418 if (src_size > 1 && | |
| 419 FXSYS_memcmp(src_buf + src_size - 2, "\xFF\xD9", 2) != 0) { | |
| 420 ((uint8_t*)src_buf)[src_size - 2] = 0xFF; | |
| 421 ((uint8_t*)src_buf)[src_size - 1] = 0xD9; | |
| 422 } | |
| 423 m_OutputWidth = m_OrigWidth = width; | |
| 424 m_OutputHeight = m_OrigHeight = height; | |
| 425 if (!InitDecode()) { | |
| 426 return FALSE; | |
| 427 } | |
| 428 if (cinfo.num_components < nComps) { | |
| 429 return FALSE; | |
| 430 } | |
| 431 if ((int)cinfo.image_width < width) { | |
| 432 return FALSE; | |
| 433 } | |
| 434 m_Pitch = | |
| 435 (static_cast<FX_DWORD>(cinfo.image_width) * cinfo.num_components + 3) / | |
| 436 4 * 4; | |
| 437 m_pScanlineBuf = FX_Alloc(uint8_t, m_Pitch); | |
| 438 m_nComps = cinfo.num_components; | |
| 439 m_bpc = 8; | |
| 440 m_bColorTransformed = FALSE; | |
| 441 m_bStarted = FALSE; | |
| 442 return TRUE; | |
| 443 } | |
| 444 extern "C" { | |
| 445 int32_t FX_GetDownsampleRatio(int32_t originWidth, | |
| 446 int32_t originHeight, | |
| 447 int32_t downsampleWidth, | |
| 448 int32_t downsampleHeight) { | |
| 449 int iratio_w = originWidth / downsampleWidth; | |
| 450 int iratio_h = originHeight / downsampleHeight; | |
| 451 int ratio = (iratio_w > iratio_h) ? iratio_h : iratio_w; | |
| 452 if (ratio >= 8) { | |
| 453 return 8; | |
| 454 } | |
| 455 if (ratio >= 4) { | |
| 456 return 4; | |
| 457 } | |
| 458 if (ratio >= 2) { | |
| 459 return 2; | |
| 460 } | |
| 461 return 1; | |
| 462 } | |
| 463 } | |
| 464 void CCodec_JpegDecoder::v_DownScale(int dest_width, int dest_height) { | |
| 465 int old_scale = m_DownScale; | |
| 466 m_DownScale = | |
| 467 FX_GetDownsampleRatio(m_OrigWidth, m_OrigHeight, dest_width, dest_height); | |
| 468 m_OutputWidth = (m_OrigWidth + m_DownScale - 1) / m_DownScale; | |
| 469 m_OutputHeight = (m_OrigHeight + m_DownScale - 1) / m_DownScale; | |
| 470 m_Pitch = (static_cast<FX_DWORD>(m_OutputWidth) * m_nComps + 3) / 4 * 4; | |
| 471 if (old_scale != m_DownScale) { | |
| 472 m_NextLine = -1; | |
| 473 } | |
| 474 } | |
| 475 FX_BOOL CCodec_JpegDecoder::v_Rewind() { | |
| 476 if (m_bStarted) { | |
| 477 jpeg_destroy_decompress(&cinfo); | |
| 478 if (!InitDecode()) { | |
| 479 return FALSE; | |
| 480 } | |
| 481 } | |
| 482 if (setjmp(m_JmpBuf) == -1) { | |
| 483 return FALSE; | |
| 484 } | |
| 485 cinfo.scale_denom = m_nDefaultScaleDenom * m_DownScale; | |
| 486 m_OutputWidth = (m_OrigWidth + m_DownScale - 1) / m_DownScale; | |
| 487 m_OutputHeight = (m_OrigHeight + m_DownScale - 1) / m_DownScale; | |
| 488 if (!jpeg_start_decompress(&cinfo)) { | |
| 489 jpeg_destroy_decompress(&cinfo); | |
| 490 return FALSE; | |
| 491 } | |
| 492 if ((int)cinfo.output_width > m_OrigWidth) { | |
| 493 FXSYS_assert(FALSE); | |
| 494 return FALSE; | |
| 495 } | |
| 496 m_bStarted = TRUE; | |
| 497 return TRUE; | |
| 498 } | |
| 499 uint8_t* CCodec_JpegDecoder::v_GetNextLine() { | |
| 500 if (setjmp(m_JmpBuf) == -1) | |
| 501 return nullptr; | |
| 502 | |
| 503 int nlines = jpeg_read_scanlines(&cinfo, &m_pScanlineBuf, 1); | |
| 504 if (nlines < 1) { | |
| 505 return nullptr; | |
| 506 } | |
| 507 return m_pScanlineBuf; | |
| 508 } | |
| 509 FX_DWORD CCodec_JpegDecoder::GetSrcOffset() { | |
| 510 return (FX_DWORD)(m_SrcSize - src.bytes_in_buffer); | |
| 511 } | |
| 512 ICodec_ScanlineDecoder* CCodec_JpegModule::CreateDecoder( | |
| 513 const uint8_t* src_buf, | |
| 514 FX_DWORD src_size, | |
| 515 int width, | |
| 516 int height, | |
| 517 int nComps, | |
| 518 FX_BOOL ColorTransform) { | |
| 519 if (!src_buf || src_size == 0) { | |
| 520 return NULL; | |
| 521 } | |
| 522 CCodec_JpegDecoder* pDecoder = new CCodec_JpegDecoder; | |
| 523 if (!pDecoder->Create(src_buf, src_size, width, height, nComps, | |
| 524 ColorTransform)) { | |
| 525 delete pDecoder; | |
| 526 return NULL; | |
| 527 } | |
| 528 return pDecoder; | |
| 529 } | |
| 530 FX_BOOL CCodec_JpegModule::LoadInfo(const uint8_t* src_buf, | |
| 531 FX_DWORD src_size, | |
| 532 int& width, | |
| 533 int& height, | |
| 534 int& num_components, | |
| 535 int& bits_per_components, | |
| 536 FX_BOOL& color_transform, | |
| 537 uint8_t** icc_buf_ptr, | |
| 538 FX_DWORD* icc_length) { | |
| 539 return _JpegLoadInfo(src_buf, src_size, width, height, num_components, | |
| 540 bits_per_components, color_transform, icc_buf_ptr, | |
| 541 icc_length); | |
| 542 } | |
| 543 FX_BOOL CCodec_JpegModule::Encode(const CFX_DIBSource* pSource, | |
| 544 uint8_t*& dest_buf, | |
| 545 FX_STRSIZE& dest_size, | |
| 546 int quality, | |
| 547 const uint8_t* icc_buf, | |
| 548 FX_DWORD icc_length) { | |
| 549 if (pSource->GetBPP() < 8 || pSource->GetPalette()) | |
| 550 return FALSE; | |
| 551 | |
| 552 _JpegEncode(pSource, dest_buf, dest_size, quality, icc_buf, icc_length); | |
| 553 return TRUE; | |
| 554 } | |
| 555 struct FXJPEG_Context { | |
| 556 jmp_buf m_JumpMark; | |
| 557 jpeg_decompress_struct m_Info; | |
| 558 jpeg_error_mgr m_ErrMgr; | |
| 559 jpeg_source_mgr m_SrcMgr; | |
| 560 unsigned int m_SkipSize; | |
| 561 void* (*m_AllocFunc)(unsigned int); | |
| 562 void (*m_FreeFunc)(void*); | |
| 563 }; | |
| 564 extern "C" { | |
| 565 static void _error_fatal1(j_common_ptr cinfo) { | |
| 566 longjmp(((FXJPEG_Context*)cinfo->client_data)->m_JumpMark, -1); | |
| 567 } | |
| 568 }; | |
| 569 extern "C" { | |
| 570 static void _src_skip_data1(struct jpeg_decompress_struct* cinfo, long num) { | |
| 571 if (cinfo->src->bytes_in_buffer < (size_t)num) { | |
| 572 ((FXJPEG_Context*)cinfo->client_data)->m_SkipSize = | |
| 573 (unsigned int)(num - cinfo->src->bytes_in_buffer); | |
| 574 cinfo->src->bytes_in_buffer = 0; | |
| 575 } else { | |
| 576 cinfo->src->next_input_byte += num; | |
| 577 cinfo->src->bytes_in_buffer -= num; | |
| 578 } | |
| 579 } | |
| 580 }; | |
| 581 static void* jpeg_alloc_func(unsigned int size) { | |
| 582 return FX_Alloc(char, size); | |
| 583 } | |
| 584 static void jpeg_free_func(void* p) { | |
| 585 FX_Free(p); | |
| 586 } | |
| 587 void* CCodec_JpegModule::Start() { | |
| 588 FXJPEG_Context* p = FX_Alloc(FXJPEG_Context, 1); | |
| 589 p->m_AllocFunc = jpeg_alloc_func; | |
| 590 p->m_FreeFunc = jpeg_free_func; | |
| 591 p->m_ErrMgr.error_exit = _error_fatal1; | |
| 592 p->m_ErrMgr.emit_message = _error_do_nothing1; | |
| 593 p->m_ErrMgr.output_message = _error_do_nothing; | |
| 594 p->m_ErrMgr.format_message = _error_do_nothing2; | |
| 595 p->m_ErrMgr.reset_error_mgr = _error_do_nothing; | |
| 596 p->m_SrcMgr.init_source = _src_do_nothing; | |
| 597 p->m_SrcMgr.term_source = _src_do_nothing; | |
| 598 p->m_SrcMgr.skip_input_data = _src_skip_data1; | |
| 599 p->m_SrcMgr.fill_input_buffer = _src_fill_buffer; | |
| 600 p->m_SrcMgr.resync_to_restart = _src_resync; | |
| 601 p->m_Info.client_data = p; | |
| 602 p->m_Info.err = &p->m_ErrMgr; | |
| 603 if (setjmp(p->m_JumpMark) == -1) { | |
| 604 return 0; | |
| 605 } | |
| 606 jpeg_create_decompress(&p->m_Info); | |
| 607 p->m_Info.src = &p->m_SrcMgr; | |
| 608 p->m_SkipSize = 0; | |
| 609 return p; | |
| 610 } | |
| 611 void CCodec_JpegModule::Finish(void* pContext) { | |
| 612 FXJPEG_Context* p = (FXJPEG_Context*)pContext; | |
| 613 jpeg_destroy_decompress(&p->m_Info); | |
| 614 p->m_FreeFunc(p); | |
| 615 } | |
| 616 void CCodec_JpegModule::Input(void* pContext, | |
| 617 const unsigned char* src_buf, | |
| 618 FX_DWORD src_size) { | |
| 619 FXJPEG_Context* p = (FXJPEG_Context*)pContext; | |
| 620 if (p->m_SkipSize) { | |
| 621 if (p->m_SkipSize > src_size) { | |
| 622 p->m_SrcMgr.bytes_in_buffer = 0; | |
| 623 p->m_SkipSize -= src_size; | |
| 624 return; | |
| 625 } | |
| 626 src_size -= p->m_SkipSize; | |
| 627 src_buf += p->m_SkipSize; | |
| 628 p->m_SkipSize = 0; | |
| 629 } | |
| 630 p->m_SrcMgr.next_input_byte = src_buf; | |
| 631 p->m_SrcMgr.bytes_in_buffer = src_size; | |
| 632 } | |
| 633 | |
| 634 #ifdef PDF_ENABLE_XFA | |
| 635 int CCodec_JpegModule::ReadHeader(void* pContext, | |
| 636 int* width, | |
| 637 int* height, | |
| 638 int* nComps, | |
| 639 CFX_DIBAttribute* pAttribute) { | |
| 640 #else // PDF_ENABLE_XFA | |
| 641 int CCodec_JpegModule::ReadHeader(void* pContext, | |
| 642 int* width, | |
| 643 int* height, | |
| 644 int* nComps) { | |
| 645 #endif // PDF_ENABLE_XFA | |
| 646 FXJPEG_Context* p = (FXJPEG_Context*)pContext; | |
| 647 if (setjmp(p->m_JumpMark) == -1) { | |
| 648 return 1; | |
| 649 } | |
| 650 int ret = jpeg_read_header(&p->m_Info, true); | |
| 651 if (ret == JPEG_SUSPENDED) { | |
| 652 return 2; | |
| 653 } | |
| 654 if (ret != JPEG_HEADER_OK) { | |
| 655 return 1; | |
| 656 } | |
| 657 *width = p->m_Info.image_width; | |
| 658 *height = p->m_Info.image_height; | |
| 659 *nComps = p->m_Info.num_components; | |
| 660 #ifdef PDF_ENABLE_XFA | |
| 661 _JpegLoadAttribute(&p->m_Info, pAttribute); | |
| 662 #endif | |
| 663 return 0; | |
| 664 } | |
| 665 int CCodec_JpegModule::StartScanline(void* pContext, int down_scale) { | |
| 666 FXJPEG_Context* p = (FXJPEG_Context*)pContext; | |
| 667 if (setjmp(p->m_JumpMark) == -1) { | |
| 668 return 0; | |
| 669 } | |
| 670 p->m_Info.scale_denom = down_scale; | |
| 671 return jpeg_start_decompress(&p->m_Info); | |
| 672 } | |
| 673 FX_BOOL CCodec_JpegModule::ReadScanline(void* pContext, | |
| 674 unsigned char* dest_buf) { | |
| 675 FXJPEG_Context* p = (FXJPEG_Context*)pContext; | |
| 676 if (setjmp(p->m_JumpMark) == -1) { | |
| 677 return FALSE; | |
| 678 } | |
| 679 int nlines = jpeg_read_scanlines(&p->m_Info, &dest_buf, 1); | |
| 680 return nlines == 1; | |
| 681 } | |
| 682 FX_DWORD CCodec_JpegModule::GetAvailInput(void* pContext, | |
| 683 uint8_t** avail_buf_ptr) { | |
| 684 if (avail_buf_ptr) { | |
| 685 *avail_buf_ptr = NULL; | |
| 686 if (((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer > 0) { | |
| 687 *avail_buf_ptr = | |
| 688 (uint8_t*)((FXJPEG_Context*)pContext)->m_SrcMgr.next_input_byte; | |
| 689 } | |
| 690 } | |
| 691 return (FX_DWORD)((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer; | |
| 692 } | |
| OLD | NEW |