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 59 static char errStr[JMSG_LENGTH_MAX]="No error"; 60 61 struct my_error_mgr 62 { 63 struct jpeg_error_mgr pub; 64 jmp_buf setjmp_buffer; 65 }; 66 typedef struct my_error_mgr *my_error_ptr; 67 68 static 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 77 static 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 85 enum {COMPRESS=1, DECOMPRESS=2}; 86 87 typedef 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 97 static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3}; 98 99 #define NUMSF 4 100 static 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 116 static 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 140 static 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 205 static 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 259 static 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 308 static 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 369 static 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 432 DLLEXPORT char* DLLCALL tjGetErrorStr(void) 433 { 434 return errStr; 435 } 436 437 438 DLLEXPORT 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 451 static boolean empty_output_buffer(j_compress_ptr cinfo) 452 { 453 ERREXIT(cinfo, JERR_BUFFER_SIZE); 454 return TRUE; 455 } 456 457 static void dst_noop(j_compress_ptr cinfo) 458 { 459 } 460 461 static 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 484 DLLEXPORT 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 498 DLLEXPORT 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 // This allows for rare corner cases in which a JPEG image can actually be 506 // larger than the uncompressed input (we wouldn't mention it if it hadn't 507 // happened before.) 508 mcuw=tjMCUWidth[jpegSubsamp]; 509 mcuh=tjMCUHeight[jpegSubsamp]; 510 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh); 511 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048; 512 513 bailout: 514 return retval; 515 } 516 517 518 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height) 519 { 520 unsigned long retval=0; 521 if(width<1 || height<1) 522 _throw("TJBUFSIZE(): Invalid argument"); 523 524 // This allows for rare corner cases in which a JPEG image can actually be 525 // larger than the uncompressed input (we wouldn't mention it if it hadn't 526 // happened before.) 527 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048; 528 529 bailout: 530 return retval; 531 } 532 533 534 DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, 535 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, 536 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags) 537 { 538 int i, retval=0; JSAMPROW *row_pointer=NULL; 539 #ifndef JCS_EXTENSIONS 540 unsigned char *rgbBuf=NULL; 541 #endif 542 543 getinstance(handle) 544 if((this->init&COMPRESS)==0) 545 _throw("tjCompress2(): Instance has not been initialized for compression"); 546 547 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0 548 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL 549 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100) 550 _throw("tjCompress2(): Invalid argument"); 551 552 if(setjmp(this->jerr.setjmp_buffer)) 553 { 554 /* If we get here, the JPEG code has signaled an error. */ 555 retval=-1; 556 goto bailout; 557 } 558 559 if(pitch==0) pitch=width*tjPixelSize[pixelFormat]; 560 561 #ifndef JCS_EXTENSIONS 562 if(pixelFormat!=TJPF_GRAY) 563 { 564 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE); 565 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure"); 566 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf); 567 pitch=width*RGB_PIXELSIZE; 568 } 569 #endif 570 571 cinfo->image_width=width; 572 cinfo->image_height=height; 573 574 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 575 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 576 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 577 578 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1) 579 return -1; 580 581 this->jdst.next_output_byte=*jpegBuf; 582 this->jdst.free_in_buffer=tjBufSize(width, height, jpegSubsamp); 583 584 jpeg_start_compress(cinfo, TRUE); 585 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL) 586 _throw("tjCompress2(): Memory allocation failure"); 587 for(i=0; i<height; i++) 588 { 589 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch]; 590 else row_pointer[i]=&srcBuf[i*pitch]; 591 } 592 while(cinfo->next_scanline<cinfo->image_height) 593 { 594 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline], 595 cinfo->image_height-cinfo->next_scanline); 596 } 597 jpeg_finish_compress(cinfo); 598 *jpegSize=tjBufSize(width, height, jpegSubsamp) 599 -(unsigned long)(this->jdst.free_in_buffer); 600 601 bailout: 602 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo); 603 #ifndef JCS_EXTENSIONS 604 if(rgbBuf) free(rgbBuf); 605 #endif 606 if(row_pointer) free(row_pointer); 607 return retval; 608 } 609 610 DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf, 611 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf, 612 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags) 613 { 614 int retval=0; unsigned long size; 615 retval=tjCompress2(handle, srcBuf, width, pitch, height, 616 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual, 617 flags); 618 *jpegSize=size; 619 return retval; 620 } 621 622 623 /* Decompressor */ 624 625 static boolean fill_input_buffer(j_decompress_ptr dinfo) 626 { 627 ERREXIT(dinfo, JERR_BUFFER_SIZE); 628 return TRUE; 629 } 630 631 static void skip_input_data(j_decompress_ptr dinfo, long num_bytes) 632 { 633 dinfo->src->next_input_byte += (size_t) num_bytes; 634 dinfo->src->bytes_in_buffer -= (size_t) num_bytes; 635 } 636 637 static void src_noop(j_decompress_ptr dinfo) 638 { 639 } 640 641 static tjhandle _tjInitDecompress(tjinstance *this) 642 { 643 /* This is also straight out of example.c */ 644 this->dinfo.err=jpeg_std_error(&this->jerr.pub); 645 this->jerr.pub.error_exit=my_error_exit; 646 this->jerr.pub.output_message=my_output_message; 647 648 if(setjmp(this->jerr.setjmp_buffer)) 649 { 650 /* If we get here, the JPEG code has signaled an error. */ 651 if(this) free(this); return NULL; 652 } 653 654 jpeg_create_decompress(&this->dinfo); 655 this->dinfo.src=&this->jsrc; 656 this->jsrc.init_source=src_noop; 657 this->jsrc.fill_input_buffer=fill_input_buffer; 658 this->jsrc.skip_input_data=skip_input_data; 659 this->jsrc.resync_to_restart=jpeg_resync_to_restart; 660 this->jsrc.term_source=src_noop; 661 662 this->init|=DECOMPRESS; 663 return (tjhandle)this; 664 } 665 666 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void) 667 { 668 tjinstance *this; 669 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL) 670 { 671 snprintf(errStr, JMSG_LENGTH_MAX, 672 "tjInitDecompress(): Memory allocation failure"); 673 return NULL; 674 } 675 MEMZERO(this, sizeof(tjinstance)); 676 return _tjInitDecompress(this); 677 } 678 679 680 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle, 681 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, 682 int *jpegSubsamp) 683 { 684 int retval=0; 685 686 getinstance(handle); 687 if((this->init&DECOMPRESS)==0) 688 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression"); 689 690 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL 691 || jpegSubsamp==NULL) 692 _throw("tjDecompressHeader2(): Invalid argument"); 693 694 if(setjmp(this->jerr.setjmp_buffer)) 695 { 696 /* If we get here, the JPEG code has signaled an error. */ 697 return -1; 698 } 699 700 this->jsrc.bytes_in_buffer=jpegSize; 701 this->jsrc.next_input_byte=jpegBuf; 702 jpeg_read_header(dinfo, TRUE); 703 704 *width=dinfo->image_width; 705 *height=dinfo->image_height; 706 *jpegSubsamp=getSubsamp(dinfo); 707 708 jpeg_abort_decompress(dinfo); 709 710 if(*jpegSubsamp<0) 711 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image"); 712 if(*width<1 || *height<1) 713 _throw("tjDecompressHeader2(): Invalid data returned in header"); 714 715 bailout: 716 return retval; 717 } 718 719 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle, 720 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height) 721 { 722 int jpegSubsamp; 723 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height, 724 &jpegSubsamp); 725 } 726 727 728 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors) 729 { 730 if(numscalingfactors==NULL) 731 { 732 snprintf(errStr, JMSG_LENGTH_MAX, 733 "tjGetScalingFactors(): Invalid argument"); 734 return NULL; 735 } 736 737 *numscalingfactors=NUMSF; 738 return (tjscalingfactor *)sf; 739 } 740 741 742 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf, 743 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, 744 int height, int pixelFormat, int flags) 745 { 746 int i, retval=0; JSAMPROW *row_pointer=NULL; 747 int jpegwidth, jpegheight, scaledw, scaledh; 748 #ifndef JCS_EXTENSIONS 749 unsigned char *rgbBuf=NULL; 750 unsigned char *_dstBuf=NULL; int _pitch=0; 751 #endif 752 753 getinstance(handle); 754 if((this->init&DECOMPRESS)==0) 755 _throw("tjDecompress2(): Instance has not been initialized for decompression"); 756 757 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0 758 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF) 759 _throw("tjDecompress2(): Invalid argument"); 760 761 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 762 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 763 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 764 765 if(setjmp(this->jerr.setjmp_buffer)) 766 { 767 /* If we get here, the JPEG code has signaled an error. */ 768 retval=-1; 769 goto bailout; 770 } 771 772 this->jsrc.bytes_in_buffer=jpegSize; 773 this->jsrc.next_input_byte=jpegBuf; 774 jpeg_read_header(dinfo, TRUE); 775 if(setDecompDefaults(dinfo, pixelFormat)==-1) 776 { 777 retval=-1; goto bailout; 778 } 779 780 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE; 781 782 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height; 783 if(width==0) width=jpegwidth; 784 if(height==0) height=jpegheight; 785 for(i=0; i<NUMSF; i++) 786 { 787 scaledw=TJSCALED(jpegwidth, sf[i]); 788 scaledh=TJSCALED(jpegheight, sf[i]); 789 if(scaledw<=width && scaledh<=height) 790 break; 791 } 792 if(scaledw>width || scaledh>height) 793 _throw("tjDecompress2(): Could not scale down to desired image dimensions"); 794 width=scaledw; height=scaledh; 795 dinfo->scale_num=sf[i].num; 796 dinfo->scale_denom=sf[i].denom; 797 798 jpeg_start_decompress(dinfo); 799 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat]; 800 801 #ifndef JCS_EXTENSIONS 802 if(pixelFormat!=TJPF_GRAY && 803 (RGB_RED!=tjRedOffset[pixelFormat] || 804 RGB_GREEN!=tjGreenOffset[pixelFormat] || 805 RGB_BLUE!=tjBlueOffset[pixelFormat] || 806 RGB_PIXELSIZE!=tjPixelSize[pixelFormat])) 807 { 808 rgbBuf=(unsigned char *)malloc(width*height*3); 809 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure"); 810 _pitch=pitch; pitch=width*3; 811 _dstBuf=dstBuf; dstBuf=rgbBuf; 812 } 813 #endif 814 815 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW) 816 *dinfo->output_height))==NULL) 817 _throw("tjDecompress2(): Memory allocation failure"); 818 for(i=0; i<(int)dinfo->output_height; i++) 819 { 820 if(flags&TJFLAG_BOTTOMUP) 821 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch]; 822 else row_pointer[i]=&dstBuf[i*pitch]; 823 } 824 while(dinfo->output_scanline<dinfo->output_height) 825 { 826 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline], 827 dinfo->output_height-dinfo->output_scanline); 828 } 829 jpeg_finish_decompress(dinfo); 830 831 #ifndef JCS_EXTENSIONS 832 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat); 833 #endif 834 835 bailout: 836 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo); 837 #ifndef JCS_EXTENSIONS 838 if(rgbBuf) free(rgbBuf); 839 #endif 840 if(row_pointer) free(row_pointer); 841 return retval; 842 } 843 844 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf, 845 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, 846 int height, int pixelSize, int flags) 847 { 848 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch, 849 height, getPixelFormat(pixelSize, flags), flags); 850 } 851