Home | History | Annotate | Download | only in highgui
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 
     42 #include "_highgui.h"
     43 #include "grfmt_jpeg.h"
     44 
     45 // JPEG filter factory
     46 
     47 GrFmtJpeg::GrFmtJpeg()
     48 {
     49     m_sign_len = 3;
     50     m_signature = "\xFF\xD8\xFF";
     51     m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)";
     52 }
     53 
     54 
     55 GrFmtJpeg::~GrFmtJpeg()
     56 {
     57 }
     58 
     59 
     60 GrFmtReader* GrFmtJpeg::NewReader( const char* filename )
     61 {
     62     return new GrFmtJpegReader( filename );
     63 }
     64 
     65 
     66 GrFmtWriter* GrFmtJpeg::NewWriter( const char* filename )
     67 {
     68     return new GrFmtJpegWriter( filename );
     69 }
     70 
     71 
     72 #ifdef HAVE_JPEG
     73 
     74 /****************************************************************************************\
     75     This part of the file implements JPEG codec on base of IJG libjpeg library,
     76     in particular, this is the modified example.doc from libjpeg package.
     77     See otherlibs/_graphics/readme.txt for copyright notice.
     78 \****************************************************************************************/
     79 
     80 #include <stdio.h>
     81 #include <setjmp.h>
     82 
     83 #ifdef WIN32
     84 
     85 #define XMD_H // prevent redefinition of INT32
     86 #undef FAR  // prevent FAR redefinition
     87 
     88 #endif
     89 
     90 #if defined WIN32 && defined __GNUC__
     91 typedef unsigned char boolean;
     92 #endif
     93 
     94 extern "C" {
     95 #include "jpeglib.h"
     96 }
     97 
     98 /////////////////////// Error processing /////////////////////
     99 
    100 typedef struct GrFmtJpegErrorMgr
    101 {
    102     struct jpeg_error_mgr pub;    /* "parent" structure */
    103     jmp_buf setjmp_buffer;        /* jump label */
    104 }
    105 GrFmtJpegErrorMgr;
    106 
    107 
    108 METHODDEF(void)
    109 error_exit( j_common_ptr cinfo )
    110 {
    111     GrFmtJpegErrorMgr* err_mgr = (GrFmtJpegErrorMgr*)(cinfo->err);
    112 
    113     /* Return control to the setjmp point */
    114     longjmp( err_mgr->setjmp_buffer, 1 );
    115 }
    116 
    117 
    118 /////////////////////// GrFmtJpegReader ///////////////////
    119 
    120 
    121 GrFmtJpegReader::GrFmtJpegReader( const char* filename ) : GrFmtReader( filename )
    122 {
    123     m_cinfo = 0;
    124     m_f = 0;
    125 }
    126 
    127 
    128 GrFmtJpegReader::~GrFmtJpegReader()
    129 {
    130 }
    131 
    132 
    133 void  GrFmtJpegReader::Close()
    134 {
    135     if( m_f )
    136     {
    137         fclose( m_f );
    138         m_f = 0;
    139     }
    140 
    141     if( m_cinfo )
    142     {
    143         jpeg_decompress_struct* cinfo = (jpeg_decompress_struct*)m_cinfo;
    144         GrFmtJpegErrorMgr* jerr = (GrFmtJpegErrorMgr*)m_jerr;
    145 
    146         jpeg_destroy_decompress( cinfo );
    147         delete cinfo;
    148         delete jerr;
    149         m_cinfo = 0;
    150         m_jerr = 0;
    151     }
    152     GrFmtReader::Close();
    153 }
    154 
    155 
    156 bool  GrFmtJpegReader::ReadHeader()
    157 {
    158     bool result = false;
    159     Close();
    160 
    161     jpeg_decompress_struct* cinfo = new jpeg_decompress_struct;
    162     GrFmtJpegErrorMgr* jerr = new GrFmtJpegErrorMgr;
    163 
    164     cinfo->err = jpeg_std_error(&jerr->pub);
    165     jerr->pub.error_exit = error_exit;
    166 
    167     m_cinfo = cinfo;
    168     m_jerr = jerr;
    169 
    170     if( setjmp( jerr->setjmp_buffer ) == 0 )
    171     {
    172         jpeg_create_decompress( cinfo );
    173 
    174         m_f = fopen( m_filename, "rb" );
    175         if( m_f )
    176         {
    177             jpeg_stdio_src( cinfo, m_f );
    178             jpeg_read_header( cinfo, TRUE );
    179 
    180             m_width = cinfo->image_width;
    181             m_height = cinfo->image_height;
    182             m_iscolor = cinfo->num_components > 1;
    183 
    184             result = true;
    185         }
    186     }
    187 
    188     if( !result )
    189         Close();
    190 
    191     return result;
    192 }
    193 
    194 /***************************************************************************
    195  * following code is for supporting MJPEG image files
    196  * based on a message of Laurent Pinchart on the video4linux mailing list
    197  ***************************************************************************/
    198 
    199 /* JPEG DHT Segment for YCrCb omitted from MJPEG data */
    200 static
    201 unsigned char my_jpeg_odml_dht[0x1a4] = {
    202     0xff, 0xc4, 0x01, 0xa2,
    203 
    204     0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
    205     0x00, 0x00, 0x00, 0x00, 0x00,
    206     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
    207 
    208     0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    209     0x00, 0x00, 0x00, 0x00, 0x00,
    210     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
    211 
    212     0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
    213     0x04, 0x00, 0x00, 0x01, 0x7d,
    214     0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
    215     0x13, 0x51, 0x61, 0x07,
    216     0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1,
    217     0x15, 0x52, 0xd1, 0xf0,
    218     0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a,
    219     0x25, 0x26, 0x27, 0x28,
    220     0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
    221     0x46, 0x47, 0x48, 0x49,
    222     0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
    223     0x66, 0x67, 0x68, 0x69,
    224     0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85,
    225     0x86, 0x87, 0x88, 0x89,
    226     0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
    227     0xa4, 0xa5, 0xa6, 0xa7,
    228     0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
    229     0xc2, 0xc3, 0xc4, 0xc5,
    230     0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
    231     0xd9, 0xda, 0xe1, 0xe2,
    232     0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
    233     0xf5, 0xf6, 0xf7, 0xf8,
    234     0xf9, 0xfa,
    235 
    236     0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
    237     0x04, 0x00, 0x01, 0x02, 0x77,
    238     0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
    239     0x51, 0x07, 0x61, 0x71,
    240     0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09,
    241     0x23, 0x33, 0x52, 0xf0,
    242     0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
    243     0x18, 0x19, 0x1a, 0x26,
    244     0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
    245     0x45, 0x46, 0x47, 0x48,
    246     0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
    247     0x65, 0x66, 0x67, 0x68,
    248     0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
    249     0x84, 0x85, 0x86, 0x87,
    250     0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
    251     0xa2, 0xa3, 0xa4, 0xa5,
    252     0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
    253     0xb9, 0xba, 0xc2, 0xc3,
    254     0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
    255     0xd7, 0xd8, 0xd9, 0xda,
    256     0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
    257     0xf5, 0xf6, 0xf7, 0xf8,
    258     0xf9, 0xfa
    259 };
    260 
    261 /*
    262  * Parse the DHT table.
    263  * This code comes from jpeg6b (jdmarker.c).
    264  */
    265 static
    266 int my_jpeg_load_dht (struct jpeg_decompress_struct *info, unsigned char *dht,
    267               JHUFF_TBL *ac_tables[], JHUFF_TBL *dc_tables[])
    268 {
    269     unsigned int length = (dht[2] << 8) + dht[3] - 2;
    270     unsigned int pos = 4;
    271     unsigned int count, i;
    272     int index;
    273 
    274     JHUFF_TBL **hufftbl;
    275     unsigned char bits[17];
    276     unsigned char huffval[256];
    277 
    278     while (length > 16)
    279     {
    280        bits[0] = 0;
    281        index = dht[pos++];
    282        count = 0;
    283        for (i = 1; i <= 16; ++i)
    284        {
    285            bits[i] = dht[pos++];
    286            count += bits[i];
    287        }
    288        length -= 17;
    289 
    290        if (count > 256 || count > length)
    291            return -1;
    292 
    293        for (i = 0; i < count; ++i)
    294            huffval[i] = dht[pos++];
    295        length -= count;
    296 
    297        if (index & 0x10)
    298        {
    299            index -= 0x10;
    300            hufftbl = &ac_tables[index];
    301        }
    302        else
    303            hufftbl = &dc_tables[index];
    304 
    305        if (index < 0 || index >= NUM_HUFF_TBLS)
    306            return -1;
    307 
    308        if (*hufftbl == NULL)
    309            *hufftbl = jpeg_alloc_huff_table ((j_common_ptr)info);
    310        if (*hufftbl == NULL)
    311            return -1;
    312 
    313        memcpy ((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits);
    314        memcpy ((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval);
    315     }
    316 
    317     if (length != 0)
    318        return -1;
    319 
    320     return 0;
    321 }
    322 
    323 /***************************************************************************
    324  * end of code for supportting MJPEG image files
    325  * based on a message of Laurent Pinchart on the video4linux mailing list
    326  ***************************************************************************/
    327 
    328 bool  GrFmtJpegReader::ReadData( uchar* data, int step, int color )
    329 {
    330     bool result = false;
    331 
    332     color = color > 0 || (m_iscolor && color < 0);
    333 
    334     if( m_cinfo && m_jerr && m_width && m_height )
    335     {
    336         jpeg_decompress_struct* cinfo = (jpeg_decompress_struct*)m_cinfo;
    337         GrFmtJpegErrorMgr* jerr = (GrFmtJpegErrorMgr*)m_jerr;
    338         JSAMPARRAY buffer = 0;
    339 
    340         if( setjmp( jerr->setjmp_buffer ) == 0 )
    341         {
    342             /* check if this is a mjpeg image format */
    343             if ( cinfo->ac_huff_tbl_ptrs[0] == NULL &&
    344                 cinfo->ac_huff_tbl_ptrs[1] == NULL &&
    345                 cinfo->dc_huff_tbl_ptrs[0] == NULL &&
    346                 cinfo->dc_huff_tbl_ptrs[1] == NULL )
    347             {
    348                 /* yes, this is a mjpeg image format, so load the correct
    349                 huffman table */
    350                 my_jpeg_load_dht( cinfo,
    351                     my_jpeg_odml_dht,
    352                     cinfo->ac_huff_tbl_ptrs,
    353                     cinfo->dc_huff_tbl_ptrs );
    354             }
    355 
    356             if( color > 0 || (m_iscolor && color < 0) )
    357             {
    358                 color = 1;
    359                 if( cinfo->num_components != 4 )
    360                 {
    361                     cinfo->out_color_space = JCS_RGB;
    362                     cinfo->out_color_components = 3;
    363                 }
    364                 else
    365                 {
    366                     cinfo->out_color_space = JCS_CMYK;
    367                     cinfo->out_color_components = 4;
    368                 }
    369             }
    370             else
    371             {
    372                 color = 0;
    373                 if( cinfo->num_components != 4 )
    374                 {
    375                     cinfo->out_color_space = JCS_GRAYSCALE;
    376                     cinfo->out_color_components = 1;
    377                 }
    378                 else
    379                 {
    380                     cinfo->out_color_space = JCS_CMYK;
    381                     cinfo->out_color_components = 4;
    382                 }
    383             }
    384 
    385             jpeg_start_decompress( cinfo );
    386 
    387             buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo,
    388                                               JPOOL_IMAGE, m_width*4, 1 );
    389 
    390             for( ; m_height--; data += step )
    391             {
    392                 jpeg_read_scanlines( cinfo, buffer, 1 );
    393                 if( color )
    394                 {
    395                     if( cinfo->out_color_components == 3 )
    396                         icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
    397                     else
    398                         icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
    399                 }
    400                 else
    401                 {
    402                     if( cinfo->out_color_components == 1 )
    403                         memcpy( data, buffer[0], m_width );
    404                     else
    405                         icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) );
    406                 }
    407             }
    408             result = true;
    409             jpeg_finish_decompress( cinfo );
    410         }
    411     }
    412 
    413     Close();
    414     return result;
    415 }
    416 
    417 
    418 /////////////////////// GrFmtJpegWriter ///////////////////
    419 
    420 GrFmtJpegWriter::GrFmtJpegWriter( const char* filename ) : GrFmtWriter( filename )
    421 {
    422 }
    423 
    424 
    425 GrFmtJpegWriter::~GrFmtJpegWriter()
    426 {
    427 }
    428 
    429 
    430 bool  GrFmtJpegWriter::WriteImage( const uchar* data, int step,
    431                                    int width, int height, int /*depth*/, int _channels )
    432 {
    433     const int default_quality = 95;
    434     struct jpeg_compress_struct cinfo;
    435     GrFmtJpegErrorMgr jerr;
    436 
    437     bool result = false;
    438     FILE* f = 0;
    439     int channels = _channels > 1 ? 3 : 1;
    440     uchar* buffer = 0; // temporary buffer for row flipping
    441 
    442     cinfo.err = jpeg_std_error(&jerr.pub);
    443     jerr.pub.error_exit = error_exit;
    444 
    445     if( setjmp( jerr.setjmp_buffer ) == 0 )
    446     {
    447         jpeg_create_compress(&cinfo);
    448         f = fopen( m_filename, "wb" );
    449 
    450         if( f )
    451         {
    452             jpeg_stdio_dest( &cinfo, f );
    453 
    454             cinfo.image_width = width;
    455             cinfo.image_height = height;
    456             cinfo.input_components = channels;
    457             cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE;
    458 
    459             jpeg_set_defaults( &cinfo );
    460             jpeg_set_quality( &cinfo, default_quality,
    461                               TRUE /* limit to baseline-JPEG values */ );
    462             jpeg_start_compress( &cinfo, TRUE );
    463 
    464             if( channels > 1 )
    465                 buffer = new uchar[width*channels];
    466 
    467             for( ; height--; data += step )
    468             {
    469                 uchar* ptr = (uchar*)data;
    470 
    471                 if( _channels == 3 )
    472                 {
    473                     icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) );
    474                     ptr = buffer;
    475                 }
    476                 else if( _channels == 4 )
    477                 {
    478                     icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 );
    479                     ptr = buffer;
    480                 }
    481 
    482                 jpeg_write_scanlines( &cinfo, &ptr, 1 );
    483             }
    484 
    485             jpeg_finish_compress( &cinfo );
    486             result = true;
    487         }
    488     }
    489 
    490     if(f) fclose(f);
    491     jpeg_destroy_compress( &cinfo );
    492 
    493     delete[] buffer;
    494     return result;
    495 }
    496 
    497 #else
    498 
    499 //////////////////////  JPEG-oriented two-level bitstream ////////////////////////
    500 
    501 RJpegBitStream::RJpegBitStream()
    502 {
    503 }
    504 
    505 RJpegBitStream::~RJpegBitStream()
    506 {
    507     Close();
    508 }
    509 
    510 
    511 bool  RJpegBitStream::Open( const char* filename )
    512 {
    513     Close();
    514     Allocate();
    515 
    516     m_is_opened = m_low_strm.Open( filename );
    517     if( m_is_opened ) SetPos(0);
    518     return m_is_opened;
    519 }
    520 
    521 
    522 void  RJpegBitStream::Close()
    523 {
    524     m_low_strm.Close();
    525     m_is_opened = false;
    526 }
    527 
    528 
    529 void  RJpegBitStream::ReadBlock()
    530 {
    531     uchar* end = m_start + m_block_size;
    532     uchar* current = m_start;
    533 
    534     if( setjmp( m_low_strm.JmpBuf()) == 0 )
    535     {
    536         int sz = m_unGetsize;
    537         memmove( current - sz, m_end - sz, sz );
    538         while( current < end )
    539         {
    540             int val = m_low_strm.GetByte();
    541             if( val != 0xff )
    542             {
    543                 *current++ = (uchar)val;
    544             }
    545             else
    546             {
    547                 val = m_low_strm.GetByte();
    548                 if( val == 0 )
    549                     *current++ = 0xFF;
    550                 else if( !(0xD0 <= val && val <= 0xD7) )
    551                 {
    552                     m_low_strm.SetPos( m_low_strm.GetPos() - 2 );
    553                     goto fetch_end;
    554                 }
    555             }
    556         }
    557 fetch_end: ;
    558     }
    559     else
    560     {
    561         if( current == m_start && m_jmp_set )
    562             longjmp( m_jmp_buf, RBS_THROW_EOS );
    563     }
    564     m_current = m_start;
    565     m_end = m_start + (((current - m_start) + 3) & -4);
    566     if( !bsIsBigEndian() )
    567         bsBSwapBlock( m_start, m_end );
    568 }
    569 
    570 
    571 void  RJpegBitStream::Flush()
    572 {
    573     m_end = m_start + m_block_size;
    574     m_current = m_end - 4;
    575     m_bit_idx = 0;
    576 }
    577 
    578 void  RJpegBitStream::AlignOnByte()
    579 {
    580     m_bit_idx &= -8;
    581 }
    582 
    583 int  RJpegBitStream::FindMarker()
    584 {
    585     int code = m_low_strm.GetWord();
    586     while( (code & 0xFF00) != 0xFF00 || (code == 0xFFFF || code == 0xFF00 ))
    587     {
    588         code = ((code&255) << 8) | m_low_strm.GetByte();
    589     }
    590     return code;
    591 }
    592 
    593 
    594 /****************************** JPEG (JFIF) reader ***************************/
    595 
    596 // zigzag & IDCT prescaling (AAN algorithm) tables
    597 static const uchar zigzag[] =
    598 {
    599   0,  8,  1,  2,  9, 16, 24, 17, 10,  3,  4, 11, 18, 25, 32, 40,
    600  33, 26, 19, 12,  5,  6, 13, 20, 27, 34, 41, 48, 56, 49, 42, 35,
    601  28, 21, 14,  7, 15, 22, 29, 36, 43, 50, 57, 58, 51, 44, 37, 30,
    602  23, 31, 38, 45, 52, 59, 60, 53, 46, 39, 47, 54, 61, 62, 55, 63,
    603  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63
    604 };
    605 
    606 
    607 static const int idct_prescale[] =
    608 {
    609     16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
    610     22725, 31521, 29692, 26722, 22725, 17855, 12299,  6270,
    611     21407, 29692, 27969, 25172, 21407, 16819, 11585,  5906,
    612     19266, 26722, 25172, 22654, 19266, 15137, 10426,  5315,
    613     16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
    614     12873, 17855, 16819, 15137, 12873, 10114,  6967,  3552,
    615      8867, 12299, 11585, 10426,  8867,  6967,  4799,  2446,
    616      4520,  6270,  5906,  5315,  4520,  3552,  2446,  1247
    617 };
    618 
    619 
    620 #define fixb         14
    621 #define fix(x, n)    (int)((x)*(1 << (n)) + .5)
    622 #define fix1(x, n)   (x)
    623 #define fixmul(x)    (x)
    624 
    625 #define C0_707     fix( 0.707106781f, fixb )
    626 #define C0_924     fix( 0.923879533f, fixb )
    627 #define C0_541     fix( 0.541196100f, fixb )
    628 #define C0_382     fix( 0.382683432f, fixb )
    629 #define C1_306     fix( 1.306562965f, fixb )
    630 
    631 #define C1_082     fix( 1.082392200f, fixb )
    632 #define C1_414     fix( 1.414213562f, fixb )
    633 #define C1_847     fix( 1.847759065f, fixb )
    634 #define C2_613     fix( 2.613125930f, fixb )
    635 
    636 #define fixc       12
    637 #define b_cb       fix( 1.772, fixc )
    638 #define g_cb      -fix( 0.34414, fixc )
    639 #define g_cr      -fix( 0.71414, fixc )
    640 #define r_cr       fix( 1.402, fixc )
    641 
    642 #define y_r        fix( 0.299, fixc )
    643 #define y_g        fix( 0.587, fixc )
    644 #define y_b        fix( 0.114, fixc )
    645 
    646 #define cb_r      -fix( 0.1687, fixc )
    647 #define cb_g      -fix( 0.3313, fixc )
    648 #define cb_b       fix( 0.5,    fixc )
    649 
    650 #define cr_r       fix( 0.5,    fixc )
    651 #define cr_g      -fix( 0.4187, fixc )
    652 #define cr_b      -fix( 0.0813, fixc )
    653 
    654 
    655 // IDCT without prescaling
    656 static void aan_idct8x8( int *src, int *dst, int step )
    657 {
    658     int   workspace[64], *work = workspace;
    659     int   i;
    660 
    661     /* Pass 1: process rows */
    662     for( i = 8; i > 0; i--, src += 8, work += 8 )
    663     {
    664         /* Odd part */
    665         int  x0 = src[5], x1 = src[3];
    666         int  x2 = src[1], x3 = src[7];
    667 
    668         int  x4 = x0 + x1; x0 -= x1;
    669 
    670         x1 = x2 + x3; x2 -= x3;
    671         x3 = x1 + x4; x1 -= x4;
    672 
    673         x4 = (x0 + x2)*C1_847;
    674         x0 = descale( x4 - x0*C2_613, fixb);
    675         x2 = descale( x2*C1_082 - x4, fixb);
    676         x1 = descale( x1*C1_414, fixb);
    677 
    678         x0 -= x3;
    679         x1 -= x0;
    680         x2 += x1;
    681 
    682         work[7] = x3; work[6] = x0;
    683         work[5] = x1; work[4] = x2;
    684 
    685         /* Even part */
    686         x2 = src[2]; x3 = src[6];
    687         x0 = src[0]; x1 = src[4];
    688 
    689         x4 = x2 + x3;
    690         x2 = descale((x2-x3)*C1_414, fixb) - x4;
    691 
    692         x3 = x0 + x1; x0 -= x1;
    693         x1 = x3 + x4; x3 -= x4;
    694         x4 = x0 + x2; x0 -= x2;
    695 
    696         x2 = work[7];
    697         x1 -= x2; x2 = 2*x2 + x1;
    698         work[7] = x1; work[0] = x2;
    699 
    700         x2 = work[6];
    701         x1 = x4 + x2; x4 -= x2;
    702         work[1] = x1; work[6] = x4;
    703 
    704         x1 = work[5]; x2 = work[4];
    705         x4 = x0 + x1; x0 -= x1;
    706         x1 = x3 + x2; x3 -= x2;
    707 
    708         work[2] = x4; work[5] = x0;
    709         work[3] = x3; work[4] = x1;
    710     }
    711 
    712     /* Pass 2: process columns */
    713     work = workspace;
    714     for( i = 8; i > 0; i--, dst += step, work++ )
    715     {
    716         /* Odd part */
    717         int  x0 = work[8*5], x1 = work[8*3];
    718         int  x2 = work[8*1], x3 = work[8*7];
    719 
    720         int  x4 = x0 + x1; x0 -= x1;
    721         x1 = x2 + x3; x2 -= x3;
    722         x3 = x1 + x4; x1 -= x4;
    723 
    724         x4 = (x0 + x2)*C1_847;
    725         x0 = descale( x4 - x0*C2_613, fixb);
    726         x2 = descale( x2*C1_082 - x4, fixb);
    727         x1 = descale( x1*C1_414, fixb);
    728 
    729         x0 -= x3;
    730         x1 -= x0;
    731         x2 += x1;
    732 
    733         dst[7] = x3; dst[6] = x0;
    734         dst[5] = x1; dst[4] = x2;
    735 
    736         /* Even part */
    737         x2 = work[8*2]; x3 = work[8*6];
    738         x0 = work[8*0]; x1 = work[8*4];
    739 
    740         x4 = x2 + x3;
    741         x2 = descale((x2-x3)*C1_414, fixb) - x4;
    742 
    743         x3 = x0 + x1; x0 -= x1;
    744         x1 = x3 + x4; x3 -= x4;
    745         x4 = x0 + x2; x0 -= x2;
    746 
    747         x2 = dst[7];
    748         x1 -= x2; x2 = 2*x2 + x1;
    749         x1 = descale(x1,3);
    750         x2 = descale(x2,3);
    751 
    752         dst[7] = x1; dst[0] = x2;
    753 
    754         x2 = dst[6];
    755         x1 = descale(x4 + x2,3);
    756         x4 = descale(x4 - x2,3);
    757         dst[1] = x1; dst[6] = x4;
    758 
    759         x1 = dst[5]; x2 = dst[4];
    760 
    761         x4 = descale(x0 + x1,3);
    762         x0 = descale(x0 - x1,3);
    763         x1 = descale(x3 + x2,3);
    764         x3 = descale(x3 - x2,3);
    765 
    766         dst[2] = x4; dst[5] = x0;
    767         dst[3] = x3; dst[4] = x1;
    768     }
    769 }
    770 
    771 
    772 static const int max_dec_htable_size = 1 << 12;
    773 static const int first_table_bits = 9;
    774 
    775 GrFmtJpegReader::GrFmtJpegReader( const char* filename ) : GrFmtReader( filename )
    776 {
    777     m_planes= -1;
    778     m_offset= -1;
    779 
    780     int i;
    781     for( i = 0; i < 4; i++ )
    782     {
    783         m_td[i] = new short[max_dec_htable_size];
    784         m_ta[i] = new short[max_dec_htable_size];
    785     }
    786 }
    787 
    788 
    789 GrFmtJpegReader::~GrFmtJpegReader()
    790 {
    791     for( int i = 0; i < 4; i++ )
    792     {
    793         delete[] m_td[i];
    794         m_td[i] = 0;
    795         delete[] m_ta[i];
    796         m_ta[i] = 0;
    797     }
    798 }
    799 
    800 
    801 void  GrFmtJpegReader::Close()
    802 {
    803     m_strm.Close();
    804     GrFmtReader::Close();
    805 }
    806 
    807 
    808 bool GrFmtJpegReader::ReadHeader()
    809 {
    810     char buffer[16];
    811     int  i;
    812     bool result = false, is_sof = false,
    813          is_qt = false, is_ht = false, is_sos = false;
    814 
    815     assert( strlen(m_filename) != 0 );
    816     if( !m_strm.Open( m_filename )) return false;
    817 
    818     memset( m_is_tq, 0, sizeof(m_is_tq));
    819     memset( m_is_td, 0, sizeof(m_is_td));
    820     memset( m_is_ta, 0, sizeof(m_is_ta));
    821     m_MCUs = 0;
    822 
    823     if( setjmp( m_strm.JmpBuf()) == 0 )
    824     {
    825         RMByteStream& lstrm = m_strm.m_low_strm;
    826 
    827         lstrm.Skip( 2 ); // skip SOI marker
    828 
    829         for(;;)
    830         {
    831             int marker = m_strm.FindMarker() & 255;
    832 
    833             // check for standalone markers
    834             if( marker != 0xD8 /* SOI */ && marker != 0xD9 /* EOI */ &&
    835                 marker != 0x01 /* TEM */ && !( 0xD0 <= marker && marker <= 0xD7 ))
    836             {
    837                 int pos    = lstrm.GetPos();
    838                 int length = lstrm.GetWord();
    839 
    840                 switch( marker )
    841                 {
    842                 case 0xE0: // APP0
    843                     lstrm.GetBytes( buffer, 5 );
    844                     if( strcmp(buffer, "JFIF") == 0 ) // JFIF identification
    845                     {
    846                         m_version = lstrm.GetWord();
    847                         //is_jfif = true;
    848                     }
    849                     break;
    850 
    851                 case 0xC0: // SOF0
    852                     m_precision = lstrm.GetByte();
    853                     m_height = lstrm.GetWord();
    854                     m_width = lstrm.GetWord();
    855                     m_planes = lstrm.GetByte();
    856 
    857                     if( m_width == 0 || m_height == 0 || // DNL not supported
    858                        (m_planes != 1 && m_planes != 3)) goto parsing_end;
    859 
    860                     m_iscolor = m_planes == 3;
    861 
    862                     memset( m_ci, -1, sizeof(m_ci));
    863 
    864                     for( i = 0; i < m_planes; i++ )
    865                     {
    866                         int idx = lstrm.GetByte();
    867 
    868                         if( idx < 1 || idx > m_planes ) // wrong index
    869                         {
    870                             idx = i+1; // hack
    871                         }
    872                         cmp_info& ci = m_ci[idx-1];
    873 
    874                         if( ci.tq > 0 /* duplicated description */) goto parsing_end;
    875 
    876                         ci.h = (char)lstrm.GetByte();
    877                         ci.v = (char)(ci.h & 15);
    878                         ci.h >>= 4;
    879                         ci.tq = (char)lstrm.GetByte();
    880                         if( !((ci.h == 1 || ci.h == 2 || ci.h == 4) &&
    881                               (ci.v == 1 || ci.v == 2 || ci.v == 4) &&
    882                               ci.tq < 3) ||
    883                             // chroma mcu-parts should have equal sizes and
    884                             // be non greater then luma sizes
    885                             !( i != 2 || (ci.h == m_ci[1].h && ci.v == m_ci[1].v &&
    886                                           ci.h <= m_ci[0].h && ci.v <= m_ci[0].v)))
    887                             goto parsing_end;
    888                     }
    889                     is_sof = true;
    890                     m_type = marker - 0xC0;
    891                     break;
    892 
    893                 case 0xDB: // DQT
    894                     if( !LoadQuantTables( length )) goto parsing_end;
    895                     is_qt = true;
    896                     break;
    897 
    898                 case 0xC4: // DHT
    899                     if( !LoadHuffmanTables( length )) goto parsing_end;
    900                     is_ht = true;
    901                     break;
    902 
    903                 case 0xDA: // SOS
    904                     is_sos = true;
    905                     m_offset = pos - 2;
    906                     goto parsing_end;
    907 
    908                 case 0xDD: // DRI
    909                     m_MCUs = lstrm.GetWord();
    910                     break;
    911                 }
    912                 lstrm.SetPos( pos + length );
    913             }
    914         }
    915 parsing_end: ;
    916     }
    917 
    918     result = /*is_jfif &&*/ is_sof && is_qt && is_ht && is_sos;
    919     if( !result )
    920     {
    921         m_width = m_height = -1;
    922         m_offset = -1;
    923         m_strm.Close();
    924     }
    925     return result;
    926 }
    927 
    928 
    929 bool GrFmtJpegReader::LoadQuantTables( int length )
    930 {
    931     uchar buffer[128];
    932     int  i, tq_size;
    933 
    934     RMByteStream& lstrm = m_strm.m_low_strm;
    935     length -= 2;
    936 
    937     while( length > 0 )
    938     {
    939         int tq = lstrm.GetByte();
    940         int size = tq >> 4;
    941         tq &= 15;
    942 
    943         tq_size = (64<<size) + 1;
    944         if( tq > 3 || size > 1 || length < tq_size ) return false;
    945         length -= tq_size;
    946 
    947         lstrm.GetBytes( buffer, tq_size - 1 );
    948 
    949         if( size == 0 ) // 8 bit quant factors
    950         {
    951             for( i = 0; i < 64; i++ )
    952             {
    953                 int idx = zigzag[i];
    954                 m_tq[tq][idx] = buffer[i] * 16 * idct_prescale[idx];
    955             }
    956         }
    957         else // 16 bit quant factors
    958         {
    959             for( i = 0; i < 64; i++ )
    960             {
    961                 int idx = zigzag[i];
    962                 m_tq[tq][idx] = ((unsigned short*)buffer)[i] * idct_prescale[idx];
    963             }
    964         }
    965         m_is_tq[tq] = true;
    966     }
    967 
    968     return true;
    969 }
    970 
    971 
    972 bool GrFmtJpegReader::LoadHuffmanTables( int length )
    973 {
    974     const int max_bits = 16;
    975     uchar buffer[1024];
    976     int  buffer2[1024];
    977 
    978     int  i, ht_size;
    979     RMByteStream& lstrm = m_strm.m_low_strm;
    980     length -= 2;
    981 
    982     while( length > 0 )
    983     {
    984         int t = lstrm.GetByte();
    985         int hclass = t >> 4;
    986         t &= 15;
    987 
    988         if( t > 3 || hclass > 1 || length < 17 ) return false;
    989         length -= 17;
    990 
    991         lstrm.GetBytes( buffer, max_bits );
    992         for( i = 0, ht_size = 0; i < max_bits; i++ ) ht_size += buffer[i];
    993 
    994         if( length < ht_size ) return false;
    995         length -= ht_size;
    996 
    997         lstrm.GetBytes( buffer + max_bits, ht_size );
    998 
    999         if( !::bsCreateDecodeHuffmanTable(
   1000                   ::bsCreateSourceHuffmanTable(
   1001                         buffer, buffer2, max_bits, first_table_bits ),
   1002                         hclass == 0 ? m_td[t] : m_ta[t],
   1003                         max_dec_htable_size )) return false;
   1004         if( hclass == 0 )
   1005             m_is_td[t] = true;
   1006         else
   1007             m_is_ta[t] = true;
   1008     }
   1009     return true;
   1010 }
   1011 
   1012 
   1013 bool GrFmtJpegReader::ReadData( uchar* data, int step, int color )
   1014 {
   1015     if( m_offset < 0 || !m_strm.IsOpened())
   1016         return false;
   1017 
   1018     if( setjmp( m_strm.JmpBuf()) == 0 )
   1019     {
   1020         RMByteStream& lstrm = m_strm.m_low_strm;
   1021         lstrm.SetPos( m_offset );
   1022 
   1023         for(;;)
   1024         {
   1025             int marker = m_strm.FindMarker() & 255;
   1026 
   1027             if( marker == 0xD8 /* SOI */ || marker == 0xD9 /* EOI */ )
   1028                 goto decoding_end;
   1029 
   1030             // check for standalone markers
   1031             if( marker != 0x01 /* TEM */ && !( 0xD0 <= marker && marker <= 0xD7 ))
   1032             {
   1033                 int pos    = lstrm.GetPos();
   1034                 int length = lstrm.GetWord();
   1035 
   1036                 switch( marker )
   1037                 {
   1038                 case 0xC4: // DHT
   1039                     if( !LoadHuffmanTables( length )) goto decoding_end;
   1040                     break;
   1041 
   1042                 case 0xDA: // SOS
   1043                     // read scan header
   1044                     {
   1045                         int idx[3] = { -1, -1, -1 };
   1046                         int i, ns = lstrm.GetByte();
   1047                         int sum = 0, a; // spectral selection & approximation
   1048 
   1049                         if( ns != m_planes ) goto decoding_end;
   1050                         for( i = 0; i < ns; i++ )
   1051                         {
   1052                             int td, ta, c = lstrm.GetByte() - 1;
   1053                             if( c < 0 || m_planes <= c )
   1054                             {
   1055                                 c = i; // hack
   1056                             }
   1057 
   1058                             if( idx[c] != -1 ) goto decoding_end;
   1059                             idx[i] = c;
   1060                             td = lstrm.GetByte();
   1061                             ta = td & 15;
   1062                             td >>= 4;
   1063                             if( !(ta <= 3 && m_is_ta[ta] &&
   1064                                   td <= 3 && m_is_td[td] &&
   1065                                   m_is_tq[m_ci[c].tq]) )
   1066                                 goto decoding_end;
   1067 
   1068                             m_ci[c].td = (char)td;
   1069                             m_ci[c].ta = (char)ta;
   1070 
   1071                             sum += m_ci[c].h*m_ci[c].v;
   1072                         }
   1073 
   1074                         if( sum > 10 ) goto decoding_end;
   1075 
   1076                         m_ss = lstrm.GetByte();
   1077                         m_se = lstrm.GetByte();
   1078 
   1079                         a = lstrm.GetByte();
   1080                         m_al = a & 15;
   1081                         m_ah = a >> 4;
   1082 
   1083                         ProcessScan( idx, ns, data, step, color );
   1084                         goto decoding_end; // only single scan case is supported now
   1085                     }
   1086 
   1087                     //m_offset = pos - 2;
   1088                     //break;
   1089 
   1090                 case 0xDD: // DRI
   1091                     m_MCUs = lstrm.GetWord();
   1092                     break;
   1093                 }
   1094 
   1095                 if( marker != 0xDA ) lstrm.SetPos( pos + length );
   1096             }
   1097         }
   1098 decoding_end: ;
   1099     }
   1100 
   1101     return true;
   1102 }
   1103 
   1104 
   1105 void  GrFmtJpegReader::ResetDecoder()
   1106 {
   1107     m_ci[0].dc_pred = m_ci[1].dc_pred = m_ci[2].dc_pred = 0;
   1108 }
   1109 
   1110 void  GrFmtJpegReader::ProcessScan( int* idx, int ns, uchar* data, int step, int color )
   1111 {
   1112     int   i, s = 0, mcu, x1 = 0, y1 = 0;
   1113     int   temp[64];
   1114     int   blocks[10][64];
   1115     int   pos[3], h[3], v[3];
   1116     int   x_shift = 0, y_shift = 0;
   1117     int   nch = color ? 3 : 1;
   1118 
   1119     assert( ns == m_planes && m_ss == 0 && m_se == 63 &&
   1120             m_al == 0 && m_ah == 0 ); // sequental & single scan
   1121 
   1122     assert( idx[0] == 0 && (ns ==1 || (idx[1] == 1 && idx[2] == 2)));
   1123 
   1124     for( i = 0; i < ns; i++ )
   1125     {
   1126         int c = idx[i];
   1127         h[c] = m_ci[c].h*8;
   1128         v[c] = m_ci[c].v*8;
   1129         pos[c] = s >> 6;
   1130         s += h[c]*v[c];
   1131     }
   1132 
   1133     if( ns == 3 )
   1134     {
   1135         x_shift = h[0]/(h[1]*2);
   1136         y_shift = v[0]/(v[1]*2);
   1137     }
   1138 
   1139     m_strm.Flush();
   1140     ResetDecoder();
   1141 
   1142     for( mcu = 0;; mcu++ )
   1143     {
   1144         int  x2, y2, x, y, xc;
   1145         int* cmp;
   1146         uchar* data1;
   1147 
   1148         if( mcu == m_MCUs && m_MCUs != 0 )
   1149         {
   1150             ResetDecoder();
   1151             m_strm.AlignOnByte();
   1152             mcu = 0;
   1153         }
   1154 
   1155         // Get mcu
   1156         for( i = 0; i < ns; i++ )
   1157         {
   1158             int  c = idx[i];
   1159             cmp = blocks[pos[c]];
   1160             for( y = 0; y < v[c]; y += 8, cmp += h[c]*8 )
   1161                 for( x = 0; x < h[c]; x += 8 )
   1162                 {
   1163                     GetBlock( temp, c );
   1164                     if( i < (color ? 3 : 1))
   1165                     {
   1166                         aan_idct8x8( temp, cmp + x, h[c] );
   1167                     }
   1168                 }
   1169         }
   1170 
   1171         y2 = v[0];
   1172         x2 = h[0];
   1173 
   1174         if( y1 + y2 > m_height ) y2 = m_height - y1;
   1175         if( x1 + x2 > m_width ) x2 = m_width - x1;
   1176 
   1177         cmp = blocks[0];
   1178         data1 = data + x1*nch;
   1179 
   1180         if( ns == 1 )
   1181             for( y = 0; y < y2; y++, data1 += step, cmp += h[0] )
   1182             {
   1183                 if( color )
   1184                 {
   1185                     for( x = 0; x < x2; x++ )
   1186                     {
   1187                         int val = descale( cmp[x] + 128*4, 2 );
   1188                         data1[x*3] = data1[x*3 + 1] = data1[x*3 + 2] = saturate( val );
   1189                     }
   1190                 }
   1191                 else
   1192                 {
   1193                     for( x = 0; x < x2; x++ )
   1194                     {
   1195                         int val = descale( cmp[x] + 128*4, 2 );
   1196                         data1[x] = saturate( val );
   1197                     }
   1198                 }
   1199             }
   1200         else
   1201         {
   1202             for( y = 0; y < y2; y++, data1 += step, cmp += h[0] )
   1203             {
   1204                 if( color )
   1205                 {
   1206                     int  shift = h[1]*(y >> y_shift);
   1207                     int* cmpCb = blocks[pos[1]] + shift;
   1208                     int* cmpCr = blocks[pos[2]] + shift;
   1209                     x = 0;
   1210                     if( x_shift == 0 )
   1211                     {
   1212                         for( ; x < x2; x++ )
   1213                         {
   1214                             int Y  = (cmp[x] + 128*4) << fixc;
   1215                             int Cb = cmpCb[x];
   1216                             int Cr = cmpCr[x];
   1217                             int t = (Y + Cb*b_cb) >> (fixc + 2);
   1218                             data1[x*3] = saturate(t);
   1219                             t = (Y + Cb*g_cb + Cr*g_cr) >> (fixc + 2);
   1220                             data1[x*3 + 1] = saturate(t);
   1221                             t = (Y + Cr*r_cr) >> (fixc + 2);
   1222                             data1[x*3 + 2] = saturate(t);
   1223                         }
   1224                     }
   1225                     else if( x_shift == 1 )
   1226                     {
   1227                         for( xc = 0; x <= x2 - 2; x += 2, xc++ )
   1228                         {
   1229                             int Y  = (cmp[x] + 128*4) << fixc;
   1230                             int Cb = cmpCb[xc];
   1231                             int Cr = cmpCr[xc];
   1232                             int t = (Y + Cb*b_cb) >> (fixc + 2);
   1233                             data1[x*3] = saturate(t);
   1234                             t = (Y + Cb*g_cb + Cr*g_cr) >> (fixc + 2);
   1235                             data1[x*3 + 1] = saturate(t);
   1236                             t = (Y + Cr*r_cr) >> (fixc + 2);
   1237                             data1[x*3 + 2] = saturate(t);
   1238                             Y = (cmp[x+1] + 128*4) << fixc;
   1239                             t = (Y + Cb*b_cb) >> (fixc + 2);
   1240                             data1[x*3 + 3] = saturate(t);
   1241                             t = (Y + Cb*g_cb + Cr*g_cr) >> (fixc + 2);
   1242                             data1[x*3 + 4] = saturate(t);
   1243                             t = (Y + Cr*r_cr) >> (fixc + 2);
   1244                             data1[x*3 + 5] = saturate(t);
   1245                         }
   1246                     }
   1247                     for( ; x < x2; x++ )
   1248                     {
   1249                         int Y  = (cmp[x] + 128*4) << fixc;
   1250                         int Cb = cmpCb[x >> x_shift];
   1251                         int Cr = cmpCr[x >> x_shift];
   1252                         int t = (Y + Cb*b_cb) >> (fixc + 2);
   1253                         data1[x*3] = saturate(t);
   1254                         t = (Y + Cb*g_cb + Cr*g_cr) >> (fixc + 2);
   1255                         data1[x*3 + 1] = saturate(t);
   1256                         t = (Y + Cr*r_cr) >> (fixc + 2);
   1257                         data1[x*3 + 2] = saturate(t);
   1258                     }
   1259                 }
   1260                 else
   1261                 {
   1262                     for( x = 0; x < x2; x++ )
   1263                     {
   1264                         int val = descale( cmp[x] + 128*4, 2 );
   1265                         data1[x] = saturate(val);
   1266                     }
   1267                 }
   1268             }
   1269         }
   1270 
   1271         x1 += h[0];
   1272         if( x1 >= m_width )
   1273         {
   1274             x1 = 0;
   1275             y1 += v[0];
   1276             data += v[0]*step;
   1277             if( y1 >= m_height ) break;
   1278         }
   1279     }
   1280 }
   1281 
   1282 
   1283 void  GrFmtJpegReader::GetBlock( int* block, int c )
   1284 {
   1285     memset( block, 0, 64*sizeof(block[0]) );
   1286 
   1287     assert( 0 <= c && c < 3 );
   1288     const short* td = m_td[m_ci[c].td];
   1289     const short* ta = m_ta[m_ci[c].ta];
   1290     const int* tq = m_tq[m_ci[c].tq];
   1291 
   1292     // Get DC coefficient
   1293     int i = 0, cat  = m_strm.GetHuff( td );
   1294     int mask = bs_bit_mask[cat];
   1295     int val  = m_strm.Get( cat );
   1296 
   1297     val -= (val*2 <= mask ? mask : 0);
   1298     m_ci[c].dc_pred = val += m_ci[c].dc_pred;
   1299 
   1300     block[0] = descale(val * tq[0],16);
   1301 
   1302     // Get AC coeffs
   1303     for(;;)
   1304     {
   1305         cat = m_strm.GetHuff( ta );
   1306         if( cat == 0 ) break; // end of block
   1307 
   1308         i += (cat >> 4) + 1;
   1309         cat &= 15;
   1310         mask = bs_bit_mask[cat];
   1311         val  = m_strm.Get( cat );
   1312         cat  = zigzag[i];
   1313         val -= (val*2 <= mask ? mask : 0);
   1314         block[cat] = descale(val * tq[cat], 16);
   1315         assert( i <= 63 );
   1316         if( i >= 63 ) break;
   1317     }
   1318 }
   1319 
   1320 ////////////////////// WJpegStream ///////////////////////
   1321 
   1322 WJpegBitStream::WJpegBitStream()
   1323 {
   1324 }
   1325 
   1326 
   1327 WJpegBitStream::~WJpegBitStream()
   1328 {
   1329     Close();
   1330     m_is_opened = false;
   1331 }
   1332 
   1333 
   1334 
   1335 bool  WJpegBitStream::Open( const char* filename )
   1336 {
   1337     Close();
   1338     Allocate();
   1339 
   1340     m_is_opened = m_low_strm.Open( filename );
   1341     if( m_is_opened )
   1342     {
   1343         m_block_pos = 0;
   1344         ResetBuffer();
   1345     }
   1346     return m_is_opened;
   1347 }
   1348 
   1349 
   1350 void  WJpegBitStream::Close()
   1351 {
   1352     if( m_is_opened )
   1353     {
   1354         Flush();
   1355         m_low_strm.Close();
   1356         m_is_opened = false;
   1357     }
   1358 }
   1359 
   1360 
   1361 void  WJpegBitStream::Flush()
   1362 {
   1363     Put( -1, m_bit_idx & 31 );
   1364     *((ulong*&)m_current)++ = m_val;
   1365     WriteBlock();
   1366     ResetBuffer();
   1367 }
   1368 
   1369 
   1370 void  WJpegBitStream::WriteBlock()
   1371 {
   1372     uchar* ptr = m_start;
   1373     if( !bsIsBigEndian() )
   1374         bsBSwapBlock( m_start, m_current );
   1375 
   1376     while( ptr < m_current )
   1377     {
   1378         int val = *ptr++;
   1379         m_low_strm.PutByte( val );
   1380         if( val == 0xff )
   1381         {
   1382             m_low_strm.PutByte( 0 );
   1383         }
   1384     }
   1385 
   1386     m_current = m_start;
   1387 }
   1388 
   1389 
   1390 /////////////////////// GrFmtJpegWriter ///////////////////
   1391 
   1392 GrFmtJpegWriter::GrFmtJpegWriter( const char* filename ) : GrFmtWriter( filename )
   1393 {
   1394 }
   1395 
   1396 GrFmtJpegWriter::~GrFmtJpegWriter()
   1397 {
   1398 }
   1399 
   1400 //  Standard JPEG quantization tables
   1401 static const uchar jpegTableK1_T[] =
   1402 {
   1403     16, 12, 14, 14,  18,  24,  49,  72,
   1404     11, 12, 13, 17,  22,  35,  64,  92,
   1405     10, 14, 16, 22,  37,  55,  78,  95,
   1406     16, 19, 24, 29,  56,  64,  87,  98,
   1407     24, 26, 40, 51,  68,  81, 103, 112,
   1408     40, 58, 57, 87, 109, 104, 121, 100,
   1409     51, 60, 69, 80, 103, 113, 120, 103,
   1410     61, 55, 56, 62,  77,  92, 101,  99
   1411 };
   1412 
   1413 
   1414 static const uchar jpegTableK2_T[] =
   1415 {
   1416     17, 18, 24, 47, 99, 99, 99, 99,
   1417     18, 21, 26, 66, 99, 99, 99, 99,
   1418     24, 26, 56, 99, 99, 99, 99, 99,
   1419     47, 66, 99, 99, 99, 99, 99, 99,
   1420     99, 99, 99, 99, 99, 99, 99, 99,
   1421     99, 99, 99, 99, 99, 99, 99, 99,
   1422     99, 99, 99, 99, 99, 99, 99, 99,
   1423     99, 99, 99, 99, 99, 99, 99, 99
   1424 };
   1425 
   1426 
   1427 // Standard Huffman tables
   1428 
   1429 // ... for luma DCs.
   1430 static const uchar jpegTableK3[] =
   1431 {
   1432     0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
   1433     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
   1434 };
   1435 
   1436 
   1437 // ... for chroma DCs.
   1438 static const uchar jpegTableK4[] =
   1439 {
   1440     0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
   1441     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
   1442 };
   1443 
   1444 
   1445 // ... for luma ACs.
   1446 static const uchar jpegTableK5[] =
   1447 {
   1448     0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125,
   1449     0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
   1450     0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
   1451     0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
   1452     0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
   1453     0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
   1454     0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
   1455     0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
   1456     0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
   1457     0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
   1458     0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
   1459     0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
   1460     0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
   1461     0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
   1462     0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
   1463     0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
   1464     0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
   1465     0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
   1466     0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
   1467     0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
   1468     0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
   1469     0xf9, 0xfa
   1470 };
   1471 
   1472 // ... for chroma ACs
   1473 static const uchar jpegTableK6[] =
   1474 {
   1475     0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119,
   1476     0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
   1477     0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
   1478     0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
   1479     0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
   1480     0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
   1481     0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
   1482     0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
   1483     0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
   1484     0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
   1485     0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
   1486     0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
   1487     0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
   1488     0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
   1489     0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
   1490     0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
   1491     0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
   1492     0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
   1493     0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
   1494     0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
   1495     0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
   1496     0xf9, 0xfa
   1497 };
   1498 
   1499 
   1500 static const char jpegHeader[] =
   1501     "\xFF\xD8"  // SOI  - start of image
   1502     "\xFF\xE0"  // APP0 - jfif extention
   1503     "\x00\x10"  // 2 bytes: length of APP0 segment
   1504     "JFIF\x00"  // JFIF signature
   1505     "\x01\x02"  // version of JFIF
   1506     "\x00"      // units = pixels ( 1 - inch, 2 - cm )
   1507     "\x00\x01\x00\x01" // 2 2-bytes values: x density & y density
   1508     "\x00\x00"; // width & height of thumbnail: ( 0x0 means no thumbnail)
   1509 
   1510 #define postshift 14
   1511 
   1512 // FDCT with postscaling
   1513 static void aan_fdct8x8( int *src, int *dst,
   1514                          int step, const int *postscale )
   1515 {
   1516     int  workspace[64], *work = workspace;
   1517     int  i;
   1518 
   1519     // Pass 1: process rows
   1520     for( i = 8; i > 0; i--, src += step, work += 8 )
   1521     {
   1522         int x0 = src[0], x1 = src[7];
   1523         int x2 = src[3], x3 = src[4];
   1524 
   1525         int x4 = x0 + x1; x0 -= x1;
   1526         x1 = x2 + x3; x2 -= x3;
   1527 
   1528         work[7] = x0; work[1] = x2;
   1529         x2 = x4 + x1; x4 -= x1;
   1530 
   1531         x0 = src[1]; x3 = src[6];
   1532         x1 = x0 + x3; x0 -= x3;
   1533         work[5] = x0;
   1534 
   1535         x0 = src[2]; x3 = src[5];
   1536         work[3] = x0 - x3; x0 += x3;
   1537 
   1538         x3 = x0 + x1; x0 -= x1;
   1539         x1 = x2 + x3; x2 -= x3;
   1540 
   1541         work[0] = x1; work[4] = x2;
   1542 
   1543         x0 = descale((x0 - x4)*C0_707, fixb);
   1544         x1 = x4 + x0; x4 -= x0;
   1545         work[2] = x4; work[6] = x1;
   1546 
   1547         x0 = work[1]; x1 = work[3];
   1548         x2 = work[5]; x3 = work[7];
   1549 
   1550         x0 += x1; x1 += x2; x2 += x3;
   1551         x1 = descale(x1*C0_707, fixb);
   1552 
   1553         x4 = x1 + x3; x3 -= x1;
   1554         x1 = (x0 - x2)*C0_382;
   1555         x0 = descale(x0*C0_541 + x1, fixb);
   1556         x2 = descale(x2*C1_306 + x1, fixb);
   1557 
   1558         x1 = x0 + x3; x3 -= x0;
   1559         x0 = x4 + x2; x4 -= x2;
   1560 
   1561         work[5] = x1; work[1] = x0;
   1562         work[7] = x4; work[3] = x3;
   1563     }
   1564 
   1565     work = workspace;
   1566     // pass 2: process columns
   1567     for( i = 8; i > 0; i--, work++, postscale += 8, dst += 8 )
   1568     {
   1569         int  x0 = work[8*0], x1 = work[8*7];
   1570         int  x2 = work[8*3], x3 = work[8*4];
   1571 
   1572         int  x4 = x0 + x1; x0 -= x1;
   1573         x1 = x2 + x3; x2 -= x3;
   1574 
   1575         work[8*7] = x0; work[8*0] = x2;
   1576         x2 = x4 + x1; x4 -= x1;
   1577 
   1578         x0 = work[8*1]; x3 = work[8*6];
   1579         x1 = x0 + x3; x0 -= x3;
   1580         work[8*4] = x0;
   1581 
   1582         x0 = work[8*2]; x3 = work[8*5];
   1583         work[8*3] = x0 - x3; x0 += x3;
   1584 
   1585         x3 = x0 + x1; x0 -= x1;
   1586         x1 = x2 + x3; x2 -= x3;
   1587 
   1588         dst[0] = descale(x1*postscale[0], postshift);
   1589         dst[4] = descale(x2*postscale[4], postshift);
   1590 
   1591         x0 = descale((x0 - x4)*C0_707, fixb);
   1592         x1 = x4 + x0; x4 -= x0;
   1593 
   1594         dst[2] = descale(x4*postscale[2], postshift);
   1595         dst[6] = descale(x1*postscale[6], postshift);
   1596 
   1597         x0 = work[8*0]; x1 = work[8*3];
   1598         x2 = work[8*4]; x3 = work[8*7];
   1599 
   1600         x0 += x1; x1 += x2; x2 += x3;
   1601         x1 = descale(x1*C0_707, fixb);
   1602 
   1603         x4 = x1 + x3; x3 -= x1;
   1604         x1 = (x0 - x2)*C0_382;
   1605         x0 = descale(x0*C0_541 + x1, fixb);
   1606         x2 = descale(x2*C1_306 + x1, fixb);
   1607 
   1608         x1 = x0 + x3; x3 -= x0;
   1609         x0 = x4 + x2; x4 -= x2;
   1610 
   1611         dst[5] = descale(x1*postscale[5], postshift);
   1612         dst[1] = descale(x0*postscale[1], postshift);
   1613         dst[7] = descale(x4*postscale[7], postshift);
   1614         dst[3] = descale(x3*postscale[3], postshift);
   1615     }
   1616 }
   1617 
   1618 
   1619 bool  GrFmtJpegWriter::WriteImage( const uchar* data, int step,
   1620                                    int width, int height, int /*depth*/, int _channels )
   1621 {
   1622     assert( data && width > 0 && height > 0 );
   1623 
   1624     if( !m_strm.Open( m_filename ) ) return false;
   1625 
   1626     // encode the header and tables
   1627     // for each mcu:
   1628     //   convert rgb to yuv with downsampling (if color).
   1629     //   for every block:
   1630     //     calc dct and quantize
   1631     //     encode block.
   1632     int x, y;
   1633     int i, j;
   1634     const int max_quality = 12;
   1635     int   quality = max_quality;
   1636     WMByteStream& lowstrm = m_strm.m_low_strm;
   1637     int   fdct_qtab[2][64];
   1638     ulong huff_dc_tab[2][16];
   1639     ulong huff_ac_tab[2][256];
   1640     int  channels = _channels > 1 ? 3 : 1;
   1641     int  x_scale = channels > 1 ? 2 : 1, y_scale = x_scale;
   1642     int  dc_pred[] = { 0, 0, 0 };
   1643     int  x_step = x_scale * 8;
   1644     int  y_step = y_scale * 8;
   1645     int  block[6][64];
   1646     int  buffer[1024];
   1647     int  luma_count = x_scale*y_scale;
   1648     int  block_count = luma_count + channels - 1;
   1649     int  Y_step = x_scale*8;
   1650     const int UV_step = 16;
   1651     double inv_quality;
   1652 
   1653     if( quality < 3 ) quality = 3;
   1654     if( quality > max_quality ) quality = max_quality;
   1655 
   1656     inv_quality = 1./quality;
   1657 
   1658     // Encode header
   1659     lowstrm.PutBytes( jpegHeader, sizeof(jpegHeader) - 1 );
   1660 
   1661     // Encode quantization tables
   1662     for( i = 0; i < (channels > 1 ? 2 : 1); i++ )
   1663     {
   1664         const uchar* qtable = i == 0 ? jpegTableK1_T : jpegTableK2_T;
   1665         int chroma_scale = i > 0 ? luma_count : 1;
   1666 
   1667         lowstrm.PutWord( 0xffdb );   // DQT marker
   1668         lowstrm.PutWord( 2 + 65*1 ); // put single qtable
   1669         lowstrm.PutByte( 0*16 + i ); // 8-bit table
   1670 
   1671         // put coefficients
   1672         for( j = 0; j < 64; j++ )
   1673         {
   1674             int idx = zigzag[j];
   1675             int qval = cvRound(qtable[idx]*inv_quality);
   1676             if( qval < 1 )
   1677                 qval = 1;
   1678             if( qval > 255 )
   1679                 qval = 255;
   1680             fdct_qtab[i][idx] = cvRound((1 << (postshift + 9))/
   1681                                       (qval*chroma_scale*idct_prescale[idx]));
   1682             lowstrm.PutByte( qval );
   1683         }
   1684     }
   1685 
   1686     // Encode huffman tables
   1687     for( i = 0; i < (channels > 1 ? 4 : 2); i++ )
   1688     {
   1689         const uchar* htable = i == 0 ? jpegTableK3 : i == 1 ? jpegTableK5 :
   1690                               i == 2 ? jpegTableK4 : jpegTableK6;
   1691         int is_ac_tab = i & 1;
   1692         int idx = i >= 2;
   1693         int tableSize = 16 + (is_ac_tab ? 162 : 12);
   1694 
   1695         lowstrm.PutWord( 0xFFC4   );      // DHT marker
   1696         lowstrm.PutWord( 3 + tableSize ); // define one huffman table
   1697         lowstrm.PutByte( is_ac_tab*16 + idx ); // put DC/AC flag and table index
   1698         lowstrm.PutBytes( htable, tableSize ); // put table
   1699 
   1700         bsCreateEncodeHuffmanTable( bsCreateSourceHuffmanTable(
   1701             htable, buffer, 16, 9 ), is_ac_tab ? huff_ac_tab[idx] :
   1702             huff_dc_tab[idx], is_ac_tab ? 256 : 16 );
   1703     }
   1704 
   1705     // put frame header
   1706     lowstrm.PutWord( 0xFFC0 );          // SOF0 marker
   1707     lowstrm.PutWord( 8 + 3*channels );  // length of frame header
   1708     lowstrm.PutByte( 8 );               // sample precision
   1709     lowstrm.PutWord( height );
   1710     lowstrm.PutWord( width );
   1711     lowstrm.PutByte( channels );        // number of components
   1712 
   1713     for( i = 0; i < channels; i++ )
   1714     {
   1715         lowstrm.PutByte( i + 1 );  // (i+1)-th component id (Y,U or V)
   1716         if( i == 0 )
   1717             lowstrm.PutByte(x_scale*16 + y_scale); // chroma scale factors
   1718         else
   1719             lowstrm.PutByte(1*16 + 1);
   1720         lowstrm.PutByte( i > 0 ); // quantization table idx
   1721     }
   1722 
   1723     // put scan header
   1724     lowstrm.PutWord( 0xFFDA );          // SOS marker
   1725     lowstrm.PutWord( 6 + 2*channels );  // length of scan header
   1726     lowstrm.PutByte( channels );        // number of components in the scan
   1727 
   1728     for( i = 0; i < channels; i++ )
   1729     {
   1730         lowstrm.PutByte( i+1 );             // component id
   1731         lowstrm.PutByte( (i>0)*16 + (i>0) );// selection of DC & AC tables
   1732     }
   1733 
   1734     lowstrm.PutWord(0*256 + 63);// start and end of spectral selection - for
   1735                                 // sequental DCT start is 0 and end is 63
   1736 
   1737     lowstrm.PutByte( 0 );  // successive approximation bit position
   1738                            // high & low - (0,0) for sequental DCT
   1739 
   1740     // encode data
   1741     for( y = 0; y < height; y += y_step, data += y_step*step )
   1742     {
   1743         for( x = 0; x < width; x += x_step )
   1744         {
   1745             int x_limit = x_step;
   1746             int y_limit = y_step;
   1747             const uchar* rgb_data = data + x*_channels;
   1748             int* Y_data = block[0];
   1749 
   1750             if( x + x_limit > width ) x_limit = width - x;
   1751             if( y + y_limit > height ) y_limit = height - y;
   1752 
   1753             memset( block, 0, block_count*64*sizeof(block[0][0]));
   1754 
   1755             if( channels > 1 )
   1756             {
   1757                 int* UV_data = block[luma_count];
   1758 
   1759                 for( i = 0; i < y_limit; i++, rgb_data += step, Y_data += Y_step )
   1760                 {
   1761                     for( j = 0; j < x_limit; j++, rgb_data += _channels )
   1762                     {
   1763                         int r = rgb_data[2];
   1764                         int g = rgb_data[1];
   1765                         int b = rgb_data[0];
   1766 
   1767                         int Y = descale( r*y_r + g*y_g + b*y_b, fixc - 2) - 128*4;
   1768                         int U = descale( r*cb_r + g*cb_g + b*cb_b, fixc - 2 );
   1769                         int V = descale( r*cr_r + g*cr_g + b*cr_b, fixc - 2 );
   1770                         int j2 = j >> (x_scale - 1);
   1771 
   1772                         Y_data[j] = Y;
   1773                         UV_data[j2] += U;
   1774                         UV_data[j2 + 8] += V;
   1775                     }
   1776 
   1777                     rgb_data -= x_limit*_channels;
   1778                     if( ((i+1) & (y_scale - 1)) == 0 )
   1779                     {
   1780                         UV_data += UV_step;
   1781                     }
   1782                 }
   1783             }
   1784             else
   1785             {
   1786                 for( i = 0; i < y_limit; i++, rgb_data += step, Y_data += Y_step )
   1787                 {
   1788                     for( j = 0; j < x_limit; j++ )
   1789                         Y_data[j] = rgb_data[j]*4 - 128*4;
   1790                 }
   1791             }
   1792 
   1793             for( i = 0; i < block_count; i++ )
   1794             {
   1795                 int is_chroma = i >= luma_count;
   1796                 int src_step = x_scale * 8;
   1797                 int run = 0, val;
   1798                 int* src_ptr = block[i & -2] + (i & 1)*8;
   1799                 const ulong* htable = huff_ac_tab[is_chroma];
   1800 
   1801                 aan_fdct8x8( src_ptr, buffer, src_step, fdct_qtab[is_chroma] );
   1802 
   1803                 j = is_chroma + (i > luma_count);
   1804                 val = buffer[0] - dc_pred[j];
   1805                 dc_pred[j] = buffer[0];
   1806 
   1807                 {
   1808                 float a = (float)val;
   1809                 int cat = (((int&)a >> 23) & 255) - (126 & (val ? -1 : 0));
   1810 
   1811                 assert( cat <= 11 );
   1812                 m_strm.PutHuff( cat, huff_dc_tab[is_chroma] );
   1813                 m_strm.Put( val - (val < 0 ? 1 : 0), cat );
   1814                 }
   1815 
   1816                 for( j = 1; j < 64; j++ )
   1817                 {
   1818                     val = buffer[zigzag[j]];
   1819 
   1820                     if( val == 0 )
   1821                     {
   1822                         run++;
   1823                     }
   1824                     else
   1825                     {
   1826                         while( run >= 16 )
   1827                         {
   1828                             m_strm.PutHuff( 0xF0, htable ); // encode 16 zeros
   1829                             run -= 16;
   1830                         }
   1831 
   1832                         {
   1833                         float a = (float)val;
   1834                         int cat = (((int&)a >> 23) & 255) - (126 & (val ? -1 : 0));
   1835 
   1836                         assert( cat <= 10 );
   1837                         m_strm.PutHuff( cat + run*16, htable );
   1838                         m_strm.Put( val - (val < 0 ? 1 : 0), cat );
   1839                         }
   1840 
   1841                         run = 0;
   1842                     }
   1843                 }
   1844 
   1845                 if( run )
   1846                 {
   1847                     m_strm.PutHuff( 0x00, htable ); // encode EOB
   1848                 }
   1849             }
   1850         }
   1851     }
   1852 
   1853     // Flush
   1854     m_strm.Flush();
   1855 
   1856     lowstrm.PutWord( 0xFFD9 ); // EOI marker
   1857     m_strm.Close();
   1858 
   1859     return true;
   1860 }
   1861 
   1862 #endif
   1863 
   1864 /* End of file. */
   1865 
   1866 
   1867