turbojpeg.c revision 67ce3b2352fe1f7511edbfed74ec6960e41e97dc
1/* 2 * Copyright (C)2009-2011 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 <jinclude.h> 34#define JPEG_INTERNALS 35#include <jpeglib.h> 36#include <jerror.h> 37#include <setjmp.h> 38#include "./turbojpeg.h" 39#include "./tjutil.h" 40#include "transupp.h" 41 42extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, 43 unsigned long *, boolean); 44extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long); 45 46#define PAD(v, p) ((v+(p)-1)&(~((p)-1))) 47 48 49/* Error handling (based on example in example.c) */ 50 51static char errStr[JMSG_LENGTH_MAX]="No error"; 52 53struct my_error_mgr 54{ 55 struct jpeg_error_mgr pub; 56 jmp_buf setjmp_buffer; 57}; 58typedef struct my_error_mgr *my_error_ptr; 59 60static void my_error_exit(j_common_ptr cinfo) 61{ 62 my_error_ptr myerr=(my_error_ptr)cinfo->err; 63 (*cinfo->err->output_message)(cinfo); 64 longjmp(myerr->setjmp_buffer, 1); 65} 66 67/* Based on output_message() in jerror.c */ 68 69static void my_output_message(j_common_ptr cinfo) 70{ 71 (*cinfo->err->format_message)(cinfo, errStr); 72} 73 74 75/* Global structures, macros, etc. */ 76 77enum {COMPRESS=1, DECOMPRESS=2}; 78 79typedef struct _tjinstance 80{ 81 struct jpeg_compress_struct cinfo; 82 struct jpeg_decompress_struct dinfo; 83 struct my_error_mgr jerr; 84 int init; 85} tjinstance; 86 87static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3}; 88 89static const JXFORM_CODE xformtypes[TJ_NUMXOP]= 90{ 91 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE, 92 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270 93}; 94 95#define NUMSF 4 96static const tjscalingfactor sf[NUMSF]={ 97 {1, 1}, 98 {1, 2}, 99 {1, 4}, 100 {1, 8} 101}; 102 103#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \ 104 retval=-1; goto bailout;} 105#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \ 106 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \ 107 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \ 108 return -1;} \ 109 cinfo=&this->cinfo; dinfo=&this->dinfo; 110 111static int getPixelFormat(int pixelSize, int flags) 112{ 113 if(pixelSize==1) return TJPF_GRAY; 114 if(pixelSize==3) 115 { 116 if(flags&TJ_BGR) return TJPF_BGR; 117 else return TJPF_RGB; 118 } 119 if(pixelSize==4) 120 { 121 if(flags&TJ_ALPHAFIRST) 122 { 123 if(flags&TJ_BGR) return TJPF_XBGR; 124 else return TJPF_XRGB; 125 } 126 else 127 { 128 if(flags&TJ_BGR) return TJPF_BGRX; 129 else return TJPF_RGBX; 130 } 131 } 132 return -1; 133} 134 135static int setCompDefaults(struct jpeg_compress_struct *cinfo, 136 int pixelFormat, int subsamp, int jpegQual) 137{ 138 int retval=0; 139 140 switch(pixelFormat) 141 { 142 case TJPF_GRAY: 143 cinfo->in_color_space=JCS_GRAYSCALE; break; 144 #if JCS_EXTENSIONS==1 145 case TJPF_RGB: 146 cinfo->in_color_space=JCS_EXT_RGB; break; 147 case TJPF_BGR: 148 cinfo->in_color_space=JCS_EXT_BGR; break; 149 case TJPF_RGBX: 150 case TJPF_RGBA: 151 cinfo->in_color_space=JCS_EXT_RGBX; break; 152 case TJPF_BGRX: 153 case TJPF_BGRA: 154 cinfo->in_color_space=JCS_EXT_BGRX; break; 155 case TJPF_XRGB: 156 case TJPF_ARGB: 157 cinfo->in_color_space=JCS_EXT_XRGB; break; 158 case TJPF_XBGR: 159 case TJPF_ABGR: 160 cinfo->in_color_space=JCS_EXT_XBGR; break; 161 #else 162 case TJPF_RGB: 163 if(RGB_RED==0 && RGB_GREEN==1 && RGB_BLUE==2 && RGB_PIXELSIZE==3) 164 { 165 cinfo->in_color_space=JCS_RGB; break; 166 } 167 default: 168 _throw("Unsupported pixel format"); 169 #endif 170 } 171 172 cinfo->input_components=tjPixelSize[pixelFormat]; 173 jpeg_set_defaults(cinfo); 174 if(jpegQual>=0) 175 { 176 jpeg_set_quality(cinfo, jpegQual, TRUE); 177 if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW; 178 else cinfo->dct_method=JDCT_FASTEST; 179 } 180 if(subsamp==TJSAMP_GRAY) 181 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); 182 else 183 jpeg_set_colorspace(cinfo, JCS_YCbCr); 184 185 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8; 186 cinfo->comp_info[1].h_samp_factor=1; 187 cinfo->comp_info[2].h_samp_factor=1; 188 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8; 189 cinfo->comp_info[1].v_samp_factor=1; 190 cinfo->comp_info[2].v_samp_factor=1; 191 192 #if JCS_EXTENSIONS!=1 193 bailout: 194 #endif 195 return retval; 196} 197 198static int setDecompDefaults(struct jpeg_decompress_struct *dinfo, 199 int pixelFormat) 200{ 201 int retval=0; 202 203 switch(pixelFormat) 204 { 205 case TJPF_GRAY: 206 dinfo->out_color_space=JCS_GRAYSCALE; break; 207 #if JCS_EXTENSIONS==1 208 case TJPF_RGB: 209 dinfo->out_color_space=JCS_EXT_RGB; break; 210 case TJPF_BGR: 211 dinfo->out_color_space=JCS_EXT_BGR; break; 212 case TJPF_RGBX: 213 dinfo->out_color_space=JCS_EXT_RGBX; break; 214 case TJPF_BGRX: 215 dinfo->out_color_space=JCS_EXT_BGRX; break; 216 case TJPF_XRGB: 217 dinfo->out_color_space=JCS_EXT_XRGB; break; 218 case TJPF_XBGR: 219 dinfo->out_color_space=JCS_EXT_XBGR; break; 220 #if JCS_ALPHA_EXTENSIONS==1 221 case TJPF_RGBA: 222 dinfo->out_color_space=JCS_EXT_RGBA; break; 223 case TJPF_BGRA: 224 dinfo->out_color_space=JCS_EXT_BGRA; break; 225 case TJPF_ARGB: 226 dinfo->out_color_space=JCS_EXT_ARGB; break; 227 case TJPF_ABGR: 228 dinfo->out_color_space=JCS_EXT_ABGR; break; 229 #endif 230 #else 231 case TJPF_RGB: 232 if(RGB_RED==0 && RGB_GREEN==1 && RGB_BLUE==2 && RGB_PIXELSIZE==3) 233 { 234 dinfo->out_color_space=JCS_RGB; break; 235 } 236 #endif 237 default: 238 _throw("Unsupported pixel format"); 239 } 240 241 bailout: 242 return retval; 243} 244 245 246static int getSubsamp(j_decompress_ptr dinfo) 247{ 248 int retval=-1, i, k; 249 for(i=0; i<NUMSUBOPT; i++) 250 { 251 if(dinfo->num_components==pixelsize[i]) 252 { 253 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8 254 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8) 255 { 256 int match=0; 257 for(k=1; k<dinfo->num_components; k++) 258 { 259 if(dinfo->comp_info[k].h_samp_factor==1 260 && dinfo->comp_info[k].v_samp_factor==1) 261 match++; 262 } 263 if(match==dinfo->num_components-1) 264 { 265 retval=i; break; 266 } 267 } 268 } 269 } 270 return retval; 271} 272 273 274/* General API functions */ 275 276DLLEXPORT char* DLLCALL tjGetErrorStr(void) 277{ 278 return errStr; 279} 280 281 282DLLEXPORT int DLLCALL tjDestroy(tjhandle handle) 283{ 284 getinstance(handle); 285 if(setjmp(this->jerr.setjmp_buffer)) return -1; 286 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo); 287 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo); 288 free(this); 289 return 0; 290} 291 292 293/* These are exposed mainly because Windows can't malloc() and free() across 294 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL 295 with turbojpeg.dll for compatibility reasons. However, these functions 296 can potentially be used for other purposes by different implementations. */ 297 298DLLEXPORT void DLLCALL tjFree(unsigned char *buf) 299{ 300 if(buf) free(buf); 301} 302 303 304DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes) 305{ 306 return (unsigned char *)malloc(bytes); 307} 308 309 310/* Compressor */ 311 312static tjhandle _tjInitCompress(tjinstance *this) 313{ 314 unsigned char buffer[1], *buf=buffer; unsigned long size=1; 315 316 /* This is also straight out of example.c */ 317 this->cinfo.err=jpeg_std_error(&this->jerr.pub); 318 this->jerr.pub.error_exit=my_error_exit; 319 this->jerr.pub.output_message=my_output_message; 320 321 if(setjmp(this->jerr.setjmp_buffer)) 322 { 323 /* If we get here, the JPEG code has signaled an error. */ 324 if(this) free(this); return NULL; 325 } 326 327 jpeg_create_compress(&this->cinfo); 328 /* Make an initial call so it will create the destination manager */ 329 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0); 330 331 this->init|=COMPRESS; 332 return (tjhandle)this; 333} 334 335DLLEXPORT tjhandle DLLCALL tjInitCompress(void) 336{ 337 tjinstance *this=NULL; 338 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL) 339 { 340 snprintf(errStr, JMSG_LENGTH_MAX, 341 "tjInitCompress(): Memory allocation failure"); 342 return NULL; 343 } 344 MEMZERO(this, sizeof(tjinstance)); 345 return _tjInitCompress(this); 346} 347 348 349DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height, 350 int jpegSubsamp) 351{ 352 unsigned long retval=0; int mcuw, mcuh, chromasf; 353 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT) 354 _throw("tjBufSize(): Invalid argument"); 355 356 // This allows for rare corner cases in which a JPEG image can actually be 357 // larger than the uncompressed input (we wouldn't mention it if it hadn't 358 // happened before.) 359 mcuw=tjMCUWidth[jpegSubsamp]; 360 mcuh=tjMCUHeight[jpegSubsamp]; 361 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh); 362 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048; 363 364 bailout: 365 return retval; 366} 367 368 369DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height) 370{ 371 unsigned long retval=0; 372 if(width<1 || height<1) 373 _throw("TJBUFSIZE(): Invalid argument"); 374 375 // This allows for rare corner cases in which a JPEG image can actually be 376 // larger than the uncompressed input (we wouldn't mention it if it hadn't 377 // happened before.) 378 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048; 379 380 bailout: 381 return retval; 382} 383 384 385DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height, 386 int subsamp) 387{ 388 unsigned long retval=0; 389 int pw, ph, cw, ch; 390 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT) 391 _throw("tjBufSizeYUV(): Invalid argument"); 392 pw=PAD(width, tjMCUWidth[subsamp]/8); 393 ph=PAD(height, tjMCUHeight[subsamp]/8); 394 cw=pw*8/tjMCUWidth[subsamp]; ch=ph*8/tjMCUHeight[subsamp]; 395 retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2); 396 397 bailout: 398 return retval; 399} 400 401 402DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height, 403 int subsamp) 404{ 405 return tjBufSizeYUV(width, height, subsamp); 406} 407 408 409DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, 410 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, 411 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags) 412{ 413 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL; 414 415 getinstance(handle) 416 if((this->init&COMPRESS)==0) 417 _throw("tjCompress2(): Instance has not been initialized for compression"); 418 419 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0 420 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL 421 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100) 422 _throw("tjCompress2(): Invalid argument"); 423 424 if(setjmp(this->jerr.setjmp_buffer)) 425 { 426 /* If we get here, the JPEG code has signaled an error. */ 427 retval=-1; 428 goto bailout; 429 } 430 431 if(pitch==0) pitch=width*tjPixelSize[pixelFormat]; 432 433 cinfo->image_width=width; 434 cinfo->image_height=height; 435 436 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 437 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 438 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 439 440 if(flags&TJFLAG_NOREALLOC) 441 { 442 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp); 443 } 444 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc); 445 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1) 446 return -1; 447 448 jpeg_start_compress(cinfo, TRUE); 449 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL) 450 _throw("tjCompress2(): Memory allocation failure"); 451 for(i=0; i<height; i++) 452 { 453 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch]; 454 else row_pointer[i]=&srcBuf[i*pitch]; 455 } 456 while(cinfo->next_scanline<cinfo->image_height) 457 { 458 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline], 459 cinfo->image_height-cinfo->next_scanline); 460 } 461 jpeg_finish_compress(cinfo); 462 463 bailout: 464 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo); 465 if(row_pointer) free(row_pointer); 466 return retval; 467} 468 469DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf, 470 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf, 471 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags) 472{ 473 int retval=0; unsigned long size; 474 if(flags&TJ_YUV) 475 { 476 size=tjBufSizeYUV(width, height, jpegSubsamp); 477 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height, 478 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags); 479 } 480 else 481 { 482 retval=tjCompress2(handle, srcBuf, width, pitch, height, 483 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual, 484 flags|TJFLAG_NOREALLOC); 485 } 486 *jpegSize=size; 487 return retval; 488} 489 490 491DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, 492 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf, 493 int subsamp, int flags) 494{ 495 int i, retval=0; JSAMPROW *row_pointer=NULL; 496 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS]; 497 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS]; 498 JSAMPROW *outbuf[MAX_COMPONENTS]; 499 int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS]; 500 JSAMPLE *ptr=dstBuf; 501 unsigned long yuvsize=0; 502 jpeg_component_info *compptr; 503 504 getinstance(handle); 505 if((this->init&COMPRESS)==0) 506 _throw("tjEncodeYUV2(): Instance has not been initialized for compression"); 507 508 for(i=0; i<MAX_COMPONENTS; i++) 509 { 510 tmpbuf[i]=NULL; _tmpbuf[i]=NULL; 511 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL; 512 } 513 514 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0 515 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0 516 || subsamp>=NUMSUBOPT) 517 _throw("tjEncodeYUV2(): Invalid argument"); 518 519 if(setjmp(this->jerr.setjmp_buffer)) 520 { 521 /* If we get here, the JPEG code has signaled an error. */ 522 retval=-1; 523 goto bailout; 524 } 525 526 if(pitch==0) pitch=width*tjPixelSize[pixelFormat]; 527 528 cinfo->image_width=width; 529 cinfo->image_height=height; 530 531 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 532 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 533 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 534 535 yuvsize=tjBufSizeYUV(width, height, subsamp); 536 jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0); 537 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1)==-1) return -1; 538 539 jpeg_start_compress(cinfo, TRUE); 540 pw=PAD(width, cinfo->max_h_samp_factor); 541 ph=PAD(height, cinfo->max_v_samp_factor); 542 543 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL) 544 _throw("tjEncodeYUV2(): Memory allocation failure"); 545 for(i=0; i<height; i++) 546 { 547 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch]; 548 else row_pointer[i]=&srcBuf[i*pitch]; 549 } 550 if(height<ph) 551 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1]; 552 553 for(i=0; i<cinfo->num_components; i++) 554 { 555 compptr=&cinfo->comp_info[i]; 556 _tmpbuf[i]=(JSAMPLE *)malloc( 557 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE) 558 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16); 559 if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure"); 560 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor); 561 if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure"); 562 for(row=0; row<cinfo->max_v_samp_factor; row++) 563 { 564 unsigned char *_tmpbuf_aligned= 565 (unsigned char *)PAD((size_t)_tmpbuf[i], 16); 566 tmpbuf[i][row]=&_tmpbuf_aligned[ 567 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE) 568 /compptr->h_samp_factor, 16) * row]; 569 } 570 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16) 571 * compptr->v_samp_factor + 16); 572 if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure"); 573 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor); 574 if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure"); 575 for(row=0; row<compptr->v_samp_factor; row++) 576 { 577 unsigned char *_tmpbuf2_aligned= 578 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16); 579 tmpbuf2[i][row]=&_tmpbuf2_aligned[ 580 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row]; 581 } 582 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor; 583 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor; 584 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]); 585 if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure"); 586 for(row=0; row<ch[i]; row++) 587 { 588 outbuf[i][row]=ptr; 589 ptr+=PAD(cw[i], 4); 590 } 591 } 592 if(yuvsize!=(unsigned long)(ptr-dstBuf)) 593 _throw("tjEncodeYUV2(): Generated image is not the correct size"); 594 595 for(row=0; row<ph; row+=cinfo->max_v_samp_factor) 596 { 597 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0, 598 cinfo->max_v_samp_factor); 599 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0); 600 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++) 601 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i], 602 row*compptr->v_samp_factor/cinfo->max_v_samp_factor, 603 compptr->v_samp_factor, cw[i]); 604 } 605 cinfo->next_scanline+=height; 606 jpeg_abort_compress(cinfo); 607 608 bailout: 609 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo); 610 if(row_pointer) free(row_pointer); 611 for(i=0; i<MAX_COMPONENTS; i++) 612 { 613 if(tmpbuf[i]!=NULL) free(tmpbuf[i]); 614 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]); 615 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]); 616 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]); 617 if(outbuf[i]!=NULL) free(outbuf[i]); 618 } 619 return retval; 620} 621 622DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, 623 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf, 624 int subsamp, int flags) 625{ 626 return tjEncodeYUV2(handle, srcBuf, width, pitch, height, 627 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags); 628} 629 630 631/* Decompressor */ 632 633static tjhandle _tjInitDecompress(tjinstance *this) 634{ 635 unsigned char buffer[1]; 636 637 /* This is also straight out of example.c */ 638 this->dinfo.err=jpeg_std_error(&this->jerr.pub); 639 this->jerr.pub.error_exit=my_error_exit; 640 this->jerr.pub.output_message=my_output_message; 641 642 if(setjmp(this->jerr.setjmp_buffer)) 643 { 644 /* If we get here, the JPEG code has signaled an error. */ 645 if(this) free(this); return NULL; 646 } 647 648 jpeg_create_decompress(&this->dinfo); 649 /* Make an initial call so it will create the source manager */ 650 jpeg_mem_src_tj(&this->dinfo, buffer, 1); 651 652 this->init|=DECOMPRESS; 653 return (tjhandle)this; 654} 655 656DLLEXPORT tjhandle DLLCALL tjInitDecompress(void) 657{ 658 tjinstance *this; 659 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL) 660 { 661 snprintf(errStr, JMSG_LENGTH_MAX, 662 "tjInitDecompress(): Memory allocation failure"); 663 return NULL; 664 } 665 MEMZERO(this, sizeof(tjinstance)); 666 return _tjInitDecompress(this); 667} 668 669 670DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle, 671 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, 672 int *jpegSubsamp) 673{ 674 int retval=0; 675 676 getinstance(handle); 677 if((this->init&DECOMPRESS)==0) 678 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression"); 679 680 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL 681 || jpegSubsamp==NULL) 682 _throw("tjDecompressHeader2(): Invalid argument"); 683 684 if(setjmp(this->jerr.setjmp_buffer)) 685 { 686 /* If we get here, the JPEG code has signaled an error. */ 687 return -1; 688 } 689 690 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); 691 jpeg_read_header(dinfo, TRUE); 692 693 *width=dinfo->image_width; 694 *height=dinfo->image_height; 695 *jpegSubsamp=getSubsamp(dinfo); 696 697 jpeg_abort_decompress(dinfo); 698 699 if(*jpegSubsamp<0) 700 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image"); 701 if(*width<1 || *height<1) 702 _throw("tjDecompressHeader2(): Invalid data returned in header"); 703 704 bailout: 705 return retval; 706} 707 708DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle, 709 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height) 710{ 711 int jpegSubsamp; 712 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height, 713 &jpegSubsamp); 714} 715 716 717DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors) 718{ 719 if(numscalingfactors==NULL) 720 { 721 snprintf(errStr, JMSG_LENGTH_MAX, 722 "tjGetScalingFactors(): Invalid argument"); 723 return NULL; 724 } 725 726 *numscalingfactors=NUMSF; 727 return (tjscalingfactor *)sf; 728} 729 730 731DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf, 732 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, 733 int height, int pixelFormat, int flags) 734{ 735 int i, retval=0; JSAMPROW *row_pointer=NULL; 736 int jpegwidth, jpegheight, scaledw, scaledh; 737 738 getinstance(handle); 739 if((this->init&DECOMPRESS)==0) 740 _throw("tjDecompress2(): Instance has not been initialized for decompression"); 741 742 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0 743 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF) 744 _throw("tjDecompress2(): Invalid argument"); 745 746 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 747 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 748 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 749 750 if(setjmp(this->jerr.setjmp_buffer)) 751 { 752 /* If we get here, the JPEG code has signaled an error. */ 753 retval=-1; 754 goto bailout; 755 } 756 757 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); 758 jpeg_read_header(dinfo, TRUE); 759 if(setDecompDefaults(dinfo, pixelFormat)==-1) return -1; 760 761 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE; 762 763 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height; 764 if(width==0) width=jpegwidth; 765 if(height==0) height=jpegheight; 766 for(i=0; i<NUMSF; i++) 767 { 768 scaledw=TJSCALED(jpegwidth, sf[i]); 769 scaledh=TJSCALED(jpegheight, sf[i]); 770 if(scaledw<=width && scaledh<=height) 771 break; 772 } 773 if(scaledw>width || scaledh>height) 774 _throw("tjDecompress2(): Could not scale down to desired image dimensions"); 775 width=scaledw; height=scaledh; 776 dinfo->scale_num=sf[i].num; 777 dinfo->scale_denom=sf[i].denom; 778 779 jpeg_start_decompress(dinfo); 780 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat]; 781 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW) 782 *dinfo->output_height))==NULL) 783 _throw("tjDecompress2(): Memory allocation failure"); 784 for(i=0; i<(int)dinfo->output_height; i++) 785 { 786 if(flags&TJFLAG_BOTTOMUP) 787 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch]; 788 else row_pointer[i]=&dstBuf[i*pitch]; 789 } 790 while(dinfo->output_scanline<dinfo->output_height) 791 { 792 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline], 793 dinfo->output_height-dinfo->output_scanline); 794 } 795 jpeg_finish_decompress(dinfo); 796 797 bailout: 798 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo); 799 if(row_pointer) free(row_pointer); 800 return retval; 801} 802 803DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf, 804 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, 805 int height, int pixelSize, int flags) 806{ 807 if(flags&TJ_YUV) 808 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags); 809 else 810 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch, 811 height, getPixelFormat(pixelSize, flags), flags); 812} 813 814 815DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle, 816 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, 817 int flags) 818{ 819 int i, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS]; 820 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS], 821 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS]; 822 JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS]; 823 824 getinstance(handle); 825 if((this->init&DECOMPRESS)==0) 826 _throw("tjDecompressToYUV(): Instance has not been initialized for decompression"); 827 828 for(i=0; i<MAX_COMPONENTS; i++) 829 { 830 tmpbuf[i]=NULL; outbuf[i]=NULL; 831 } 832 833 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL) 834 _throw("tjDecompressToYUV(): Invalid argument"); 835 836 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 837 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 838 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 839 840 if(setjmp(this->jerr.setjmp_buffer)) 841 { 842 /* If we get here, the JPEG code has signaled an error. */ 843 retval=-1; 844 goto bailout; 845 } 846 847 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); 848 jpeg_read_header(dinfo, TRUE); 849 850 for(i=0; i<dinfo->num_components; i++) 851 { 852 jpeg_component_info *compptr=&dinfo->comp_info[i]; 853 int ih; 854 iw[i]=compptr->width_in_blocks*DCTSIZE; 855 ih=compptr->height_in_blocks*DCTSIZE; 856 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor) 857 *compptr->h_samp_factor/dinfo->max_h_samp_factor; 858 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor) 859 *compptr->v_samp_factor/dinfo->max_v_samp_factor; 860 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1; 861 th[i]=compptr->v_samp_factor*DCTSIZE; 862 tmpbufsize+=iw[i]*th[i]; 863 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL) 864 _throw("tjDecompressToYUV(): Memory allocation failure"); 865 for(row=0; row<ch[i]; row++) 866 { 867 outbuf[i][row]=ptr; 868 ptr+=PAD(cw[i], 4); 869 } 870 } 871 if(usetmpbuf) 872 { 873 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL) 874 _throw("tjDecompressToYUV(): Memory allocation failure"); 875 ptr=_tmpbuf; 876 for(i=0; i<dinfo->num_components; i++) 877 { 878 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL) 879 _throw("tjDecompressToYUV(): Memory allocation failure"); 880 for(row=0; row<th[i]; row++) 881 { 882 tmpbuf[i][row]=ptr; 883 ptr+=iw[i]; 884 } 885 } 886 } 887 888 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE; 889 dinfo->raw_data_out=TRUE; 890 891 jpeg_start_decompress(dinfo); 892 for(row=0; row<(int)dinfo->output_height; 893 row+=dinfo->max_v_samp_factor*DCTSIZE) 894 { 895 JSAMPARRAY yuvptr[MAX_COMPONENTS]; 896 int crow[MAX_COMPONENTS]; 897 for(i=0; i<dinfo->num_components; i++) 898 { 899 jpeg_component_info *compptr=&dinfo->comp_info[i]; 900 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor; 901 if(usetmpbuf) yuvptr[i]=tmpbuf[i]; 902 else yuvptr[i]=&outbuf[i][crow[i]]; 903 } 904 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE); 905 if(usetmpbuf) 906 { 907 int j; 908 for(i=0; i<dinfo->num_components; i++) 909 { 910 for(j=0; j<min(th[i], ch[i]-crow[i]); j++) 911 { 912 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]); 913 } 914 } 915 } 916 } 917 jpeg_finish_decompress(dinfo); 918 919 bailout: 920 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo); 921 for(i=0; i<MAX_COMPONENTS; i++) 922 { 923 if(tmpbuf[i]) free(tmpbuf[i]); 924 if(outbuf[i]) free(outbuf[i]); 925 } 926 if(_tmpbuf) free(_tmpbuf); 927 return retval; 928} 929 930 931/* Transformer */ 932 933DLLEXPORT tjhandle DLLCALL tjInitTransform(void) 934{ 935 tjinstance *this=NULL; tjhandle handle=NULL; 936 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL) 937 { 938 snprintf(errStr, JMSG_LENGTH_MAX, 939 "tjInitTransform(): Memory allocation failure"); 940 return NULL; 941 } 942 MEMZERO(this, sizeof(tjinstance)); 943 handle=_tjInitCompress(this); 944 if(!handle) return NULL; 945 handle=_tjInitDecompress(this); 946 return handle; 947} 948 949 950DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf, 951 unsigned long jpegSize, int n, unsigned char **dstBufs, 952 unsigned long *dstSizes, tjtransform *t, int flags) 953{ 954 jpeg_transform_info *xinfo=NULL; 955 jvirt_barray_ptr *srccoefs, *dstcoefs; 956 int retval=0, i, jpegSubsamp; 957 958 getinstance(handle); 959 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0) 960 _throw("tjTransform(): Instance has not been initialized for transformation"); 961 962 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL 963 || t==NULL || flags<0) 964 _throw("tjTransform(): Invalid argument"); 965 966 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 967 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 968 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 969 970 if(setjmp(this->jerr.setjmp_buffer)) 971 { 972 /* If we get here, the JPEG code has signaled an error. */ 973 retval=-1; 974 goto bailout; 975 } 976 977 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); 978 979 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n)) 980 ==NULL) 981 _throw("tjTransform(): Memory allocation failure"); 982 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n); 983 984 for(i=0; i<n; i++) 985 { 986 xinfo[i].transform=xformtypes[t[i].op]; 987 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0; 988 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0; 989 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0; 990 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0; 991 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1; 992 else xinfo[i].slow_hflip=0; 993 994 if(xinfo[i].crop) 995 { 996 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS; 997 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS; 998 if(t[i].r.w!=0) 999 { 1000 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS; 1001 } 1002 else xinfo[i].crop_width=JCROP_UNSET; 1003 if(t[i].r.h!=0) 1004 { 1005 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS; 1006 } 1007 else xinfo[i].crop_height=JCROP_UNSET; 1008 } 1009 } 1010 1011 jcopy_markers_setup(dinfo, JCOPYOPT_ALL); 1012 jpeg_read_header(dinfo, TRUE); 1013 jpegSubsamp=getSubsamp(dinfo); 1014 if(jpegSubsamp<0) 1015 _throw("tjTransform(): Could not determine subsampling type for JPEG image"); 1016 1017 for(i=0; i<n; i++) 1018 { 1019 if(!jtransform_request_workspace(dinfo, &xinfo[i])) 1020 _throw("tjTransform(): Transform is not perfect"); 1021 1022 if(xinfo[i].crop) 1023 { 1024 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0 1025 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0) 1026 { 1027 snprintf(errStr, JMSG_LENGTH_MAX, 1028 "To crop this JPEG image, x must be a multiple of %d\n" 1029 "and y must be a multiple of %d.\n", 1030 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height); 1031 retval=-1; goto bailout; 1032 } 1033 } 1034 } 1035 1036 srccoefs=jpeg_read_coefficients(dinfo); 1037 1038 for(i=0; i<n; i++) 1039 { 1040 int w, h, alloc=1; 1041 if(!xinfo[i].crop) 1042 { 1043 w=dinfo->image_width; h=dinfo->image_height; 1044 } 1045 else 1046 { 1047 w=xinfo[i].crop_width; h=xinfo[i].crop_height; 1048 } 1049 if(flags&TJFLAG_NOREALLOC) 1050 { 1051 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp); 1052 } 1053 if(!(t[i].options&TJXOPT_NOOUTPUT)) 1054 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc); 1055 jpeg_copy_critical_parameters(dinfo, cinfo); 1056 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs, 1057 &xinfo[i]); 1058 if(!(t[i].options&TJXOPT_NOOUTPUT)) 1059 { 1060 jpeg_write_coefficients(cinfo, dstcoefs); 1061 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL); 1062 } 1063 else jinit_c_master_control(cinfo, TRUE); 1064 jtransform_execute_transformation(dinfo, cinfo, srccoefs, 1065 &xinfo[i]); 1066 if(t[i].customFilter) 1067 { 1068 int ci, by, y; 1069 for(ci=0; ci<cinfo->num_components; ci++) 1070 { 1071 jpeg_component_info *compptr=&cinfo->comp_info[ci]; 1072 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE, 1073 DCTSIZE}; 1074 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE, 1075 compptr->height_in_blocks*DCTSIZE}; 1076 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor) 1077 { 1078 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray) 1079 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor, 1080 TRUE); 1081 for(y=0; y<compptr->v_samp_factor; y++) 1082 { 1083 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion, 1084 ci, i, &t[i])==-1) 1085 _throw("tjTransform(): Error in custom filter"); 1086 arrayRegion.y+=DCTSIZE; 1087 } 1088 } 1089 } 1090 } 1091 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo); 1092 } 1093 1094 jpeg_finish_decompress(dinfo); 1095 1096 bailout: 1097 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo); 1098 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo); 1099 if(xinfo) free(xinfo); 1100 return retval; 1101} 1102