Apply maemo2 patch
[opencv] / otherlibs / highgui / grfmt_jpeg.cpp
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