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