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 "../../../include/fxcodec/fx_codec.h" 8#include "../../../include/fxge/fx_dib.h" 9#include "../../../src/fxcrt/fx_safe_types.h" 10#include "codec_int.h" 11extern "C" { 12 static void _JpegScanSOI(const FX_BYTE*& src_buf, FX_DWORD& src_size) 13 { 14 if (src_size == 0) { 15 return; 16 } 17 FX_DWORD offset = 0; 18 while (offset < src_size - 1) { 19 if (src_buf[offset] == 0xff && src_buf[offset + 1] == 0xd8) { 20 src_buf += offset; 21 src_size -= offset; 22 return; 23 } 24 offset ++; 25 } 26 } 27}; 28extern "C" { 29#undef FAR 30#include "../../fx_jpeglib.h" 31} 32extern "C" { 33 static void _src_do_nothing(struct jpeg_decompress_struct* cinfo) {} 34}; 35extern "C" { 36 static void _error_fatal(j_common_ptr cinfo) 37 { 38 longjmp(*(jmp_buf*)cinfo->client_data, -1); 39 } 40}; 41extern "C" { 42 static void _src_skip_data(struct jpeg_decompress_struct* cinfo, long num) 43 { 44 if (num > (long)cinfo->src->bytes_in_buffer) { 45 _error_fatal((j_common_ptr)cinfo); 46 } 47 cinfo->src->next_input_byte += num; 48 cinfo->src->bytes_in_buffer -= num; 49 } 50}; 51extern "C" { 52 static boolean _src_fill_buffer(j_decompress_ptr cinfo) 53 { 54 return 0; 55 } 56}; 57extern "C" { 58 static boolean _src_resync(j_decompress_ptr cinfo, int desired) 59 { 60 return 0; 61 } 62}; 63extern "C" { 64 static void _error_do_nothing(j_common_ptr cinfo) {} 65}; 66extern "C" { 67 static void _error_do_nothing1(j_common_ptr cinfo, int) {} 68}; 69extern "C" { 70 static void _error_do_nothing2(j_common_ptr cinfo, char*) {} 71}; 72#define JPEG_MARKER_EXIF (JPEG_APP0 + 1) 73#define JPEG_MARKER_ICC (JPEG_APP0 + 2) 74#define JPEG_MARKER_AUTHORTIME (JPEG_APP0 + 3) 75#define JPEG_MARKER_MAXSIZE 0xFFFF 76#define JPEG_OVERHEAD_LEN 14 77static FX_BOOL _JpegEmbedIccProfile(j_compress_ptr cinfo, FX_LPCBYTE icc_buf_ptr, FX_DWORD icc_length) 78{ 79 if(icc_buf_ptr == NULL || icc_length == 0) { 80 return FALSE; 81 } 82 FX_DWORD icc_segment_size = (JPEG_MARKER_MAXSIZE - 2 - JPEG_OVERHEAD_LEN); 83 FX_DWORD icc_segment_num = (icc_length / icc_segment_size) + 1; 84 if (icc_segment_num > 255) { 85 return FALSE; 86 } 87 FX_DWORD icc_data_length = JPEG_OVERHEAD_LEN + (icc_segment_num > 1 ? icc_segment_size : icc_length); 88 FX_LPBYTE icc_data = FX_Alloc(FX_BYTE, icc_data_length); 89 FXSYS_memcpy32(icc_data, "\x49\x43\x43\x5f\x50\x52\x4f\x46\x49\x4c\x45\x00", 12); 90 icc_data[13] = (FX_BYTE)icc_segment_num; 91 for (FX_BYTE i = 0; i < (icc_segment_num - 1); i++) { 92 icc_data[12] = i + 1; 93 FXSYS_memcpy32(icc_data + JPEG_OVERHEAD_LEN, icc_buf_ptr + i * icc_segment_size, icc_segment_size); 94 jpeg_write_marker(cinfo, JPEG_MARKER_ICC, icc_data, icc_data_length); 95 } 96 icc_data[12] = (FX_BYTE)icc_segment_num; 97 FX_DWORD icc_size = (icc_segment_num - 1) * icc_segment_size; 98 FXSYS_memcpy32(icc_data + JPEG_OVERHEAD_LEN, icc_buf_ptr + icc_size, icc_length - icc_size); 99 jpeg_write_marker(cinfo, JPEG_MARKER_ICC, icc_data, JPEG_OVERHEAD_LEN + icc_length - icc_size); 100 FX_Free(icc_data); 101 return TRUE; 102} 103extern "C" { 104 static void _dest_do_nothing(j_compress_ptr cinfo) {} 105}; 106extern "C" { 107 static boolean _dest_empty(j_compress_ptr cinfo) 108 { 109 return FALSE; 110 } 111}; 112#define JPEG_BLOCK_SIZE 1048576 113static void _JpegEncode(const CFX_DIBSource* pSource, FX_LPBYTE& dest_buf, FX_STRSIZE& dest_size, int quality, FX_LPCBYTE icc_buf, FX_DWORD icc_length) 114{ 115 struct jpeg_error_mgr jerr; 116 jerr.error_exit = _error_do_nothing; 117 jerr.emit_message = _error_do_nothing1; 118 jerr.output_message = _error_do_nothing; 119 jerr.format_message = _error_do_nothing2; 120 jerr.reset_error_mgr = _error_do_nothing; 121 122 struct jpeg_compress_struct cinfo; 123 memset(&cinfo, 0, sizeof(cinfo)); 124 cinfo.err = &jerr; 125 jpeg_create_compress(&cinfo); 126 int Bpp = pSource->GetBPP() / 8; 127 FX_DWORD nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1; 128 FX_DWORD pitch = pSource->GetPitch(); 129 FX_DWORD width = pdfium::base::checked_cast<FX_DWORD>(pSource->GetWidth()); 130 FX_DWORD height = pdfium::base::checked_cast<FX_DWORD>(pSource->GetHeight()); 131 FX_SAFE_DWORD safe_buf_len = width; 132 safe_buf_len *= height; 133 safe_buf_len *= nComponents; 134 safe_buf_len += 1024; 135 if (icc_length) { 136 safe_buf_len += 255 * 18; 137 safe_buf_len += icc_length; 138 } 139 FX_DWORD dest_buf_length = 0; 140 if (!safe_buf_len.IsValid()) { 141 dest_buf = nullptr; 142 } else { 143 dest_buf_length = safe_buf_len.ValueOrDie(); 144 dest_buf = FX_TryAlloc(FX_BYTE, dest_buf_length); 145 const int MIN_TRY_BUF_LEN = 1024; 146 while (!dest_buf && dest_buf_length > MIN_TRY_BUF_LEN) { 147 dest_buf_length >>= 1; 148 dest_buf = FX_TryAlloc(FX_BYTE, dest_buf_length); 149 } 150 } 151 if (!dest_buf) { 152 FX_OutOfMemoryTerminate(); 153 } 154 struct jpeg_destination_mgr dest; 155 dest.init_destination = _dest_do_nothing; 156 dest.term_destination = _dest_do_nothing; 157 dest.empty_output_buffer = _dest_empty; 158 dest.next_output_byte = dest_buf; 159 dest.free_in_buffer = dest_buf_length; 160 cinfo.dest = &dest; 161 cinfo.image_width = width; 162 cinfo.image_height = height; 163 cinfo.input_components = nComponents; 164 if (nComponents == 1) { 165 cinfo.in_color_space = JCS_GRAYSCALE; 166 } else if (nComponents == 3) { 167 cinfo.in_color_space = JCS_RGB; 168 } else { 169 cinfo.in_color_space = JCS_CMYK; 170 } 171 FX_LPBYTE line_buf = NULL; 172 if (nComponents > 1) { 173 line_buf = FX_Alloc2D(FX_BYTE, width, nComponents); 174 } 175 jpeg_set_defaults(&cinfo); 176 if(quality != 75) { 177 jpeg_set_quality(&cinfo, quality, TRUE); 178 } 179 jpeg_start_compress(&cinfo, TRUE); 180 _JpegEmbedIccProfile(&cinfo, icc_buf, icc_length); 181 JSAMPROW row_pointer[1]; 182 JDIMENSION row; 183 while (cinfo.next_scanline < cinfo.image_height) { 184 FX_LPCBYTE src_scan = pSource->GetScanline(cinfo.next_scanline); 185 if (nComponents > 1) { 186 FX_LPBYTE dest_scan = line_buf; 187 if (nComponents == 3) { 188 for (int i = 0; i < width; i ++) { 189 dest_scan[0] = src_scan[2]; 190 dest_scan[1] = src_scan[1]; 191 dest_scan[2] = src_scan[0]; 192 dest_scan += 3; 193 src_scan += Bpp; 194 } 195 } else { 196 for (int i = 0; i < pitch; i ++) { 197 *dest_scan++ = ~*src_scan++; 198 } 199 } 200 row_pointer[0] = line_buf; 201 } else { 202 row_pointer[0] = (FX_LPBYTE)src_scan; 203 } 204 row = cinfo.next_scanline; 205 jpeg_write_scanlines(&cinfo, row_pointer, 1); 206 if (cinfo.next_scanline == row) { 207 dest_buf = FX_Realloc(FX_BYTE, dest_buf, dest_buf_length + JPEG_BLOCK_SIZE); 208 dest.next_output_byte = dest_buf + dest_buf_length - dest.free_in_buffer; 209 dest_buf_length += JPEG_BLOCK_SIZE; 210 dest.free_in_buffer += JPEG_BLOCK_SIZE; 211 } 212 } 213 jpeg_finish_compress(&cinfo); 214 jpeg_destroy_compress(&cinfo); 215 if (line_buf) { 216 FX_Free(line_buf); 217 } 218 dest_size = dest_buf_length - (FX_STRSIZE)dest.free_in_buffer; 219} 220static FX_BOOL _JpegLoadInfo(FX_LPCBYTE src_buf, FX_DWORD src_size, int& width, int& height, 221 int& num_components, int& bits_per_components, FX_BOOL& color_transform, 222 FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length) 223{ 224 _JpegScanSOI(src_buf, src_size); 225 struct jpeg_decompress_struct cinfo; 226 struct jpeg_error_mgr jerr; 227 jerr.error_exit = _error_fatal; 228 jerr.emit_message = _error_do_nothing1; 229 jerr.output_message = _error_do_nothing; 230 jerr.format_message = _error_do_nothing2; 231 jerr.reset_error_mgr = _error_do_nothing; 232 jerr.trace_level = 0; 233 cinfo.err = &jerr; 234 jmp_buf mark; 235 cinfo.client_data = &mark; 236 if (setjmp(mark) == -1) { 237 return FALSE; 238 } 239 jpeg_create_decompress(&cinfo); 240 struct jpeg_source_mgr src; 241 src.init_source = _src_do_nothing; 242 src.term_source = _src_do_nothing; 243 src.skip_input_data = _src_skip_data; 244 src.fill_input_buffer = _src_fill_buffer; 245 src.resync_to_restart = _src_resync; 246 src.bytes_in_buffer = src_size; 247 src.next_input_byte = src_buf; 248 cinfo.src = &src; 249 if (setjmp(mark) == -1) { 250 jpeg_destroy_decompress(&cinfo); 251 return FALSE; 252 } 253 if(icc_buf_ptr && icc_length) { 254 jpeg_save_markers(&cinfo, JPEG_MARKER_ICC, JPEG_MARKER_MAXSIZE); 255 } 256 int ret = jpeg_read_header(&cinfo, TRUE); 257 if (ret != JPEG_HEADER_OK) { 258 jpeg_destroy_decompress(&cinfo); 259 return FALSE; 260 } 261 width = cinfo.image_width; 262 height = cinfo.image_height; 263 num_components = cinfo.num_components; 264 color_transform = cinfo.jpeg_color_space == JCS_YCbCr || cinfo.jpeg_color_space == JCS_YCCK; 265 bits_per_components = cinfo.data_precision; 266 if(icc_buf_ptr != NULL) { 267 *icc_buf_ptr = NULL; 268 } 269 if(icc_length != NULL) { 270 *icc_length = 0; 271 } 272 jpeg_destroy_decompress(&cinfo); 273 return TRUE; 274} 275class CCodec_JpegDecoder : public CCodec_ScanlineDecoder 276{ 277public: 278 CCodec_JpegDecoder(); 279 ~CCodec_JpegDecoder(); 280 FX_BOOL Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height, int nComps, 281 FX_BOOL ColorTransform, IFX_JpegProvider* pJP); 282 virtual void Destroy() 283 { 284 delete this; 285 } 286 virtual void v_DownScale(int dest_width, int dest_height); 287 virtual FX_BOOL v_Rewind(); 288 virtual FX_LPBYTE v_GetNextLine(); 289 virtual FX_DWORD GetSrcOffset(); 290 jmp_buf m_JmpBuf; 291 struct jpeg_decompress_struct cinfo; 292 struct jpeg_error_mgr jerr; 293 struct jpeg_source_mgr src; 294 FX_LPCBYTE m_SrcBuf; 295 FX_DWORD m_SrcSize; 296 FX_LPBYTE m_pScanlineBuf; 297 FX_BOOL InitDecode(); 298 FX_BOOL m_bInited, m_bStarted, m_bJpegTransform; 299protected: 300 IFX_JpegProvider* m_pExtProvider; 301 void* m_pExtContext; 302 FX_DWORD m_nDefaultScaleDenom; 303}; 304CCodec_JpegDecoder::CCodec_JpegDecoder() 305{ 306 m_pScanlineBuf = NULL; 307 m_DownScale = 1; 308 m_bStarted = FALSE; 309 m_bInited = FALSE; 310 m_pExtProvider = NULL; 311 m_pExtContext = NULL; 312 FXSYS_memset32(&cinfo, 0, sizeof(cinfo)); 313 FXSYS_memset32(&jerr, 0, sizeof(jerr)); 314 FXSYS_memset32(&src, 0, sizeof(src)); 315 m_nDefaultScaleDenom = 1; 316} 317CCodec_JpegDecoder::~CCodec_JpegDecoder() 318{ 319 if (m_pExtProvider) { 320 m_pExtProvider->DestroyDecoder(m_pExtContext); 321 return; 322 } 323 if (m_pScanlineBuf) { 324 FX_Free(m_pScanlineBuf); 325 } 326 if (m_bInited) { 327 jpeg_destroy_decompress(&cinfo); 328 } 329} 330FX_BOOL CCodec_JpegDecoder::InitDecode() 331{ 332 cinfo.err = &jerr; 333 cinfo.client_data = &m_JmpBuf; 334 if (setjmp(m_JmpBuf) == -1) { 335 return FALSE; 336 } 337 jpeg_create_decompress(&cinfo); 338 m_bInited = TRUE; 339 cinfo.src = &src; 340 src.bytes_in_buffer = m_SrcSize; 341 src.next_input_byte = m_SrcBuf; 342 if (setjmp(m_JmpBuf) == -1) { 343 jpeg_destroy_decompress(&cinfo); 344 m_bInited = FALSE; 345 return FALSE; 346 } 347 cinfo.image_width = m_OrigWidth; 348 cinfo.image_height = m_OrigHeight; 349 int ret = jpeg_read_header(&cinfo, TRUE); 350 if (ret != JPEG_HEADER_OK) { 351 return FALSE; 352 } 353 if (cinfo.saw_Adobe_marker) { 354 m_bJpegTransform = TRUE; 355 } 356 if (cinfo.num_components == 3 && !m_bJpegTransform) { 357 cinfo.out_color_space = cinfo.jpeg_color_space; 358 } 359 m_OrigWidth = cinfo.image_width; 360 m_OrigHeight = cinfo.image_height; 361 m_OutputWidth = m_OrigWidth; 362 m_OutputHeight = m_OrigHeight; 363 m_nDefaultScaleDenom = cinfo.scale_denom; 364 return TRUE; 365} 366FX_BOOL CCodec_JpegDecoder::Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height, 367 int nComps, FX_BOOL ColorTransform, IFX_JpegProvider* pJP) 368{ 369 if (pJP) { 370 m_pExtProvider = pJP; 371 m_pExtContext = m_pExtProvider->CreateDecoder(src_buf, src_size, width, height, nComps, ColorTransform); 372 return m_pExtContext != NULL; 373 } 374 _JpegScanSOI(src_buf, src_size); 375 m_SrcBuf = src_buf; 376 m_SrcSize = src_size; 377 jerr.error_exit = _error_fatal; 378 jerr.emit_message = _error_do_nothing1; 379 jerr.output_message = _error_do_nothing; 380 jerr.format_message = _error_do_nothing2; 381 jerr.reset_error_mgr = _error_do_nothing; 382 src.init_source = _src_do_nothing; 383 src.term_source = _src_do_nothing; 384 src.skip_input_data = _src_skip_data; 385 src.fill_input_buffer = _src_fill_buffer; 386 src.resync_to_restart = _src_resync; 387 m_bJpegTransform = ColorTransform; 388 if(src_size > 1 && FXSYS_memcmp32(src_buf + src_size - 2, "\xFF\xD9", 2) != 0) { 389 ((FX_LPBYTE)src_buf)[src_size - 2] = 0xFF; 390 ((FX_LPBYTE)src_buf)[src_size - 1] = 0xD9; 391 } 392 m_OutputWidth = m_OrigWidth = width; 393 m_OutputHeight = m_OrigHeight = height; 394 if (!InitDecode()) { 395 return FALSE; 396 } 397 if (cinfo.num_components < nComps) { 398 return FALSE; 399 } 400 if ((int)cinfo.image_width < width) { 401 return FALSE; 402 } 403 m_Pitch = (cinfo.image_width * cinfo.num_components + 3) / 4 * 4; 404 m_pScanlineBuf = FX_Alloc(FX_BYTE, m_Pitch); 405 m_nComps = cinfo.num_components; 406 m_bpc = 8; 407 m_bColorTransformed = FALSE; 408 m_bStarted = FALSE; 409 return TRUE; 410} 411extern "C" { 412 FX_INT32 FX_GetDownsampleRatio(FX_INT32 originWidth, FX_INT32 originHeight, FX_INT32 downsampleWidth, FX_INT32 downsampleHeight) 413 { 414 int iratio_w = originWidth / downsampleWidth; 415 int iratio_h = originHeight / downsampleHeight; 416 int ratio = (iratio_w > iratio_h) ? iratio_h : iratio_w; 417 if (ratio >= 8) { 418 return 8; 419 } else if (ratio >= 4) { 420 return 4; 421 } else if (ratio >= 2) { 422 return 2; 423 } 424 return 1; 425 } 426} 427void CCodec_JpegDecoder::v_DownScale(int dest_width, int dest_height) 428{ 429 if (m_pExtProvider) { 430 m_pExtProvider->DownScale(m_pExtContext, dest_width, dest_height); 431 return; 432 } 433 int old_scale = m_DownScale; 434 m_DownScale = FX_GetDownsampleRatio(m_OrigWidth, m_OrigHeight, dest_width, dest_height); 435 m_OutputWidth = (m_OrigWidth + m_DownScale - 1) / m_DownScale; 436 m_OutputHeight = (m_OrigHeight + m_DownScale - 1) / m_DownScale; 437 m_Pitch = (m_OutputWidth * m_nComps + 3) / 4 * 4; 438 if (old_scale != m_DownScale) { 439 m_NextLine = -1; 440 } 441} 442FX_BOOL CCodec_JpegDecoder::v_Rewind() 443{ 444 if (m_pExtProvider) { 445 return m_pExtProvider->Rewind(m_pExtContext); 446 } 447 if (m_bStarted) { 448 jpeg_destroy_decompress(&cinfo); 449 if (!InitDecode()) { 450 return FALSE; 451 } 452 } 453 if (setjmp(m_JmpBuf) == -1) { 454 return FALSE; 455 } 456 cinfo.scale_denom = m_nDefaultScaleDenom * m_DownScale; 457 m_OutputWidth = (m_OrigWidth + m_DownScale - 1) / m_DownScale; 458 m_OutputHeight = (m_OrigHeight + m_DownScale - 1) / m_DownScale; 459 if (!jpeg_start_decompress(&cinfo)) { 460 jpeg_destroy_decompress(&cinfo); 461 return FALSE; 462 } 463 if ((int)cinfo.output_width > m_OrigWidth) { 464 FXSYS_assert(FALSE); 465 return FALSE; 466 } 467 m_bStarted = TRUE; 468 return TRUE; 469} 470FX_LPBYTE CCodec_JpegDecoder::v_GetNextLine() 471{ 472 if (m_pExtProvider) { 473 return m_pExtProvider->GetNextLine(m_pExtContext); 474 } 475 int nlines = jpeg_read_scanlines(&cinfo, &m_pScanlineBuf, 1); 476 if (nlines < 1) { 477 return NULL; 478 } 479 return m_pScanlineBuf; 480} 481FX_DWORD CCodec_JpegDecoder::GetSrcOffset() 482{ 483 if (m_pExtProvider) { 484 return m_pExtProvider->GetSrcOffset(m_pExtContext); 485 } 486 return (FX_DWORD)(m_SrcSize - src.bytes_in_buffer); 487} 488ICodec_ScanlineDecoder* CCodec_JpegModule::CreateDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size, 489 int width, int height, int nComps, FX_BOOL ColorTransform) 490{ 491 if (src_buf == NULL || src_size == 0) { 492 return NULL; 493 } 494 CCodec_JpegDecoder* pDecoder = new CCodec_JpegDecoder; 495 if (!pDecoder->Create(src_buf, src_size, width, height, nComps, ColorTransform, m_pExtProvider)) { 496 delete pDecoder; 497 return NULL; 498 } 499 return pDecoder; 500} 501FX_BOOL CCodec_JpegModule::LoadInfo(FX_LPCBYTE src_buf, FX_DWORD src_size, int& width, int& height, 502 int& num_components, int& bits_per_components, FX_BOOL& color_transform, 503 FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length) 504{ 505 if (m_pExtProvider) { 506 return m_pExtProvider->LoadInfo(src_buf, src_size, width, height, 507 num_components, bits_per_components, color_transform, 508 icc_buf_ptr, icc_length); 509 } 510 return _JpegLoadInfo(src_buf, src_size, width, height, num_components, bits_per_components, color_transform, icc_buf_ptr, icc_length); 511} 512FX_BOOL CCodec_JpegModule::Encode(const CFX_DIBSource* pSource, FX_LPBYTE& dest_buf, FX_STRSIZE& dest_size, int quality, FX_LPCBYTE icc_buf, FX_DWORD icc_length) 513{ 514 if (m_pExtProvider) { 515 return m_pExtProvider->Encode(pSource, dest_buf, dest_size, quality, icc_buf, icc_length); 516 } 517 if(pSource->GetBPP() < 8 || pSource->GetPalette() != NULL) { 518 ASSERT(pSource->GetBPP() >= 8 && pSource->GetPalette() == NULL); 519 return FALSE; 520 } 521 _JpegEncode(pSource, dest_buf, dest_size, quality, icc_buf, icc_length); 522 return TRUE; 523} 524struct FXJPEG_Context { 525 jmp_buf m_JumpMark; 526 jpeg_decompress_struct m_Info; 527 jpeg_error_mgr m_ErrMgr; 528 jpeg_source_mgr m_SrcMgr; 529 unsigned int m_SkipSize; 530 void* (*m_AllocFunc)(unsigned int); 531 void (*m_FreeFunc)(void*); 532}; 533extern "C" { 534 static void _error_fatal1(j_common_ptr cinfo) 535 { 536 longjmp(((FXJPEG_Context*)cinfo->client_data)->m_JumpMark, -1); 537 } 538}; 539extern "C" { 540 static void _src_skip_data1(struct jpeg_decompress_struct* cinfo, long num) 541 { 542 if (cinfo->src->bytes_in_buffer < (size_t)num) { 543 ((FXJPEG_Context*)cinfo->client_data)->m_SkipSize = (unsigned int)(num - cinfo->src->bytes_in_buffer); 544 cinfo->src->bytes_in_buffer = 0; 545 } else { 546 cinfo->src->next_input_byte += num; 547 cinfo->src->bytes_in_buffer -= num; 548 } 549 } 550}; 551static void* jpeg_alloc_func(unsigned int size) 552{ 553 return FX_Alloc(char, size); 554} 555static void jpeg_free_func(void* p) 556{ 557 FX_Free(p); 558} 559void* CCodec_JpegModule::Start() 560{ 561 if (m_pExtProvider) { 562 return m_pExtProvider->Start(); 563 } 564 FXJPEG_Context* p = (FXJPEG_Context*)FX_Alloc(FX_BYTE, sizeof(FXJPEG_Context)); 565 p->m_AllocFunc = jpeg_alloc_func; 566 p->m_FreeFunc = jpeg_free_func; 567 p->m_ErrMgr.error_exit = _error_fatal1; 568 p->m_ErrMgr.emit_message = _error_do_nothing1; 569 p->m_ErrMgr.output_message = _error_do_nothing; 570 p->m_ErrMgr.format_message = _error_do_nothing2; 571 p->m_ErrMgr.reset_error_mgr = _error_do_nothing; 572 p->m_SrcMgr.init_source = _src_do_nothing; 573 p->m_SrcMgr.term_source = _src_do_nothing; 574 p->m_SrcMgr.skip_input_data = _src_skip_data1; 575 p->m_SrcMgr.fill_input_buffer = _src_fill_buffer; 576 p->m_SrcMgr.resync_to_restart = _src_resync; 577 p->m_Info.client_data = p; 578 p->m_Info.err = &p->m_ErrMgr; 579 if (setjmp(p->m_JumpMark) == -1) { 580 return 0; 581 } 582 jpeg_create_decompress(&p->m_Info); 583 p->m_Info.src = &p->m_SrcMgr; 584 p->m_SkipSize = 0; 585 return p; 586} 587void CCodec_JpegModule::Finish(void* pContext) 588{ 589 if (m_pExtProvider) { 590 m_pExtProvider->Finish(pContext); 591 return; 592 } 593 FXJPEG_Context* p = (FXJPEG_Context*)pContext; 594 jpeg_destroy_decompress(&p->m_Info); 595 p->m_FreeFunc(p); 596} 597void CCodec_JpegModule::Input(void* pContext, const unsigned char* src_buf, FX_DWORD src_size) 598{ 599 if (m_pExtProvider) { 600 m_pExtProvider->Input(pContext, src_buf, src_size); 601 return; 602 } 603 FXJPEG_Context* p = (FXJPEG_Context*)pContext; 604 if (p->m_SkipSize) { 605 if (p->m_SkipSize > src_size) { 606 p->m_SrcMgr.bytes_in_buffer = 0; 607 p->m_SkipSize -= src_size; 608 return; 609 } 610 src_size -= p->m_SkipSize; 611 src_buf += p->m_SkipSize; 612 p->m_SkipSize = 0; 613 } 614 p->m_SrcMgr.next_input_byte = src_buf; 615 p->m_SrcMgr.bytes_in_buffer = src_size; 616} 617int CCodec_JpegModule::ReadHeader(void* pContext, int* width, int* height, int* nComps) 618{ 619 if (m_pExtProvider) { 620 return m_pExtProvider->ReadHeader(pContext, width, height, nComps); 621 } 622 FXJPEG_Context* p = (FXJPEG_Context*)pContext; 623 if (setjmp(p->m_JumpMark) == -1) { 624 return 1; 625 } 626 int ret = jpeg_read_header(&p->m_Info, true); 627 if (ret == JPEG_SUSPENDED) { 628 return 2; 629 } 630 if (ret != JPEG_HEADER_OK) { 631 return 1; 632 } 633 *width = p->m_Info.image_width; 634 *height = p->m_Info.image_height; 635 *nComps = p->m_Info.num_components; 636 return 0; 637} 638FX_BOOL CCodec_JpegModule::StartScanline(void* pContext, int down_scale) 639{ 640 if (m_pExtProvider) { 641 return m_pExtProvider->StartScanline(pContext, down_scale); 642 } 643 FXJPEG_Context* p = (FXJPEG_Context*)pContext; 644 if (setjmp(p->m_JumpMark) == -1) { 645 return FALSE; 646 } 647 p->m_Info.scale_denom = down_scale; 648 return jpeg_start_decompress(&p->m_Info); 649} 650FX_BOOL CCodec_JpegModule::ReadScanline(void* pContext, unsigned char* dest_buf) 651{ 652 if (m_pExtProvider) { 653 return m_pExtProvider->ReadScanline(pContext, dest_buf); 654 } 655 FXJPEG_Context* p = (FXJPEG_Context*)pContext; 656 if (setjmp(p->m_JumpMark) == -1) { 657 return FALSE; 658 } 659 int nlines = jpeg_read_scanlines(&p->m_Info, &dest_buf, 1); 660 return nlines == 1; 661} 662FX_DWORD CCodec_JpegModule::GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr) 663{ 664 if (m_pExtProvider) { 665 return m_pExtProvider->GetAvailInput(pContext, avail_buf_ptr); 666 } 667 if(avail_buf_ptr != NULL) { 668 *avail_buf_ptr = NULL; 669 if(((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer > 0) { 670 *avail_buf_ptr = (FX_LPBYTE)((FXJPEG_Context*)pContext)->m_SrcMgr.next_input_byte; 671 } 672 } 673 return (FX_DWORD)((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer; 674} 675