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