• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GrFmtJpeg()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 
~GrFmtJpeg()55 GrFmtJpeg::~GrFmtJpeg()
56 {
57 }
58 
59 
NewReader(const char * filename)60 GrFmtReader* GrFmtJpeg::NewReader( const char* filename )
61 {
62     return new GrFmtJpegReader( filename );
63 }
64 
65 
NewWriter(const char * filename)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)
error_exit(j_common_ptr cinfo)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 
GrFmtJpegReader(const char * filename)121 GrFmtJpegReader::GrFmtJpegReader( const char* filename ) : GrFmtReader( filename )
122 {
123     m_cinfo = 0;
124     m_f = 0;
125 }
126 
127 
~GrFmtJpegReader()128 GrFmtJpegReader::~GrFmtJpegReader()
129 {
130 }
131 
132 
Close()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 
ReadHeader()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
my_jpeg_load_dht(struct jpeg_decompress_struct * info,unsigned char * dht,JHUFF_TBL * ac_tables[],JHUFF_TBL * dc_tables[])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 
ReadData(uchar * data,int step,int color)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 
GrFmtJpegWriter(const char * filename)420 GrFmtJpegWriter::GrFmtJpegWriter( const char* filename ) : GrFmtWriter( filename )
421 {
422 }
423 
424 
~GrFmtJpegWriter()425 GrFmtJpegWriter::~GrFmtJpegWriter()
426 {
427 }
428 
429 
WriteImage(const uchar * data,int step,int width,int height,int,int _channels)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 
RJpegBitStream()501 RJpegBitStream::RJpegBitStream()
502 {
503 }
504 
~RJpegBitStream()505 RJpegBitStream::~RJpegBitStream()
506 {
507     Close();
508 }
509 
510 
Open(const char * filename)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 
Close()522 void  RJpegBitStream::Close()
523 {
524     m_low_strm.Close();
525     m_is_opened = false;
526 }
527 
528 
ReadBlock()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 
Flush()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 
AlignOnByte()578 void  RJpegBitStream::AlignOnByte()
579 {
580     m_bit_idx &= -8;
581 }
582 
FindMarker()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
aan_idct8x8(int * src,int * dst,int step)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 
GrFmtJpegReader(const char * filename)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 
~GrFmtJpegReader()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 
Close()801 void  GrFmtJpegReader::Close()
802 {
803     m_strm.Close();
804     GrFmtReader::Close();
805 }
806 
807 
ReadHeader()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 
LoadQuantTables(int length)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 
LoadHuffmanTables(int length)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 
ReadData(uchar * data,int step,int color)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 
ResetDecoder()1105 void  GrFmtJpegReader::ResetDecoder()
1106 {
1107     m_ci[0].dc_pred = m_ci[1].dc_pred = m_ci[2].dc_pred = 0;
1108 }
1109 
ProcessScan(int * idx,int ns,uchar * data,int step,int color)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 
GetBlock(int * block,int c)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 
WJpegBitStream()1322 WJpegBitStream::WJpegBitStream()
1323 {
1324 }
1325 
1326 
~WJpegBitStream()1327 WJpegBitStream::~WJpegBitStream()
1328 {
1329     Close();
1330     m_is_opened = false;
1331 }
1332 
1333 
1334 
Open(const char * filename)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 
Close()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 
Flush()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 
WriteBlock()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 
GrFmtJpegWriter(const char * filename)1392 GrFmtJpegWriter::GrFmtJpegWriter( const char* filename ) : GrFmtWriter( filename )
1393 {
1394 }
1395 
~GrFmtJpegWriter()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
aan_fdct8x8(int * src,int * dst,int step,const int * postscale)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 
WriteImage(const uchar * data,int step,int width,int height,int,int _channels)1619 bool  GrFmtJpegWriter::WriteImage( const uchar* data, int step,
1620                                    int width, int height, int /*depth*/, int _channels )
1621 {
1622     assert( data && width > 0 && height > 0 );
1623 
1624     if( !m_strm.Open( m_filename ) ) return false;
1625 
1626     // encode the header and tables
1627     // for each mcu:
1628     //   convert rgb to yuv with downsampling (if color).
1629     //   for every block:
1630     //     calc dct and quantize
1631     //     encode block.
1632     int x, y;
1633     int i, j;
1634     const int max_quality = 12;
1635     int   quality = max_quality;
1636     WMByteStream& lowstrm = m_strm.m_low_strm;
1637     int   fdct_qtab[2][64];
1638     ulong huff_dc_tab[2][16];
1639     ulong huff_ac_tab[2][256];
1640     int  channels = _channels > 1 ? 3 : 1;
1641     int  x_scale = channels > 1 ? 2 : 1, y_scale = x_scale;
1642     int  dc_pred[] = { 0, 0, 0 };
1643     int  x_step = x_scale * 8;
1644     int  y_step = y_scale * 8;
1645     int  block[6][64];
1646     int  buffer[1024];
1647     int  luma_count = x_scale*y_scale;
1648     int  block_count = luma_count + channels - 1;
1649     int  Y_step = x_scale*8;
1650     const int UV_step = 16;
1651     double inv_quality;
1652 
1653     if( quality < 3 ) quality = 3;
1654     if( quality > max_quality ) quality = max_quality;
1655 
1656     inv_quality = 1./quality;
1657 
1658     // Encode header
1659     lowstrm.PutBytes( jpegHeader, sizeof(jpegHeader) - 1 );
1660 
1661     // Encode quantization tables
1662     for( i = 0; i < (channels > 1 ? 2 : 1); i++ )
1663     {
1664         const uchar* qtable = i == 0 ? jpegTableK1_T : jpegTableK2_T;
1665         int chroma_scale = i > 0 ? luma_count : 1;
1666 
1667         lowstrm.PutWord( 0xffdb );   // DQT marker
1668         lowstrm.PutWord( 2 + 65*1 ); // put single qtable
1669         lowstrm.PutByte( 0*16 + i ); // 8-bit table
1670 
1671         // put coefficients
1672         for( j = 0; j < 64; j++ )
1673         {
1674             int idx = zigzag[j];
1675             int qval = cvRound(qtable[idx]*inv_quality);
1676             if( qval < 1 )
1677                 qval = 1;
1678             if( qval > 255 )
1679                 qval = 255;
1680             fdct_qtab[i][idx] = cvRound((1 << (postshift + 9))/
1681                                       (qval*chroma_scale*idct_prescale[idx]));
1682             lowstrm.PutByte( qval );
1683         }
1684     }
1685 
1686     // Encode huffman tables
1687     for( i = 0; i < (channels > 1 ? 4 : 2); i++ )
1688     {
1689         const uchar* htable = i == 0 ? jpegTableK3 : i == 1 ? jpegTableK5 :
1690                               i == 2 ? jpegTableK4 : jpegTableK6;
1691         int is_ac_tab = i & 1;
1692         int idx = i >= 2;
1693         int tableSize = 16 + (is_ac_tab ? 162 : 12);
1694 
1695         lowstrm.PutWord( 0xFFC4   );      // DHT marker
1696         lowstrm.PutWord( 3 + tableSize ); // define one huffman table
1697         lowstrm.PutByte( is_ac_tab*16 + idx ); // put DC/AC flag and table index
1698         lowstrm.PutBytes( htable, tableSize ); // put table
1699 
1700         bsCreateEncodeHuffmanTable( bsCreateSourceHuffmanTable(
1701             htable, buffer, 16, 9 ), is_ac_tab ? huff_ac_tab[idx] :
1702             huff_dc_tab[idx], is_ac_tab ? 256 : 16 );
1703     }
1704 
1705     // put frame header
1706     lowstrm.PutWord( 0xFFC0 );          // SOF0 marker
1707     lowstrm.PutWord( 8 + 3*channels );  // length of frame header
1708     lowstrm.PutByte( 8 );               // sample precision
1709     lowstrm.PutWord( height );
1710     lowstrm.PutWord( width );
1711     lowstrm.PutByte( channels );        // number of components
1712 
1713     for( i = 0; i < channels; i++ )
1714     {
1715         lowstrm.PutByte( i + 1 );  // (i+1)-th component id (Y,U or V)
1716         if( i == 0 )
1717             lowstrm.PutByte(x_scale*16 + y_scale); // chroma scale factors
1718         else
1719             lowstrm.PutByte(1*16 + 1);
1720         lowstrm.PutByte( i > 0 ); // quantization table idx
1721     }
1722 
1723     // put scan header
1724     lowstrm.PutWord( 0xFFDA );          // SOS marker
1725     lowstrm.PutWord( 6 + 2*channels );  // length of scan header
1726     lowstrm.PutByte( channels );        // number of components in the scan
1727 
1728     for( i = 0; i < channels; i++ )
1729     {
1730         lowstrm.PutByte( i+1 );             // component id
1731         lowstrm.PutByte( (i>0)*16 + (i>0) );// selection of DC & AC tables
1732     }
1733 
1734     lowstrm.PutWord(0*256 + 63);// start and end of spectral selection - for
1735                                 // sequental DCT start is 0 and end is 63
1736 
1737     lowstrm.PutByte( 0 );  // successive approximation bit position
1738                            // high & low - (0,0) for sequental DCT
1739 
1740     // encode data
1741     for( y = 0; y < height; y += y_step, data += y_step*step )
1742     {
1743         for( x = 0; x < width; x += x_step )
1744         {
1745             int x_limit = x_step;
1746             int y_limit = y_step;
1747             const uchar* rgb_data = data + x*_channels;
1748             int* Y_data = block[0];
1749 
1750             if( x + x_limit > width ) x_limit = width - x;
1751             if( y + y_limit > height ) y_limit = height - y;
1752 
1753             memset( block, 0, block_count*64*sizeof(block[0][0]));
1754 
1755             if( channels > 1 )
1756             {
1757                 int* UV_data = block[luma_count];
1758 
1759                 for( i = 0; i < y_limit; i++, rgb_data += step, Y_data += Y_step )
1760                 {
1761                     for( j = 0; j < x_limit; j++, rgb_data += _channels )
1762                     {
1763                         int r = rgb_data[2];
1764                         int g = rgb_data[1];
1765                         int b = rgb_data[0];
1766 
1767                         int Y = descale( r*y_r + g*y_g + b*y_b, fixc - 2) - 128*4;
1768                         int U = descale( r*cb_r + g*cb_g + b*cb_b, fixc - 2 );
1769                         int V = descale( r*cr_r + g*cr_g + b*cr_b, fixc - 2 );
1770                         int j2 = j >> (x_scale - 1);
1771 
1772                         Y_data[j] = Y;
1773                         UV_data[j2] += U;
1774                         UV_data[j2 + 8] += V;
1775                     }
1776 
1777                     rgb_data -= x_limit*_channels;
1778                     if( ((i+1) & (y_scale - 1)) == 0 )
1779                     {
1780                         UV_data += UV_step;
1781                     }
1782                 }
1783             }
1784             else
1785             {
1786                 for( i = 0; i < y_limit; i++, rgb_data += step, Y_data += Y_step )
1787                 {
1788                     for( j = 0; j < x_limit; j++ )
1789                         Y_data[j] = rgb_data[j]*4 - 128*4;
1790                 }
1791             }
1792 
1793             for( i = 0; i < block_count; i++ )
1794             {
1795                 int is_chroma = i >= luma_count;
1796                 int src_step = x_scale * 8;
1797                 int run = 0, val;
1798                 int* src_ptr = block[i & -2] + (i & 1)*8;
1799                 const ulong* htable = huff_ac_tab[is_chroma];
1800 
1801                 aan_fdct8x8( src_ptr, buffer, src_step, fdct_qtab[is_chroma] );
1802 
1803                 j = is_chroma + (i > luma_count);
1804                 val = buffer[0] - dc_pred[j];
1805                 dc_pred[j] = buffer[0];
1806 
1807                 {
1808                 float a = (float)val;
1809                 int cat = (((int&)a >> 23) & 255) - (126 & (val ? -1 : 0));
1810 
1811                 assert( cat <= 11 );
1812                 m_strm.PutHuff( cat, huff_dc_tab[is_chroma] );
1813                 m_strm.Put( val - (val < 0 ? 1 : 0), cat );
1814                 }
1815 
1816                 for( j = 1; j < 64; j++ )
1817                 {
1818                     val = buffer[zigzag[j]];
1819 
1820                     if( val == 0 )
1821                     {
1822                         run++;
1823                     }
1824                     else
1825                     {
1826                         while( run >= 16 )
1827                         {
1828                             m_strm.PutHuff( 0xF0, htable ); // encode 16 zeros
1829                             run -= 16;
1830                         }
1831 
1832                         {
1833                         float a = (float)val;
1834                         int cat = (((int&)a >> 23) & 255) - (126 & (val ? -1 : 0));
1835 
1836                         assert( cat <= 10 );
1837                         m_strm.PutHuff( cat + run*16, htable );
1838                         m_strm.Put( val - (val < 0 ? 1 : 0), cat );
1839                         }
1840 
1841                         run = 0;
1842                     }
1843                 }
1844 
1845                 if( run )
1846                 {
1847                     m_strm.PutHuff( 0x00, htable ); // encode EOB
1848                 }
1849             }
1850         }
1851     }
1852 
1853     // Flush
1854     m_strm.Flush();
1855 
1856     lowstrm.PutWord( 0xFFD9 ); // EOI marker
1857     m_strm.Close();
1858 
1859     return true;
1860 }
1861 
1862 #endif
1863 
1864 /* End of file. */
1865 
1866 
1867