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