1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
43 #include "grfmt_jpeg.h"
45 // JPEG filter factory
47 GrFmtJpeg::GrFmtJpeg()
50 m_signature = "\xFF\xD8\xFF";
51 m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)";
55 GrFmtJpeg::~GrFmtJpeg()
60 GrFmtReader* GrFmtJpeg::NewReader( const char* filename )
62 return new GrFmtJpegReader( filename );
66 GrFmtWriter* GrFmtJpeg::NewWriter( const char* filename )
68 return new GrFmtJpegWriter( filename );
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 \****************************************************************************************/
85 #define XMD_H // prevent redefinition of INT32
86 #undef FAR // prevent FAR redefinition
90 #if defined WIN32 && defined __GNUC__
91 typedef unsigned char boolean;
98 /////////////////////// Error processing /////////////////////
100 typedef struct GrFmtJpegErrorMgr
102 struct jpeg_error_mgr pub; /* "parent" structure */
103 jmp_buf setjmp_buffer; /* jump label */
109 error_exit( j_common_ptr cinfo )
111 GrFmtJpegErrorMgr* err_mgr = (GrFmtJpegErrorMgr*)(cinfo->err);
113 /* Return control to the setjmp point */
114 longjmp( err_mgr->setjmp_buffer, 1 );
118 /////////////////////// GrFmtJpegReader ///////////////////
121 GrFmtJpegReader::GrFmtJpegReader( const char* filename ) : GrFmtReader( filename )
128 GrFmtJpegReader::~GrFmtJpegReader()
133 void GrFmtJpegReader::Close()
143 jpeg_decompress_struct* cinfo = (jpeg_decompress_struct*)m_cinfo;
144 GrFmtJpegErrorMgr* jerr = (GrFmtJpegErrorMgr*)m_jerr;
146 jpeg_destroy_decompress( cinfo );
152 GrFmtReader::Close();
156 bool GrFmtJpegReader::ReadHeader()
161 jpeg_decompress_struct* cinfo = new jpeg_decompress_struct;
162 GrFmtJpegErrorMgr* jerr = new GrFmtJpegErrorMgr;
164 cinfo->err = jpeg_std_error(&jerr->pub);
165 jerr->pub.error_exit = error_exit;
170 if( setjmp( jerr->setjmp_buffer ) == 0 )
172 jpeg_create_decompress( cinfo );
174 m_f = fopen( m_filename, "rb" );
177 jpeg_stdio_src( cinfo, m_f );
178 jpeg_read_header( cinfo, TRUE );
180 m_width = cinfo->image_width;
181 m_height = cinfo->image_height;
182 m_iscolor = cinfo->num_components > 1;
194 /***************************************************************************
195 * following code is for supporting MJPEG image files
196 * based on a message of Laurent Pinchart on the video4linux mailing list
197 ***************************************************************************/
199 /* JPEG DHT Segment for YCrCb omitted from MJPEG data */
201 unsigned char my_jpeg_odml_dht[0x1a4] = {
202 0xff, 0xc4, 0x01, 0xa2,
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,
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,
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,
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,
262 * Parse the DHT table.
263 * This code comes from jpeg6b (jdmarker.c).
266 int my_jpeg_load_dht (struct jpeg_decompress_struct *info, unsigned char *dht,
267 JHUFF_TBL *ac_tables[], JHUFF_TBL *dc_tables[])
269 unsigned int length = (dht[2] << 8) + dht[3] - 2;
270 unsigned int pos = 4;
271 unsigned int count, i;
275 unsigned char bits[17];
276 unsigned char huffval[256];
283 for (i = 1; i <= 16; ++i)
285 bits[i] = dht[pos++];
290 if (count > 256 || count > length)
293 for (i = 0; i < count; ++i)
294 huffval[i] = dht[pos++];
300 hufftbl = &ac_tables[index];
303 hufftbl = &dc_tables[index];
305 if (index < 0 || index >= NUM_HUFF_TBLS)
308 if (*hufftbl == NULL)
309 *hufftbl = jpeg_alloc_huff_table ((j_common_ptr)info);
310 if (*hufftbl == NULL)
313 memcpy ((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits);
314 memcpy ((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval);
323 /***************************************************************************
324 * end of code for supportting MJPEG image files
325 * based on a message of Laurent Pinchart on the video4linux mailing list
326 ***************************************************************************/
328 bool GrFmtJpegReader::ReadData( uchar* data, int step, int color )
332 color = color > 0 || (m_iscolor && color < 0);
334 if( m_cinfo && m_jerr && m_width && m_height )
336 jpeg_decompress_struct* cinfo = (jpeg_decompress_struct*)m_cinfo;
337 GrFmtJpegErrorMgr* jerr = (GrFmtJpegErrorMgr*)m_jerr;
338 JSAMPARRAY buffer = 0;
340 if( setjmp( jerr->setjmp_buffer ) == 0 )
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 )
348 /* yes, this is a mjpeg image format, so load the correct
350 my_jpeg_load_dht( cinfo,
352 cinfo->ac_huff_tbl_ptrs,
353 cinfo->dc_huff_tbl_ptrs );
356 if( color > 0 || (m_iscolor && color < 0) )
359 if( cinfo->num_components != 4 )
361 cinfo->out_color_space = JCS_RGB;
362 cinfo->out_color_components = 3;
366 cinfo->out_color_space = JCS_CMYK;
367 cinfo->out_color_components = 4;
373 if( cinfo->num_components != 4 )
375 cinfo->out_color_space = JCS_GRAYSCALE;
376 cinfo->out_color_components = 1;
380 cinfo->out_color_space = JCS_CMYK;
381 cinfo->out_color_components = 4;
385 jpeg_start_decompress( cinfo );
387 buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo,
388 JPOOL_IMAGE, m_width*4, 1 );
390 for( ; m_height--; data += step )
392 jpeg_read_scanlines( cinfo, buffer, 1 );
395 if( cinfo->out_color_components == 3 )
396 icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
398 icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
402 if( cinfo->out_color_components == 1 )
403 memcpy( data, buffer[0], m_width );
405 icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) );
409 jpeg_finish_decompress( cinfo );
418 /////////////////////// GrFmtJpegWriter ///////////////////
420 GrFmtJpegWriter::GrFmtJpegWriter( const char* filename ) : GrFmtWriter( filename )
425 GrFmtJpegWriter::~GrFmtJpegWriter()
430 bool GrFmtJpegWriter::WriteImage( const uchar* data, int step,
431 int width, int height, int /*depth*/, int _channels )
433 const int default_quality = 95;
434 struct jpeg_compress_struct cinfo;
435 GrFmtJpegErrorMgr jerr;
439 int channels = _channels > 1 ? 3 : 1;
440 uchar* buffer = 0; // temporary buffer for row flipping
442 cinfo.err = jpeg_std_error(&jerr.pub);
443 jerr.pub.error_exit = error_exit;
445 if( setjmp( jerr.setjmp_buffer ) == 0 )
447 jpeg_create_compress(&cinfo);
448 f = fopen( m_filename, "wb" );
452 jpeg_stdio_dest( &cinfo, f );
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;
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 );
465 buffer = new uchar[width*channels];
467 for( ; height--; data += step )
469 uchar* ptr = (uchar*)data;
473 icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) );
476 else if( _channels == 4 )
478 icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 );
482 jpeg_write_scanlines( &cinfo, &ptr, 1 );
485 jpeg_finish_compress( &cinfo );
491 jpeg_destroy_compress( &cinfo );
499 ////////////////////// JPEG-oriented two-level bitstream ////////////////////////
501 RJpegBitStream::RJpegBitStream()
505 RJpegBitStream::~RJpegBitStream()
511 bool RJpegBitStream::Open( const char* filename )
516 m_is_opened = m_low_strm.Open( filename );
517 if( m_is_opened ) SetPos(0);
522 void RJpegBitStream::Close()
529 void RJpegBitStream::ReadBlock()
531 uchar* end = m_start + m_block_size;
532 uchar* current = m_start;
534 if( setjmp( m_low_strm.JmpBuf()) == 0 )
536 int sz = m_unGetsize;
537 memmove( current - sz, m_end - sz, sz );
538 while( current < end )
540 int val = m_low_strm.GetByte();
543 *current++ = (uchar)val;
547 val = m_low_strm.GetByte();
550 else if( !(0xD0 <= val && val <= 0xD7) )
552 m_low_strm.SetPos( m_low_strm.GetPos() - 2 );
561 if( current == m_start && m_jmp_set )
562 longjmp( m_jmp_buf, RBS_THROW_EOS );
565 m_end = m_start + (((current - m_start) + 3) & -4);
566 if( !bsIsBigEndian() )
567 bsBSwapBlock( m_start, m_end );
571 void RJpegBitStream::Flush()
573 m_end = m_start + m_block_size;
574 m_current = m_end - 4;
578 void RJpegBitStream::AlignOnByte()
583 int RJpegBitStream::FindMarker()
585 int code = m_low_strm.GetWord();
586 while( (code & 0xFF00) != 0xFF00 || (code == 0xFFFF || code == 0xFF00 ))
588 code = ((code&255) << 8) | m_low_strm.GetByte();
594 /****************************** JPEG (JFIF) reader ***************************/
596 // zigzag & IDCT prescaling (AAN algorithm) tables
597 static const uchar zigzag[] =
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
607 static const int idct_prescale[] =
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
621 #define fix(x, n) (int)((x)*(1 << (n)) + .5)
622 #define fix1(x, n) (x)
623 #define fixmul(x) (x)
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 )
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 )
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 )
642 #define y_r fix( 0.299, fixc )
643 #define y_g fix( 0.587, fixc )
644 #define y_b fix( 0.114, fixc )
646 #define cb_r -fix( 0.1687, fixc )
647 #define cb_g -fix( 0.3313, fixc )
648 #define cb_b fix( 0.5, fixc )
650 #define cr_r fix( 0.5, fixc )
651 #define cr_g -fix( 0.4187, fixc )
652 #define cr_b -fix( 0.0813, fixc )
655 // IDCT without prescaling
656 static void aan_idct8x8( int *src, int *dst, int step )
658 int workspace[64], *work = workspace;
661 /* Pass 1: process rows */
662 for( i = 8; i > 0; i--, src += 8, work += 8 )
665 int x0 = src[5], x1 = src[3];
666 int x2 = src[1], x3 = src[7];
668 int x4 = x0 + x1; x0 -= x1;
670 x1 = x2 + x3; x2 -= x3;
671 x3 = x1 + x4; x1 -= x4;
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);
682 work[7] = x3; work[6] = x0;
683 work[5] = x1; work[4] = x2;
686 x2 = src[2]; x3 = src[6];
687 x0 = src[0]; x1 = src[4];
690 x2 = descale((x2-x3)*C1_414, fixb) - x4;
692 x3 = x0 + x1; x0 -= x1;
693 x1 = x3 + x4; x3 -= x4;
694 x4 = x0 + x2; x0 -= x2;
697 x1 -= x2; x2 = 2*x2 + x1;
698 work[7] = x1; work[0] = x2;
701 x1 = x4 + x2; x4 -= x2;
702 work[1] = x1; work[6] = x4;
704 x1 = work[5]; x2 = work[4];
705 x4 = x0 + x1; x0 -= x1;
706 x1 = x3 + x2; x3 -= x2;
708 work[2] = x4; work[5] = x0;
709 work[3] = x3; work[4] = x1;
712 /* Pass 2: process columns */
714 for( i = 8; i > 0; i--, dst += step, work++ )
717 int x0 = work[8*5], x1 = work[8*3];
718 int x2 = work[8*1], x3 = work[8*7];
720 int x4 = x0 + x1; x0 -= x1;
721 x1 = x2 + x3; x2 -= x3;
722 x3 = x1 + x4; x1 -= x4;
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);
733 dst[7] = x3; dst[6] = x0;
734 dst[5] = x1; dst[4] = x2;
737 x2 = work[8*2]; x3 = work[8*6];
738 x0 = work[8*0]; x1 = work[8*4];
741 x2 = descale((x2-x3)*C1_414, fixb) - x4;
743 x3 = x0 + x1; x0 -= x1;
744 x1 = x3 + x4; x3 -= x4;
745 x4 = x0 + x2; x0 -= x2;
748 x1 -= x2; x2 = 2*x2 + x1;
752 dst[7] = x1; dst[0] = x2;
755 x1 = descale(x4 + x2,3);
756 x4 = descale(x4 - x2,3);
757 dst[1] = x1; dst[6] = x4;
759 x1 = dst[5]; x2 = dst[4];
761 x4 = descale(x0 + x1,3);
762 x0 = descale(x0 - x1,3);
763 x1 = descale(x3 + x2,3);
764 x3 = descale(x3 - x2,3);
766 dst[2] = x4; dst[5] = x0;
767 dst[3] = x3; dst[4] = x1;
772 static const int max_dec_htable_size = 1 << 12;
773 static const int first_table_bits = 9;
775 GrFmtJpegReader::GrFmtJpegReader( const char* filename ) : GrFmtReader( filename )
781 for( i = 0; i < 4; i++ )
783 m_td[i] = new short[max_dec_htable_size];
784 m_ta[i] = new short[max_dec_htable_size];
789 GrFmtJpegReader::~GrFmtJpegReader()
791 for( int i = 0; i < 4; i++ )
801 void GrFmtJpegReader::Close()
804 GrFmtReader::Close();
808 bool GrFmtJpegReader::ReadHeader()
812 bool result = false, is_sof = false,
813 is_qt = false, is_ht = false, is_sos = false;
815 assert( strlen(m_filename) != 0 );
816 if( !m_strm.Open( m_filename )) return false;
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));
823 if( setjmp( m_strm.JmpBuf()) == 0 )
825 RMByteStream& lstrm = m_strm.m_low_strm;
827 lstrm.Skip( 2 ); // skip SOI marker
831 int marker = m_strm.FindMarker() & 255;
833 // check for standalone markers
834 if( marker != 0xD8 /* SOI */ && marker != 0xD9 /* EOI */ &&
835 marker != 0x01 /* TEM */ && !( 0xD0 <= marker && marker <= 0xD7 ))
837 int pos = lstrm.GetPos();
838 int length = lstrm.GetWord();
843 lstrm.GetBytes( buffer, 5 );
844 if( strcmp(buffer, "JFIF") == 0 ) // JFIF identification
846 m_version = lstrm.GetWord();
852 m_precision = lstrm.GetByte();
853 m_height = lstrm.GetWord();
854 m_width = lstrm.GetWord();
855 m_planes = lstrm.GetByte();
857 if( m_width == 0 || m_height == 0 || // DNL not supported
858 (m_planes != 1 && m_planes != 3)) goto parsing_end;
860 m_iscolor = m_planes == 3;
862 memset( m_ci, -1, sizeof(m_ci));
864 for( i = 0; i < m_planes; i++ )
866 int idx = lstrm.GetByte();
868 if( idx < 1 || idx > m_planes ) // wrong index
872 cmp_info& ci = m_ci[idx-1];
874 if( ci.tq > 0 /* duplicated description */) goto parsing_end;
876 ci.h = (char)lstrm.GetByte();
877 ci.v = (char)(ci.h & 15);
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) &&
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)))
890 m_type = marker - 0xC0;
894 if( !LoadQuantTables( length )) goto parsing_end;
899 if( !LoadHuffmanTables( length )) goto parsing_end;
909 m_MCUs = lstrm.GetWord();
912 lstrm.SetPos( pos + length );
918 result = /*is_jfif &&*/ is_sof && is_qt && is_ht && is_sos;
921 m_width = m_height = -1;
929 bool GrFmtJpegReader::LoadQuantTables( int length )
934 RMByteStream& lstrm = m_strm.m_low_strm;
939 int tq = lstrm.GetByte();
943 tq_size = (64<<size) + 1;
944 if( tq > 3 || size > 1 || length < tq_size ) return false;
947 lstrm.GetBytes( buffer, tq_size - 1 );
949 if( size == 0 ) // 8 bit quant factors
951 for( i = 0; i < 64; i++ )
954 m_tq[tq][idx] = buffer[i] * 16 * idct_prescale[idx];
957 else // 16 bit quant factors
959 for( i = 0; i < 64; i++ )
962 m_tq[tq][idx] = ((unsigned short*)buffer)[i] * idct_prescale[idx];
972 bool GrFmtJpegReader::LoadHuffmanTables( int length )
974 const int max_bits = 16;
979 RMByteStream& lstrm = m_strm.m_low_strm;
984 int t = lstrm.GetByte();
988 if( t > 3 || hclass > 1 || length < 17 ) return false;
991 lstrm.GetBytes( buffer, max_bits );
992 for( i = 0, ht_size = 0; i < max_bits; i++ ) ht_size += buffer[i];
994 if( length < ht_size ) return false;
997 lstrm.GetBytes( buffer + max_bits, ht_size );
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;
1013 bool GrFmtJpegReader::ReadData( uchar* data, int step, int color )
1015 if( m_offset < 0 || !m_strm.IsOpened())
1018 if( setjmp( m_strm.JmpBuf()) == 0 )
1020 RMByteStream& lstrm = m_strm.m_low_strm;
1021 lstrm.SetPos( m_offset );
1025 int marker = m_strm.FindMarker() & 255;
1027 if( marker == 0xD8 /* SOI */ || marker == 0xD9 /* EOI */ )
1030 // check for standalone markers
1031 if( marker != 0x01 /* TEM */ && !( 0xD0 <= marker && marker <= 0xD7 ))
1033 int pos = lstrm.GetPos();
1034 int length = lstrm.GetWord();
1039 if( !LoadHuffmanTables( length )) goto decoding_end;
1045 int idx[3] = { -1, -1, -1 };
1046 int i, ns = lstrm.GetByte();
1047 int sum = 0, a; // spectral selection & approximation
1049 if( ns != m_planes ) goto decoding_end;
1050 for( i = 0; i < ns; i++ )
1052 int td, ta, c = lstrm.GetByte() - 1;
1053 if( c < 0 || m_planes <= c )
1058 if( idx[c] != -1 ) goto decoding_end;
1060 td = lstrm.GetByte();
1063 if( !(ta <= 3 && m_is_ta[ta] &&
1064 td <= 3 && m_is_td[td] &&
1065 m_is_tq[m_ci[c].tq]) )
1068 m_ci[c].td = (char)td;
1069 m_ci[c].ta = (char)ta;
1071 sum += m_ci[c].h*m_ci[c].v;
1074 if( sum > 10 ) goto decoding_end;
1076 m_ss = lstrm.GetByte();
1077 m_se = lstrm.GetByte();
1079 a = lstrm.GetByte();
1083 ProcessScan( idx, ns, data, step, color );
1084 goto decoding_end; // only single scan case is supported now
1087 //m_offset = pos - 2;
1091 m_MCUs = lstrm.GetWord();
1095 if( marker != 0xDA ) lstrm.SetPos( pos + length );
1105 void GrFmtJpegReader::ResetDecoder()
1107 m_ci[0].dc_pred = m_ci[1].dc_pred = m_ci[2].dc_pred = 0;
1110 void GrFmtJpegReader::ProcessScan( int* idx, int ns, uchar* data, int step, int color )
1112 int i, s = 0, mcu, x1 = 0, y1 = 0;
1115 int pos[3], h[3], v[3];
1116 int x_shift = 0, y_shift = 0;
1117 int nch = color ? 3 : 1;
1119 assert( ns == m_planes && m_ss == 0 && m_se == 63 &&
1120 m_al == 0 && m_ah == 0 ); // sequental & single scan
1122 assert( idx[0] == 0 && (ns ==1 || (idx[1] == 1 && idx[2] == 2)));
1124 for( i = 0; i < ns; i++ )
1135 x_shift = h[0]/(h[1]*2);
1136 y_shift = v[0]/(v[1]*2);
1142 for( mcu = 0;; mcu++ )
1144 int x2, y2, x, y, xc;
1148 if( mcu == m_MCUs && m_MCUs != 0 )
1151 m_strm.AlignOnByte();
1156 for( i = 0; i < ns; 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 )
1163 GetBlock( temp, c );
1164 if( i < (color ? 3 : 1))
1166 aan_idct8x8( temp, cmp + x, h[c] );
1174 if( y1 + y2 > m_height ) y2 = m_height - y1;
1175 if( x1 + x2 > m_width ) x2 = m_width - x1;
1178 data1 = data + x1*nch;
1181 for( y = 0; y < y2; y++, data1 += step, cmp += h[0] )
1185 for( x = 0; x < x2; x++ )
1187 int val = descale( cmp[x] + 128*4, 2 );
1188 data1[x*3] = data1[x*3 + 1] = data1[x*3 + 2] = saturate( val );
1193 for( x = 0; x < x2; x++ )
1195 int val = descale( cmp[x] + 128*4, 2 );
1196 data1[x] = saturate( val );
1202 for( y = 0; y < y2; y++, data1 += step, cmp += h[0] )
1206 int shift = h[1]*(y >> y_shift);
1207 int* cmpCb = blocks[pos[1]] + shift;
1208 int* cmpCr = blocks[pos[2]] + shift;
1212 for( ; x < x2; x++ )
1214 int Y = (cmp[x] + 128*4) << fixc;
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);
1225 else if( x_shift == 1 )
1227 for( xc = 0; x <= x2 - 2; x += 2, xc++ )
1229 int Y = (cmp[x] + 128*4) << fixc;
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);
1247 for( ; x < x2; x++ )
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);
1262 for( x = 0; x < x2; x++ )
1264 int val = descale( cmp[x] + 128*4, 2 );
1265 data1[x] = saturate(val);
1277 if( y1 >= m_height ) break;
1283 void GrFmtJpegReader::GetBlock( int* block, int c )
1285 memset( block, 0, 64*sizeof(block[0]) );
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];
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 );
1297 val -= (val*2 <= mask ? mask : 0);
1298 m_ci[c].dc_pred = val += m_ci[c].dc_pred;
1300 block[0] = descale(val * tq[0],16);
1305 cat = m_strm.GetHuff( ta );
1306 if( cat == 0 ) break; // end of block
1308 i += (cat >> 4) + 1;
1310 mask = bs_bit_mask[cat];
1311 val = m_strm.Get( cat );
1313 val -= (val*2 <= mask ? mask : 0);
1314 block[cat] = descale(val * tq[cat], 16);
1316 if( i >= 63 ) break;
1320 ////////////////////// WJpegStream ///////////////////////
1322 WJpegBitStream::WJpegBitStream()
1327 WJpegBitStream::~WJpegBitStream()
1330 m_is_opened = false;
1335 bool WJpegBitStream::Open( const char* filename )
1340 m_is_opened = m_low_strm.Open( filename );
1350 void WJpegBitStream::Close()
1356 m_is_opened = false;
1361 void WJpegBitStream::Flush()
1363 Put( -1, m_bit_idx & 31 );
1364 *((ulong*&)m_current)++ = m_val;
1370 void WJpegBitStream::WriteBlock()
1372 uchar* ptr = m_start;
1373 if( !bsIsBigEndian() )
1374 bsBSwapBlock( m_start, m_current );
1376 while( ptr < m_current )
1379 m_low_strm.PutByte( val );
1382 m_low_strm.PutByte( 0 );
1386 m_current = m_start;
1390 /////////////////////// GrFmtJpegWriter ///////////////////
1392 GrFmtJpegWriter::GrFmtJpegWriter( const char* filename ) : GrFmtWriter( filename )
1396 GrFmtJpegWriter::~GrFmtJpegWriter()
1400 // Standard JPEG quantization tables
1401 static const uchar jpegTableK1_T[] =
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
1414 static const uchar jpegTableK2_T[] =
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
1427 // Standard Huffman tables
1429 // ... for luma DCs.
1430 static const uchar jpegTableK3[] =
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
1437 // ... for chroma DCs.
1438 static const uchar jpegTableK4[] =
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
1445 // ... for luma ACs.
1446 static const uchar jpegTableK5[] =
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,
1472 // ... for chroma ACs
1473 static const uchar jpegTableK6[] =
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,
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)
1510 #define postshift 14
1512 // FDCT with postscaling
1513 static void aan_fdct8x8( int *src, int *dst,
1514 int step, const int *postscale )
1516 int workspace[64], *work = workspace;
1519 // Pass 1: process rows
1520 for( i = 8; i > 0; i--, src += step, work += 8 )
1522 int x0 = src[0], x1 = src[7];
1523 int x2 = src[3], x3 = src[4];
1525 int x4 = x0 + x1; x0 -= x1;
1526 x1 = x2 + x3; x2 -= x3;
1528 work[7] = x0; work[1] = x2;
1529 x2 = x4 + x1; x4 -= x1;
1531 x0 = src[1]; x3 = src[6];
1532 x1 = x0 + x3; x0 -= x3;
1535 x0 = src[2]; x3 = src[5];
1536 work[3] = x0 - x3; x0 += x3;
1538 x3 = x0 + x1; x0 -= x1;
1539 x1 = x2 + x3; x2 -= x3;
1541 work[0] = x1; work[4] = x2;
1543 x0 = descale((x0 - x4)*C0_707, fixb);
1544 x1 = x4 + x0; x4 -= x0;
1545 work[2] = x4; work[6] = x1;
1547 x0 = work[1]; x1 = work[3];
1548 x2 = work[5]; x3 = work[7];
1550 x0 += x1; x1 += x2; x2 += x3;
1551 x1 = descale(x1*C0_707, fixb);
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);
1558 x1 = x0 + x3; x3 -= x0;
1559 x0 = x4 + x2; x4 -= x2;
1561 work[5] = x1; work[1] = x0;
1562 work[7] = x4; work[3] = x3;
1566 // pass 2: process columns
1567 for( i = 8; i > 0; i--, work++, postscale += 8, dst += 8 )
1569 int x0 = work[8*0], x1 = work[8*7];
1570 int x2 = work[8*3], x3 = work[8*4];
1572 int x4 = x0 + x1; x0 -= x1;
1573 x1 = x2 + x3; x2 -= x3;
1575 work[8*7] = x0; work[8*0] = x2;
1576 x2 = x4 + x1; x4 -= x1;
1578 x0 = work[8*1]; x3 = work[8*6];
1579 x1 = x0 + x3; x0 -= x3;
1582 x0 = work[8*2]; x3 = work[8*5];
1583 work[8*3] = x0 - x3; x0 += x3;
1585 x3 = x0 + x1; x0 -= x1;
1586 x1 = x2 + x3; x2 -= x3;
1588 dst[0] = descale(x1*postscale[0], postshift);
1589 dst[4] = descale(x2*postscale[4], postshift);
1591 x0 = descale((x0 - x4)*C0_707, fixb);
1592 x1 = x4 + x0; x4 -= x0;
1594 dst[2] = descale(x4*postscale[2], postshift);
1595 dst[6] = descale(x1*postscale[6], postshift);
1597 x0 = work[8*0]; x1 = work[8*3];
1598 x2 = work[8*4]; x3 = work[8*7];
1600 x0 += x1; x1 += x2; x2 += x3;
1601 x1 = descale(x1*C0_707, fixb);
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);
1608 x1 = x0 + x3; x3 -= x0;
1609 x0 = x4 + x2; x4 -= x2;
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);
1619 bool GrFmtJpegWriter::WriteImage( const uchar* data, int step,
1620 int width, int height, int /*depth*/, int _channels )
1622 assert( data && width > 0 && height > 0 );
1624 if( !m_strm.Open( m_filename ) ) return false;
1626 // encode the header and tables
1628 // convert rgb to yuv with downsampling (if color).
1630 // calc dct and quantize
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;
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;
1653 if( quality < 3 ) quality = 3;
1654 if( quality > max_quality ) quality = max_quality;
1656 inv_quality = 1./quality;
1659 lowstrm.PutBytes( jpegHeader, sizeof(jpegHeader) - 1 );
1661 // Encode quantization tables
1662 for( i = 0; i < (channels > 1 ? 2 : 1); i++ )
1664 const uchar* qtable = i == 0 ? jpegTableK1_T : jpegTableK2_T;
1665 int chroma_scale = i > 0 ? luma_count : 1;
1667 lowstrm.PutWord( 0xffdb ); // DQT marker
1668 lowstrm.PutWord( 2 + 65*1 ); // put single qtable
1669 lowstrm.PutByte( 0*16 + i ); // 8-bit table
1672 for( j = 0; j < 64; j++ )
1674 int idx = zigzag[j];
1675 int qval = cvRound(qtable[idx]*inv_quality);
1680 fdct_qtab[i][idx] = cvRound((1 << (postshift + 9))/
1681 (qval*chroma_scale*idct_prescale[idx]));
1682 lowstrm.PutByte( qval );
1686 // Encode huffman tables
1687 for( i = 0; i < (channels > 1 ? 4 : 2); i++ )
1689 const uchar* htable = i == 0 ? jpegTableK3 : i == 1 ? jpegTableK5 :
1690 i == 2 ? jpegTableK4 : jpegTableK6;
1691 int is_ac_tab = i & 1;
1693 int tableSize = 16 + (is_ac_tab ? 162 : 12);
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
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 );
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
1713 for( i = 0; i < channels; i++ )
1715 lowstrm.PutByte( i + 1 ); // (i+1)-th component id (Y,U or V)
1717 lowstrm.PutByte(x_scale*16 + y_scale); // chroma scale factors
1719 lowstrm.PutByte(1*16 + 1);
1720 lowstrm.PutByte( i > 0 ); // quantization table idx
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
1728 for( i = 0; i < channels; i++ )
1730 lowstrm.PutByte( i+1 ); // component id
1731 lowstrm.PutByte( (i>0)*16 + (i>0) );// selection of DC & AC tables
1734 lowstrm.PutWord(0*256 + 63);// start and end of spectral selection - for
1735 // sequental DCT start is 0 and end is 63
1737 lowstrm.PutByte( 0 ); // successive approximation bit position
1738 // high & low - (0,0) for sequental DCT
1741 for( y = 0; y < height; y += y_step, data += y_step*step )
1743 for( x = 0; x < width; x += x_step )
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];
1750 if( x + x_limit > width ) x_limit = width - x;
1751 if( y + y_limit > height ) y_limit = height - y;
1753 memset( block, 0, block_count*64*sizeof(block[0][0]));
1757 int* UV_data = block[luma_count];
1759 for( i = 0; i < y_limit; i++, rgb_data += step, Y_data += Y_step )
1761 for( j = 0; j < x_limit; j++, rgb_data += _channels )
1763 int r = rgb_data[2];
1764 int g = rgb_data[1];
1765 int b = rgb_data[0];
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);
1774 UV_data[j2 + 8] += V;
1777 rgb_data -= x_limit*_channels;
1778 if( ((i+1) & (y_scale - 1)) == 0 )
1786 for( i = 0; i < y_limit; i++, rgb_data += step, Y_data += Y_step )
1788 for( j = 0; j < x_limit; j++ )
1789 Y_data[j] = rgb_data[j]*4 - 128*4;
1793 for( i = 0; i < block_count; i++ )
1795 int is_chroma = i >= luma_count;
1796 int src_step = x_scale * 8;
1798 int* src_ptr = block[i & -2] + (i & 1)*8;
1799 const ulong* htable = huff_ac_tab[is_chroma];
1801 aan_fdct8x8( src_ptr, buffer, src_step, fdct_qtab[is_chroma] );
1803 j = is_chroma + (i > luma_count);
1804 val = buffer[0] - dc_pred[j];
1805 dc_pred[j] = buffer[0];
1808 float a = (float)val;
1809 int cat = (((int&)a >> 23) & 255) - (126 & (val ? -1 : 0));
1811 assert( cat <= 11 );
1812 m_strm.PutHuff( cat, huff_dc_tab[is_chroma] );
1813 m_strm.Put( val - (val < 0 ? 1 : 0), cat );
1816 for( j = 1; j < 64; j++ )
1818 val = buffer[zigzag[j]];
1828 m_strm.PutHuff( 0xF0, htable ); // encode 16 zeros
1833 float a = (float)val;
1834 int cat = (((int&)a >> 23) & 255) - (126 & (val ? -1 : 0));
1836 assert( cat <= 10 );
1837 m_strm.PutHuff( cat + run*16, htable );
1838 m_strm.Put( val - (val < 0 ? 1 : 0), cat );
1847 m_strm.PutHuff( 0x00, htable ); // encode EOB
1856 lowstrm.PutWord( 0xFFD9 ); // EOI marker