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 "codec_int.h" 10 #include "core/include/fxcodec/fx_codec.h" 11 #include "core/include/fxcrt/fx_safe_types.h" 12 #include "core/include/fxge/fx_dib.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 } 693