1/* 2 * Copyright (C)2009-2012 D. R. Commander. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * - Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright notice, 10 * this list of conditions and the following disclaimer in the documentation 11 * and/or other materials provided with the distribution. 12 * - Neither the name of the libjpeg-turbo Project nor the names of its 13 * contributors may be used to endorse or promote products derived from this 14 * software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* TurboJPEG/OSS: this implements the TurboJPEG API using libjpeg-turbo */ 30 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34#ifndef JCS_EXTENSIONS 35#define JPEG_INTERNAL_OPTIONS 36#endif 37#include <jpeglib.h> 38#include <jerror.h> 39#include <setjmp.h> 40#include "./turbojpeg.h" 41 42#define PAD(v, p) ((v+(p)-1)&(~((p)-1))) 43 44#define CSTATE_START 100 45#define DSTATE_START 200 46#define MEMZERO(ptr, size) memset(ptr, 0, size) 47 48#ifndef min 49 #define min(a,b) ((a)<(b)?(a):(b)) 50#endif 51 52#ifndef max 53 #define max(a,b) ((a)>(b)?(a):(b)) 54#endif 55 56 57/* Error handling (based on example in example.c) */ 58 59static char errStr[JMSG_LENGTH_MAX]="No error"; 60 61struct my_error_mgr 62{ 63 struct jpeg_error_mgr pub; 64 jmp_buf setjmp_buffer; 65}; 66typedef struct my_error_mgr *my_error_ptr; 67 68static void my_error_exit(j_common_ptr cinfo) 69{ 70 my_error_ptr myerr=(my_error_ptr)cinfo->err; 71 (*cinfo->err->output_message)(cinfo); 72 longjmp(myerr->setjmp_buffer, 1); 73} 74 75/* Based on output_message() in jerror.c */ 76 77static void my_output_message(j_common_ptr cinfo) 78{ 79 (*cinfo->err->format_message)(cinfo, errStr); 80} 81 82 83/* Global structures, macros, etc. */ 84 85enum {COMPRESS=1, DECOMPRESS=2}; 86 87typedef struct _tjinstance 88{ 89 struct jpeg_compress_struct cinfo; 90 struct jpeg_decompress_struct dinfo; 91 struct jpeg_destination_mgr jdst; 92 struct jpeg_source_mgr jsrc; 93 struct my_error_mgr jerr; 94 int init; 95} tjinstance; 96 97static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3}; 98 99#define NUMSF 4 100static const tjscalingfactor sf[NUMSF]={ 101 {1, 1}, 102 {1, 2}, 103 {1, 4}, 104 {1, 8} 105}; 106 107#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \ 108 retval=-1; goto bailout;} 109#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \ 110 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \ 111 (void) cinfo; (void) dinfo; /* silence warnings */ \ 112 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \ 113 return -1;} \ 114 cinfo=&this->cinfo; dinfo=&this->dinfo; 115 116static int getPixelFormat(int pixelSize, int flags) 117{ 118 if(pixelSize==1) return TJPF_GRAY; 119 if(pixelSize==3) 120 { 121 if(flags&TJ_BGR) return TJPF_BGR; 122 else return TJPF_RGB; 123 } 124 if(pixelSize==4) 125 { 126 if(flags&TJ_ALPHAFIRST) 127 { 128 if(flags&TJ_BGR) return TJPF_XBGR; 129 else return TJPF_XRGB; 130 } 131 else 132 { 133 if(flags&TJ_BGR) return TJPF_BGRX; 134 else return TJPF_RGBX; 135 } 136 } 137 return -1; 138} 139 140static int setCompDefaults(struct jpeg_compress_struct *cinfo, 141 int pixelFormat, int subsamp, int jpegQual) 142{ 143 int retval=0; 144 145 switch(pixelFormat) 146 { 147 case TJPF_GRAY: 148 cinfo->in_color_space=JCS_GRAYSCALE; break; 149 #if JCS_EXTENSIONS==1 150 case TJPF_RGB: 151 cinfo->in_color_space=JCS_EXT_RGB; break; 152 case TJPF_BGR: 153 cinfo->in_color_space=JCS_EXT_BGR; break; 154 case TJPF_RGBX: 155 case TJPF_RGBA: 156 cinfo->in_color_space=JCS_EXT_RGBX; break; 157 case TJPF_BGRX: 158 case TJPF_BGRA: 159 cinfo->in_color_space=JCS_EXT_BGRX; break; 160 case TJPF_XRGB: 161 case TJPF_ARGB: 162 cinfo->in_color_space=JCS_EXT_XRGB; break; 163 case TJPF_XBGR: 164 case TJPF_ABGR: 165 cinfo->in_color_space=JCS_EXT_XBGR; break; 166 #else 167 case TJPF_RGB: 168 case TJPF_BGR: 169 case TJPF_RGBX: 170 case TJPF_BGRX: 171 case TJPF_XRGB: 172 case TJPF_XBGR: 173 case TJPF_RGBA: 174 case TJPF_BGRA: 175 case TJPF_ARGB: 176 case TJPF_ABGR: 177 cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB; 178 break; 179 #endif 180 } 181 182 cinfo->input_components=tjPixelSize[pixelFormat]; 183 jpeg_set_defaults(cinfo); 184 if(jpegQual>=0) 185 { 186 jpeg_set_quality(cinfo, jpegQual, TRUE); 187 if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW; 188 else cinfo->dct_method=JDCT_FASTEST; 189 } 190 if(subsamp==TJSAMP_GRAY) 191 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); 192 else 193 jpeg_set_colorspace(cinfo, JCS_YCbCr); 194 195 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8; 196 cinfo->comp_info[1].h_samp_factor=1; 197 cinfo->comp_info[2].h_samp_factor=1; 198 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8; 199 cinfo->comp_info[1].v_samp_factor=1; 200 cinfo->comp_info[2].v_samp_factor=1; 201 202 return retval; 203} 204 205static int setDecompDefaults(struct jpeg_decompress_struct *dinfo, 206 int pixelFormat) 207{ 208 int retval=0; 209 210 switch(pixelFormat) 211 { 212 case TJPF_GRAY: 213 dinfo->out_color_space=JCS_GRAYSCALE; break; 214 #if JCS_EXTENSIONS==1 215 case TJPF_RGB: 216 dinfo->out_color_space=JCS_EXT_RGB; break; 217 case TJPF_BGR: 218 dinfo->out_color_space=JCS_EXT_BGR; break; 219 case TJPF_RGBX: 220 dinfo->out_color_space=JCS_EXT_RGBX; break; 221 case TJPF_BGRX: 222 dinfo->out_color_space=JCS_EXT_BGRX; break; 223 case TJPF_XRGB: 224 dinfo->out_color_space=JCS_EXT_XRGB; break; 225 case TJPF_XBGR: 226 dinfo->out_color_space=JCS_EXT_XBGR; break; 227 #if JCS_ALPHA_EXTENSIONS==1 228 case TJPF_RGBA: 229 dinfo->out_color_space=JCS_EXT_RGBA; break; 230 case TJPF_BGRA: 231 dinfo->out_color_space=JCS_EXT_BGRA; break; 232 case TJPF_ARGB: 233 dinfo->out_color_space=JCS_EXT_ARGB; break; 234 case TJPF_ABGR: 235 dinfo->out_color_space=JCS_EXT_ABGR; break; 236 #endif 237 #else 238 case TJPF_RGB: 239 case TJPF_BGR: 240 case TJPF_RGBX: 241 case TJPF_BGRX: 242 case TJPF_XRGB: 243 case TJPF_XBGR: 244 case TJPF_RGBA: 245 case TJPF_BGRA: 246 case TJPF_ARGB: 247 case TJPF_ABGR: 248 dinfo->out_color_space=JCS_RGB; break; 249 #endif 250 default: 251 _throw("Unsupported pixel format"); 252 } 253 254 bailout: 255 return retval; 256} 257 258 259static int getSubsamp(j_decompress_ptr dinfo) 260{ 261 int retval=-1, i, k; 262 for(i=0; i<NUMSUBOPT; i++) 263 { 264 if(dinfo->num_components==pixelsize[i]) 265 { 266 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8 267 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8) 268 { 269 int match=0; 270 for(k=1; k<dinfo->num_components; k++) 271 { 272 if(dinfo->comp_info[k].h_samp_factor==1 273 && dinfo->comp_info[k].v_samp_factor==1) 274 match++; 275 } 276 if(match==dinfo->num_components-1) 277 { 278 retval=i; break; 279 } 280 } 281 } 282 } 283 return retval; 284} 285 286 287#ifndef JCS_EXTENSIONS 288 289/* Conversion functions to emulate the colorspace extensions. This allows the 290 TurboJPEG wrapper to be used with libjpeg */ 291 292#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \ 293 int rowPad=pitch-width*PS; \ 294 while(height--) \ 295 { \ 296 unsigned char *endOfRow=src+width*PS; \ 297 while(src<endOfRow) \ 298 { \ 299 dst[RGB_RED]=src[ROFFSET]; \ 300 dst[RGB_GREEN]=src[GOFFSET]; \ 301 dst[RGB_BLUE]=src[BOFFSET]; \ 302 dst+=RGB_PIXELSIZE; src+=PS; \ 303 } \ 304 src+=rowPad; \ 305 } \ 306} 307 308static unsigned char *toRGB(unsigned char *src, int width, int pitch, 309 int height, int pixelFormat, unsigned char *dst) 310{ 311 unsigned char *retval=src; 312 switch(pixelFormat) 313 { 314 case TJPF_RGB: 315 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3 316 retval=dst; TORGB(3, 0, 1, 2); 317 #endif 318 break; 319 case TJPF_BGR: 320 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3 321 retval=dst; TORGB(3, 2, 1, 0); 322 #endif 323 break; 324 case TJPF_RGBX: 325 case TJPF_RGBA: 326 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4 327 retval=dst; TORGB(4, 0, 1, 2); 328 #endif 329 break; 330 case TJPF_BGRX: 331 case TJPF_BGRA: 332 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4 333 retval=dst; TORGB(4, 2, 1, 0); 334 #endif 335 break; 336 case TJPF_XRGB: 337 case TJPF_ARGB: 338 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4 339 retval=dst; TORGB(4, 1, 2, 3); 340 #endif 341 break; 342 case TJPF_XBGR: 343 case TJPF_ABGR: 344 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4 345 retval=dst; TORGB(4, 3, 2, 1); 346 #endif 347 break; 348 } 349 return retval; 350} 351 352#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \ 353 int rowPad=pitch-width*PS; \ 354 while(height--) \ 355 { \ 356 unsigned char *endOfRow=dst+width*PS; \ 357 while(dst<endOfRow) \ 358 { \ 359 dst[ROFFSET]=src[RGB_RED]; \ 360 dst[GOFFSET]=src[RGB_GREEN]; \ 361 dst[BOFFSET]=src[RGB_BLUE]; \ 362 SETALPHA \ 363 dst+=PS; src+=RGB_PIXELSIZE; \ 364 } \ 365 dst+=rowPad; \ 366 } \ 367} 368 369static void fromRGB(unsigned char *src, unsigned char *dst, int width, 370 int pitch, int height, int pixelFormat) 371{ 372 switch(pixelFormat) 373 { 374 case TJPF_RGB: 375 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3 376 FROMRGB(3, 0, 1, 2,); 377 #endif 378 break; 379 case TJPF_BGR: 380 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3 381 FROMRGB(3, 2, 1, 0,); 382 #endif 383 break; 384 case TJPF_RGBX: 385 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4 386 FROMRGB(4, 0, 1, 2,); 387 #endif 388 break; 389 case TJPF_RGBA: 390 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4 391 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;); 392 #endif 393 break; 394 case TJPF_BGRX: 395 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4 396 FROMRGB(4, 2, 1, 0,); 397 #endif 398 break; 399 case TJPF_BGRA: 400 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4 401 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return; 402 #endif 403 break; 404 case TJPF_XRGB: 405 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4 406 FROMRGB(4, 1, 2, 3,); return; 407 #endif 408 break; 409 case TJPF_ARGB: 410 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4 411 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return; 412 #endif 413 break; 414 case TJPF_XBGR: 415 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4 416 FROMRGB(4, 3, 2, 1,); return; 417 #endif 418 break; 419 case TJPF_ABGR: 420 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4 421 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return; 422 #endif 423 break; 424 } 425} 426 427#endif 428 429 430/* General API functions */ 431 432DLLEXPORT char* DLLCALL tjGetErrorStr(void) 433{ 434 return errStr; 435} 436 437 438DLLEXPORT int DLLCALL tjDestroy(tjhandle handle) 439{ 440 getinstance(handle); 441 if(setjmp(this->jerr.setjmp_buffer)) return -1; 442 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo); 443 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo); 444 free(this); 445 return 0; 446} 447 448 449/* Compressor */ 450 451static boolean empty_output_buffer(j_compress_ptr cinfo) 452{ 453 ERREXIT(cinfo, JERR_BUFFER_SIZE); 454 return TRUE; 455} 456 457static void dst_noop(j_compress_ptr cinfo) 458{ 459} 460 461static tjhandle _tjInitCompress(tjinstance *this) 462{ 463 /* This is also straight out of example.c */ 464 this->cinfo.err=jpeg_std_error(&this->jerr.pub); 465 this->jerr.pub.error_exit=my_error_exit; 466 this->jerr.pub.output_message=my_output_message; 467 468 if(setjmp(this->jerr.setjmp_buffer)) 469 { 470 /* If we get here, the JPEG code has signaled an error. */ 471 if(this) free(this); return NULL; 472 } 473 474 jpeg_create_compress(&this->cinfo); 475 this->cinfo.dest=&this->jdst; 476 this->jdst.init_destination=dst_noop; 477 this->jdst.empty_output_buffer=empty_output_buffer; 478 this->jdst.term_destination=dst_noop; 479 480 this->init|=COMPRESS; 481 return (tjhandle)this; 482} 483 484DLLEXPORT tjhandle DLLCALL tjInitCompress(void) 485{ 486 tjinstance *this=NULL; 487 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL) 488 { 489 snprintf(errStr, JMSG_LENGTH_MAX, 490 "tjInitCompress(): Memory allocation failure"); 491 return NULL; 492 } 493 MEMZERO(this, sizeof(tjinstance)); 494 return _tjInitCompress(this); 495} 496 497 498DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height, 499 int jpegSubsamp) 500{ 501 unsigned long retval=0; int mcuw, mcuh, chromasf; 502 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT) 503 _throw("tjBufSize(): Invalid argument"); 504 505 /* 506 * This allows for rare corner cases in which a JPEG image can actually be 507 * larger than the uncompressed input (we wouldn't mention it if it hadn't 508 * happened before.) 509 */ 510 mcuw=tjMCUWidth[jpegSubsamp]; 511 mcuh=tjMCUHeight[jpegSubsamp]; 512 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh); 513 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048; 514 515 bailout: 516 return retval; 517} 518 519 520DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height) 521{ 522 unsigned long retval=0; 523 if(width<1 || height<1) 524 _throw("TJBUFSIZE(): Invalid argument"); 525 526 /* 527 * This allows for rare corner cases in which a JPEG image can actually be 528 * larger than the uncompressed input (we wouldn't mention it if it hadn't 529 * happened before.) 530 */ 531 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048; 532 533 bailout: 534 return retval; 535} 536 537 538DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, 539 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, 540 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags) 541{ 542 int i, retval=0; JSAMPROW *row_pointer=NULL; 543 #ifndef JCS_EXTENSIONS 544 unsigned char *rgbBuf=NULL; 545 #endif 546 547 getinstance(handle) 548 if((this->init&COMPRESS)==0) 549 _throw("tjCompress2(): Instance has not been initialized for compression"); 550 551 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0 552 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL 553 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100) 554 _throw("tjCompress2(): Invalid argument"); 555 556 if(setjmp(this->jerr.setjmp_buffer)) 557 { 558 /* If we get here, the JPEG code has signaled an error. */ 559 retval=-1; 560 goto bailout; 561 } 562 563 if(pitch==0) pitch=width*tjPixelSize[pixelFormat]; 564 565 #ifndef JCS_EXTENSIONS 566 if(pixelFormat!=TJPF_GRAY) 567 { 568 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE); 569 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure"); 570 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf); 571 pitch=width*RGB_PIXELSIZE; 572 } 573 #endif 574 575 cinfo->image_width=width; 576 cinfo->image_height=height; 577 578 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 579 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 580 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 581 582 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1) 583 return -1; 584 585 this->jdst.next_output_byte=*jpegBuf; 586 this->jdst.free_in_buffer=tjBufSize(width, height, jpegSubsamp); 587 588 jpeg_start_compress(cinfo, TRUE); 589 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL) 590 _throw("tjCompress2(): Memory allocation failure"); 591 for(i=0; i<height; i++) 592 { 593 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch]; 594 else row_pointer[i]=&srcBuf[i*pitch]; 595 } 596 while(cinfo->next_scanline<cinfo->image_height) 597 { 598 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline], 599 cinfo->image_height-cinfo->next_scanline); 600 } 601 jpeg_finish_compress(cinfo); 602 *jpegSize=tjBufSize(width, height, jpegSubsamp) 603 -(unsigned long)(this->jdst.free_in_buffer); 604 605 bailout: 606 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo); 607 #ifndef JCS_EXTENSIONS 608 if(rgbBuf) free(rgbBuf); 609 #endif 610 if(row_pointer) free(row_pointer); 611 return retval; 612} 613 614DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf, 615 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf, 616 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags) 617{ 618 int retval=0; unsigned long size; 619 retval=tjCompress2(handle, srcBuf, width, pitch, height, 620 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual, 621 flags); 622 *jpegSize=size; 623 return retval; 624} 625 626 627/* Decompressor */ 628 629static boolean fill_input_buffer(j_decompress_ptr dinfo) 630{ 631 ERREXIT(dinfo, JERR_BUFFER_SIZE); 632 return TRUE; 633} 634 635static void skip_input_data(j_decompress_ptr dinfo, long num_bytes) 636{ 637 dinfo->src->next_input_byte += (size_t) num_bytes; 638 dinfo->src->bytes_in_buffer -= (size_t) num_bytes; 639} 640 641static void src_noop(j_decompress_ptr dinfo) 642{ 643} 644 645static tjhandle _tjInitDecompress(tjinstance *this) 646{ 647 /* This is also straight out of example.c */ 648 this->dinfo.err=jpeg_std_error(&this->jerr.pub); 649 this->jerr.pub.error_exit=my_error_exit; 650 this->jerr.pub.output_message=my_output_message; 651 652 if(setjmp(this->jerr.setjmp_buffer)) 653 { 654 /* If we get here, the JPEG code has signaled an error. */ 655 if(this) free(this); return NULL; 656 } 657 658 jpeg_create_decompress(&this->dinfo); 659 this->dinfo.src=&this->jsrc; 660 this->jsrc.init_source=src_noop; 661 this->jsrc.fill_input_buffer=fill_input_buffer; 662 this->jsrc.skip_input_data=skip_input_data; 663 this->jsrc.resync_to_restart=jpeg_resync_to_restart; 664 this->jsrc.term_source=src_noop; 665 666 this->init|=DECOMPRESS; 667 return (tjhandle)this; 668} 669 670DLLEXPORT tjhandle DLLCALL tjInitDecompress(void) 671{ 672 tjinstance *this; 673 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL) 674 { 675 snprintf(errStr, JMSG_LENGTH_MAX, 676 "tjInitDecompress(): Memory allocation failure"); 677 return NULL; 678 } 679 MEMZERO(this, sizeof(tjinstance)); 680 return _tjInitDecompress(this); 681} 682 683 684DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle, 685 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, 686 int *jpegSubsamp) 687{ 688 int retval=0; 689 690 getinstance(handle); 691 if((this->init&DECOMPRESS)==0) 692 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression"); 693 694 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL 695 || jpegSubsamp==NULL) 696 _throw("tjDecompressHeader2(): Invalid argument"); 697 698 if(setjmp(this->jerr.setjmp_buffer)) 699 { 700 /* If we get here, the JPEG code has signaled an error. */ 701 return -1; 702 } 703 704 this->jsrc.bytes_in_buffer=jpegSize; 705 this->jsrc.next_input_byte=jpegBuf; 706 jpeg_read_header(dinfo, TRUE); 707 708 *width=dinfo->image_width; 709 *height=dinfo->image_height; 710 *jpegSubsamp=getSubsamp(dinfo); 711 712 jpeg_abort_decompress(dinfo); 713 714 if(*jpegSubsamp<0) 715 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image"); 716 if(*width<1 || *height<1) 717 _throw("tjDecompressHeader2(): Invalid data returned in header"); 718 719 bailout: 720 return retval; 721} 722 723DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle, 724 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height) 725{ 726 int jpegSubsamp; 727 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height, 728 &jpegSubsamp); 729} 730 731 732DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors) 733{ 734 if(numscalingfactors==NULL) 735 { 736 snprintf(errStr, JMSG_LENGTH_MAX, 737 "tjGetScalingFactors(): Invalid argument"); 738 return NULL; 739 } 740 741 *numscalingfactors=NUMSF; 742 return (tjscalingfactor *)sf; 743} 744 745 746DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf, 747 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, 748 int height, int pixelFormat, int flags) 749{ 750 int i, retval=0; JSAMPROW *row_pointer=NULL; 751 int jpegwidth, jpegheight, scaledw, scaledh; 752 #ifndef JCS_EXTENSIONS 753 unsigned char *rgbBuf=NULL; 754 unsigned char *_dstBuf=NULL; int _pitch=0; 755 #endif 756 757 getinstance(handle); 758 if((this->init&DECOMPRESS)==0) 759 _throw("tjDecompress2(): Instance has not been initialized for decompression"); 760 761 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0 762 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF) 763 _throw("tjDecompress2(): Invalid argument"); 764 765 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 766 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 767 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 768 769 if(setjmp(this->jerr.setjmp_buffer)) 770 { 771 /* If we get here, the JPEG code has signaled an error. */ 772 retval=-1; 773 goto bailout; 774 } 775 776 this->jsrc.bytes_in_buffer=jpegSize; 777 this->jsrc.next_input_byte=jpegBuf; 778 jpeg_read_header(dinfo, TRUE); 779 if(setDecompDefaults(dinfo, pixelFormat)==-1) 780 { 781 retval=-1; goto bailout; 782 } 783 784 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE; 785 786 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height; 787 if(width==0) width=jpegwidth; 788 if(height==0) height=jpegheight; 789 for(i=0; i<NUMSF; i++) 790 { 791 scaledw=TJSCALED(jpegwidth, sf[i]); 792 scaledh=TJSCALED(jpegheight, sf[i]); 793 if(scaledw<=width && scaledh<=height) 794 break; 795 } 796 if(scaledw>width || scaledh>height) 797 _throw("tjDecompress2(): Could not scale down to desired image dimensions"); 798 width=scaledw; height=scaledh; 799 dinfo->scale_num=sf[i].num; 800 dinfo->scale_denom=sf[i].denom; 801 802 jpeg_start_decompress(dinfo); 803 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat]; 804 805 #ifndef JCS_EXTENSIONS 806 if(pixelFormat!=TJPF_GRAY && 807 (RGB_RED!=tjRedOffset[pixelFormat] || 808 RGB_GREEN!=tjGreenOffset[pixelFormat] || 809 RGB_BLUE!=tjBlueOffset[pixelFormat] || 810 RGB_PIXELSIZE!=tjPixelSize[pixelFormat])) 811 { 812 rgbBuf=(unsigned char *)malloc(width*height*3); 813 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure"); 814 _pitch=pitch; pitch=width*3; 815 _dstBuf=dstBuf; dstBuf=rgbBuf; 816 } 817 #endif 818 819 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW) 820 *dinfo->output_height))==NULL) 821 _throw("tjDecompress2(): Memory allocation failure"); 822 for(i=0; i<(int)dinfo->output_height; i++) 823 { 824 if(flags&TJFLAG_BOTTOMUP) 825 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch]; 826 else row_pointer[i]=&dstBuf[i*pitch]; 827 } 828 while(dinfo->output_scanline<dinfo->output_height) 829 { 830 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline], 831 dinfo->output_height-dinfo->output_scanline); 832 } 833 jpeg_finish_decompress(dinfo); 834 835 #ifndef JCS_EXTENSIONS 836 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat); 837 #endif 838 839 bailout: 840 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo); 841 #ifndef JCS_EXTENSIONS 842 if(rgbBuf) free(rgbBuf); 843 #endif 844 if(row_pointer) free(row_pointer); 845 return retval; 846} 847 848DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf, 849 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, 850 int height, int pixelSize, int flags) 851{ 852 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch, 853 height, getPixelFormat(pixelSize, flags), flags); 854} 855