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
47GrFmtJpeg::GrFmtJpeg()
48{
49    m_sign_len = 3;
50    m_signature = "\xFF\xD8\xFF";
51    m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)";
52}
53
54
55GrFmtJpeg::~GrFmtJpeg()
56{
57}
58
59
60GrFmtReader* GrFmtJpeg::NewReader( const char* filename )
61{
62    return new GrFmtJpegReader( filename );
63}
64
65
66GrFmtWriter* 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__
91typedef unsigned char boolean;
92#endif
93
94extern "C" {
95#include "jpeglib.h"
96}
97
98/////////////////////// Error processing /////////////////////
99
100typedef struct GrFmtJpegErrorMgr
101{
102    struct jpeg_error_mgr pub;    /* "parent" structure */
103    jmp_buf setjmp_buffer;        /* jump label */
104}
105GrFmtJpegErrorMgr;
106
107
108METHODDEF(void)
109error_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
121GrFmtJpegReader::GrFmtJpegReader( const char* filename ) : GrFmtReader( filename )
122{
123    m_cinfo = 0;
124    m_f = 0;
125}
126
127
128GrFmtJpegReader::~GrFmtJpegReader()
129{
130}
131
132
133void  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
156bool  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 */
200static
201unsigned 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 */
265static
266int 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
328bool  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
420GrFmtJpegWriter::GrFmtJpegWriter( const char* filename ) : GrFmtWriter( filename )
421{
422}
423
424
425GrFmtJpegWriter::~GrFmtJpegWriter()
426{
427}
428
429
430bool  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
501RJpegBitStream::RJpegBitStream()
502{
503}
504
505RJpegBitStream::~RJpegBitStream()
506{
507    Close();
508}
509
510
511bool  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
522void  RJpegBitStream::Close()
523{
524    m_low_strm.Close();
525    m_is_opened = false;
526}
527
528
529void  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        }
557fetch_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
571void  RJpegBitStream::Flush()
572{
573    m_end = m_start + m_block_size;
574    m_current = m_end - 4;
575    m_bit_idx = 0;
576}
577
578void  RJpegBitStream::AlignOnByte()
579{
580    m_bit_idx &= -8;
581}
582
583int  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
597static 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
607static 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
656static 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
772static const int max_dec_htable_size = 1 << 12;
773static const int first_table_bits = 9;
774
775GrFmtJpegReader::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
789GrFmtJpegReader::~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
801void  GrFmtJpegReader::Close()
802{
803    m_strm.Close();
804    GrFmtReader::Close();
805}
806
807
808bool 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        }
915parsing_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
929bool 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
972bool 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
1013bool 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        }
1098decoding_end: ;
1099    }
1100
1101    return true;
1102}
1103
1104
1105void  GrFmtJpegReader::ResetDecoder()
1106{
1107    m_ci[0].dc_pred = m_ci[1].dc_pred = m_ci[2].dc_pred = 0;
1108}
1109
1110void  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
1283void  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
1322WJpegBitStream::WJpegBitStream()
1323{
1324}
1325
1326
1327WJpegBitStream::~WJpegBitStream()
1328{
1329    Close();
1330    m_is_opened = false;
1331}
1332
1333
1334
1335bool  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
1350void  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
1361void  WJpegBitStream::Flush()
1362{
1363    Put( -1, m_bit_idx & 31 );
1364    *((ulong*&)m_current)++ = m_val;
1365    WriteBlock();
1366    ResetBuffer();
1367}
1368
1369
1370void  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
1392GrFmtJpegWriter::GrFmtJpegWriter( const char* filename ) : GrFmtWriter( filename )
1393{
1394}
1395
1396GrFmtJpegWriter::~GrFmtJpegWriter()
1397{
1398}
1399
1400//  Standard JPEG quantization tables
1401static 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
1414static 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.
1430static 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.
1438static 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.
1446static 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
1473static 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
1500static 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
1513static 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
1619bool  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