1 /* 2 * Copyright (C)2009-2019 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/LJT: this implements the TurboJPEG API using libjpeg or 30 libjpeg-turbo */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <ctype.h> 35 #include <jinclude.h> 36 #define JPEG_INTERNALS 37 #include <jpeglib.h> 38 #include <jerror.h> 39 #include <setjmp.h> 40 #include <errno.h> 41 #include "./turbojpeg.h" 42 #include "./tjutil.h" 43 #include "transupp.h" 44 #include "./jpegcomp.h" 45 #include "./cdjpeg.h" 46 47 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, unsigned long *, 48 boolean); 49 extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *, 50 unsigned long); 51 52 #define PAD(v, p) ((v + (p) - 1) & (~((p) - 1))) 53 #define isPow2(x) (((x) & (x - 1)) == 0) 54 55 56 /* Error handling (based on example in example.txt) */ 57 58 static char errStr[JMSG_LENGTH_MAX] = "No error"; 59 60 struct my_error_mgr { 61 struct jpeg_error_mgr pub; 62 jmp_buf setjmp_buffer; 63 void (*emit_message) (j_common_ptr, int); 64 boolean warning, stopOnWarning; 65 }; 66 typedef struct my_error_mgr *my_error_ptr; 67 68 #define JMESSAGE(code, string) string, 69 static const char *turbojpeg_message_table[] = { 70 #include "cderror.h" 71 NULL 72 }; 73 74 static void my_error_exit(j_common_ptr cinfo) 75 { 76 my_error_ptr myerr = (my_error_ptr)cinfo->err; 77 78 (*cinfo->err->output_message) (cinfo); 79 longjmp(myerr->setjmp_buffer, 1); 80 } 81 82 /* Based on output_message() in jerror.c */ 83 84 static void my_output_message(j_common_ptr cinfo) 85 { 86 (*cinfo->err->format_message) (cinfo, errStr); 87 } 88 89 static void my_emit_message(j_common_ptr cinfo, int msg_level) 90 { 91 my_error_ptr myerr = (my_error_ptr)cinfo->err; 92 93 myerr->emit_message(cinfo, msg_level); 94 if (msg_level < 0) { 95 myerr->warning = TRUE; 96 if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1); 97 } 98 } 99 100 101 /* Global structures, macros, etc. */ 102 103 enum { COMPRESS = 1, DECOMPRESS = 2 }; 104 105 typedef struct _tjinstance { 106 struct jpeg_compress_struct cinfo; 107 struct jpeg_decompress_struct dinfo; 108 struct my_error_mgr jerr; 109 int init, headerRead; 110 char errStr[JMSG_LENGTH_MAX]; 111 boolean isInstanceError; 112 } tjinstance; 113 114 static const int pixelsize[TJ_NUMSAMP] = { 3, 3, 3, 1, 3, 3 }; 115 116 static const JXFORM_CODE xformtypes[TJ_NUMXOP] = { 117 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE, 118 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270 119 }; 120 121 #define NUMSF 16 122 static const tjscalingfactor sf[NUMSF] = { 123 { 2, 1 }, 124 { 15, 8 }, 125 { 7, 4 }, 126 { 13, 8 }, 127 { 3, 2 }, 128 { 11, 8 }, 129 { 5, 4 }, 130 { 9, 8 }, 131 { 1, 1 }, 132 { 7, 8 }, 133 { 3, 4 }, 134 { 5, 8 }, 135 { 1, 2 }, 136 { 3, 8 }, 137 { 1, 4 }, 138 { 1, 8 } 139 }; 140 141 static J_COLOR_SPACE pf2cs[TJ_NUMPF] = { 142 JCS_EXT_RGB, JCS_EXT_BGR, JCS_EXT_RGBX, JCS_EXT_BGRX, JCS_EXT_XBGR, 143 JCS_EXT_XRGB, JCS_GRAYSCALE, JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ABGR, 144 JCS_EXT_ARGB, JCS_CMYK 145 }; 146 147 static int cs2pf[JPEG_NUMCS] = { 148 TJPF_UNKNOWN, TJPF_GRAY, 149 #if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3 150 TJPF_RGB, 151 #elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 3 152 TJPF_BGR, 153 #elif RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 4 154 TJPF_RGBX, 155 #elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 4 156 TJPF_BGRX, 157 #elif RGB_RED == 3 && RGB_GREEN == 2 && RGB_BLUE == 1 && RGB_PIXELSIZE == 4 158 TJPF_XBGR, 159 #elif RGB_RED == 1 && RGB_GREEN == 2 && RGB_BLUE == 3 && RGB_PIXELSIZE == 4 160 TJPF_XRGB, 161 #endif 162 TJPF_UNKNOWN, TJPF_CMYK, TJPF_UNKNOWN, TJPF_RGB, TJPF_RGBX, TJPF_BGR, 163 TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_RGBA, TJPF_BGRA, TJPF_ABGR, TJPF_ARGB, 164 TJPF_UNKNOWN 165 }; 166 167 #define _throwg(m) { \ 168 snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \ 169 retval = -1; goto bailout; \ 170 } 171 #define _throwunix(m) { \ 172 snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerror(errno)); \ 173 retval = -1; goto bailout; \ 174 } 175 #define _throw(m) { \ 176 snprintf(this->errStr, JMSG_LENGTH_MAX, "%s", m); \ 177 this->isInstanceError = TRUE; _throwg(m) \ 178 } 179 180 #define getinstance(handle) \ 181 tjinstance *this = (tjinstance *)handle; \ 182 j_compress_ptr cinfo = NULL; \ 183 j_decompress_ptr dinfo = NULL; \ 184 \ 185 if (!this) { \ 186 snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \ 187 return -1; \ 188 } \ 189 cinfo = &this->cinfo; dinfo = &this->dinfo; \ 190 this->jerr.warning = FALSE; \ 191 this->isInstanceError = FALSE; 192 193 #define getcinstance(handle) \ 194 tjinstance *this = (tjinstance *)handle; \ 195 j_compress_ptr cinfo = NULL; \ 196 \ 197 if (!this) { \ 198 snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \ 199 return -1; \ 200 } \ 201 cinfo = &this->cinfo; \ 202 this->jerr.warning = FALSE; \ 203 this->isInstanceError = FALSE; 204 205 #define getdinstance(handle) \ 206 tjinstance *this = (tjinstance *)handle; \ 207 j_decompress_ptr dinfo = NULL; \ 208 \ 209 if (!this) { \ 210 snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \ 211 return -1; \ 212 } \ 213 dinfo = &this->dinfo; \ 214 this->jerr.warning = FALSE; \ 215 this->isInstanceError = FALSE; 216 217 static int getPixelFormat(int pixelSize, int flags) 218 { 219 if (pixelSize == 1) return TJPF_GRAY; 220 if (pixelSize == 3) { 221 if (flags & TJ_BGR) return TJPF_BGR; 222 else return TJPF_RGB; 223 } 224 if (pixelSize == 4) { 225 if (flags & TJ_ALPHAFIRST) { 226 if (flags & TJ_BGR) return TJPF_XBGR; 227 else return TJPF_XRGB; 228 } else { 229 if (flags & TJ_BGR) return TJPF_BGRX; 230 else return TJPF_RGBX; 231 } 232 } 233 return -1; 234 } 235 236 static int setCompDefaults(struct jpeg_compress_struct *cinfo, int pixelFormat, 237 int subsamp, int jpegQual, int flags) 238 { 239 int retval = 0; 240 char *env = NULL; 241 242 cinfo->in_color_space = pf2cs[pixelFormat]; 243 cinfo->input_components = tjPixelSize[pixelFormat]; 244 jpeg_set_defaults(cinfo); 245 246 #ifndef NO_GETENV 247 if ((env = getenv("TJ_OPTIMIZE")) != NULL && strlen(env) > 0 && 248 !strcmp(env, "1")) 249 cinfo->optimize_coding = TRUE; 250 if ((env = getenv("TJ_ARITHMETIC")) != NULL && strlen(env) > 0 && 251 !strcmp(env, "1")) 252 cinfo->arith_code = TRUE; 253 if ((env = getenv("TJ_RESTART")) != NULL && strlen(env) > 0) { 254 int temp = -1; 255 char tempc = 0; 256 257 if (sscanf(env, "%d%c", &temp, &tempc) >= 1 && temp >= 0 && 258 temp <= 65535) { 259 if (toupper(tempc) == 'B') { 260 cinfo->restart_interval = temp; 261 cinfo->restart_in_rows = 0; 262 } else 263 cinfo->restart_in_rows = temp; 264 } 265 } 266 #endif 267 268 if (jpegQual >= 0) { 269 jpeg_set_quality(cinfo, jpegQual, TRUE); 270 if (jpegQual >= 96 || flags & TJFLAG_ACCURATEDCT) 271 cinfo->dct_method = JDCT_ISLOW; 272 else 273 cinfo->dct_method = JDCT_FASTEST; 274 } 275 if (subsamp == TJSAMP_GRAY) 276 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); 277 else if (pixelFormat == TJPF_CMYK) 278 jpeg_set_colorspace(cinfo, JCS_YCCK); 279 else 280 jpeg_set_colorspace(cinfo, JCS_YCbCr); 281 282 if (flags & TJFLAG_PROGRESSIVE) 283 jpeg_simple_progression(cinfo); 284 #ifndef NO_GETENV 285 else if ((env = getenv("TJ_PROGRESSIVE")) != NULL && strlen(env) > 0 && 286 !strcmp(env, "1")) 287 jpeg_simple_progression(cinfo); 288 #endif 289 290 cinfo->comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8; 291 cinfo->comp_info[1].h_samp_factor = 1; 292 cinfo->comp_info[2].h_samp_factor = 1; 293 if (cinfo->num_components > 3) 294 cinfo->comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8; 295 cinfo->comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8; 296 cinfo->comp_info[1].v_samp_factor = 1; 297 cinfo->comp_info[2].v_samp_factor = 1; 298 if (cinfo->num_components > 3) 299 cinfo->comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8; 300 301 return retval; 302 } 303 304 305 static int getSubsamp(j_decompress_ptr dinfo) 306 { 307 int retval = -1, i, k; 308 309 /* The sampling factors actually have no meaning with grayscale JPEG files, 310 and in fact it's possible to generate grayscale JPEGs with sampling 311 factors > 1 (even though those sampling factors are ignored by the 312 decompressor.) Thus, we need to treat grayscale as a special case. */ 313 if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE) 314 return TJSAMP_GRAY; 315 316 for (i = 0; i < NUMSUBOPT; i++) { 317 if (dinfo->num_components == pixelsize[i] || 318 ((dinfo->jpeg_color_space == JCS_YCCK || 319 dinfo->jpeg_color_space == JCS_CMYK) && 320 pixelsize[i] == 3 && dinfo->num_components == 4)) { 321 if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 && 322 dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) { 323 int match = 0; 324 325 for (k = 1; k < dinfo->num_components; k++) { 326 int href = 1, vref = 1; 327 328 if ((dinfo->jpeg_color_space == JCS_YCCK || 329 dinfo->jpeg_color_space == JCS_CMYK) && k == 3) { 330 href = tjMCUWidth[i] / 8; vref = tjMCUHeight[i] / 8; 331 } 332 if (dinfo->comp_info[k].h_samp_factor == href && 333 dinfo->comp_info[k].v_samp_factor == vref) 334 match++; 335 } 336 if (match == dinfo->num_components - 1) { 337 retval = i; break; 338 } 339 } 340 /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified 341 in non-standard ways. */ 342 if (dinfo->comp_info[0].h_samp_factor == 2 && 343 dinfo->comp_info[0].v_samp_factor == 2 && 344 (i == TJSAMP_422 || i == TJSAMP_440)) { 345 int match = 0; 346 347 for (k = 1; k < dinfo->num_components; k++) { 348 int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8; 349 350 if ((dinfo->jpeg_color_space == JCS_YCCK || 351 dinfo->jpeg_color_space == JCS_CMYK) && k == 3) { 352 href = vref = 2; 353 } 354 if (dinfo->comp_info[k].h_samp_factor == href && 355 dinfo->comp_info[k].v_samp_factor == vref) 356 match++; 357 } 358 if (match == dinfo->num_components - 1) { 359 retval = i; break; 360 } 361 } 362 /* Handle 4:4:4 images whose sampling factors are specified in 363 non-standard ways. */ 364 if (dinfo->comp_info[0].h_samp_factor * 365 dinfo->comp_info[0].v_samp_factor <= 366 D_MAX_BLOCKS_IN_MCU / pixelsize[i] && i == TJSAMP_444) { 367 int match = 0; 368 for (k = 1; k < dinfo->num_components; k++) { 369 if (dinfo->comp_info[i].h_samp_factor == 370 dinfo->comp_info[0].h_samp_factor && 371 dinfo->comp_info[i].v_samp_factor == 372 dinfo->comp_info[0].v_samp_factor) 373 match++; 374 if (match == dinfo->num_components - 1) { 375 retval = i; break; 376 } 377 } 378 } 379 } 380 } 381 return retval; 382 } 383 384 385 /* General API functions */ 386 387 DLLEXPORT char *tjGetErrorStr2(tjhandle handle) 388 { 389 tjinstance *this = (tjinstance *)handle; 390 391 if (this && this->isInstanceError) { 392 this->isInstanceError = FALSE; 393 return this->errStr; 394 } else 395 return errStr; 396 } 397 398 399 DLLEXPORT char *tjGetErrorStr(void) 400 { 401 return errStr; 402 } 403 404 405 DLLEXPORT int tjGetErrorCode(tjhandle handle) 406 { 407 tjinstance *this = (tjinstance *)handle; 408 409 if (this && this->jerr.warning) return TJERR_WARNING; 410 else return TJERR_FATAL; 411 } 412 413 414 DLLEXPORT int tjDestroy(tjhandle handle) 415 { 416 getinstance(handle); 417 418 if (setjmp(this->jerr.setjmp_buffer)) return -1; 419 if (this->init & COMPRESS) jpeg_destroy_compress(cinfo); 420 if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo); 421 free(this); 422 return 0; 423 } 424 425 426 /* These are exposed mainly because Windows can't malloc() and free() across 427 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL 428 with turbojpeg.dll for compatibility reasons. However, these functions 429 can potentially be used for other purposes by different implementations. */ 430 431 DLLEXPORT void tjFree(unsigned char *buf) 432 { 433 if (buf) free(buf); 434 } 435 436 437 DLLEXPORT unsigned char *tjAlloc(int bytes) 438 { 439 return (unsigned char *)malloc(bytes); 440 } 441 442 443 /* Compressor */ 444 445 static tjhandle _tjInitCompress(tjinstance *this) 446 { 447 static unsigned char buffer[1]; 448 unsigned char *buf = buffer; 449 unsigned long size = 1; 450 451 /* This is also straight out of example.txt */ 452 this->cinfo.err = jpeg_std_error(&this->jerr.pub); 453 this->jerr.pub.error_exit = my_error_exit; 454 this->jerr.pub.output_message = my_output_message; 455 this->jerr.emit_message = this->jerr.pub.emit_message; 456 this->jerr.pub.emit_message = my_emit_message; 457 this->jerr.pub.addon_message_table = turbojpeg_message_table; 458 this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE; 459 this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE; 460 461 if (setjmp(this->jerr.setjmp_buffer)) { 462 /* If we get here, the JPEG code has signaled an error. */ 463 if (this) free(this); 464 return NULL; 465 } 466 467 jpeg_create_compress(&this->cinfo); 468 /* Make an initial call so it will create the destination manager */ 469 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0); 470 471 this->init |= COMPRESS; 472 return (tjhandle)this; 473 } 474 475 DLLEXPORT tjhandle tjInitCompress(void) 476 { 477 tjinstance *this = NULL; 478 479 if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) { 480 snprintf(errStr, JMSG_LENGTH_MAX, 481 "tjInitCompress(): Memory allocation failure"); 482 return NULL; 483 } 484 MEMZERO(this, sizeof(tjinstance)); 485 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error"); 486 return _tjInitCompress(this); 487 } 488 489 490 DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp) 491 { 492 unsigned long retval = 0; 493 int mcuw, mcuh, chromasf; 494 495 if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT) 496 _throwg("tjBufSize(): Invalid argument"); 497 498 /* This allows for rare corner cases in which a JPEG image can actually be 499 larger than the uncompressed input (we wouldn't mention it if it hadn't 500 happened before.) */ 501 mcuw = tjMCUWidth[jpegSubsamp]; 502 mcuh = tjMCUHeight[jpegSubsamp]; 503 chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh); 504 retval = PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048; 505 506 bailout: 507 return retval; 508 } 509 510 DLLEXPORT unsigned long TJBUFSIZE(int width, int height) 511 { 512 unsigned long retval = 0; 513 514 if (width < 1 || height < 1) 515 _throwg("TJBUFSIZE(): Invalid argument"); 516 517 /* This allows for rare corner cases in which a JPEG image can actually be 518 larger than the uncompressed input (we wouldn't mention it if it hadn't 519 happened before.) */ 520 retval = PAD(width, 16) * PAD(height, 16) * 6 + 2048; 521 522 bailout: 523 return retval; 524 } 525 526 527 DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height, 528 int subsamp) 529 { 530 int retval = 0, nc, i; 531 532 if (subsamp < 0 || subsamp >= NUMSUBOPT) 533 _throwg("tjBufSizeYUV2(): Invalid argument"); 534 535 nc = (subsamp == TJSAMP_GRAY ? 1 : 3); 536 for (i = 0; i < nc; i++) { 537 int pw = tjPlaneWidth(i, width, subsamp); 538 int stride = PAD(pw, pad); 539 int ph = tjPlaneHeight(i, height, subsamp); 540 541 if (pw < 0 || ph < 0) return -1; 542 else retval += stride * ph; 543 } 544 545 bailout: 546 return retval; 547 } 548 549 DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp) 550 { 551 return tjBufSizeYUV2(width, 4, height, subsamp); 552 } 553 554 DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int subsamp) 555 { 556 return tjBufSizeYUV(width, height, subsamp); 557 } 558 559 560 DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp) 561 { 562 int pw, nc, retval = 0; 563 564 if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP) 565 _throwg("tjPlaneWidth(): Invalid argument"); 566 nc = (subsamp == TJSAMP_GRAY ? 1 : 3); 567 if (componentID < 0 || componentID >= nc) 568 _throwg("tjPlaneWidth(): Invalid argument"); 569 570 pw = PAD(width, tjMCUWidth[subsamp] / 8); 571 if (componentID == 0) 572 retval = pw; 573 else 574 retval = pw * 8 / tjMCUWidth[subsamp]; 575 576 bailout: 577 return retval; 578 } 579 580 581 DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp) 582 { 583 int ph, nc, retval = 0; 584 585 if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP) 586 _throwg("tjPlaneHeight(): Invalid argument"); 587 nc = (subsamp == TJSAMP_GRAY ? 1 : 3); 588 if (componentID < 0 || componentID >= nc) 589 _throwg("tjPlaneHeight(): Invalid argument"); 590 591 ph = PAD(height, tjMCUHeight[subsamp] / 8); 592 if (componentID == 0) 593 retval = ph; 594 else 595 retval = ph * 8 / tjMCUHeight[subsamp]; 596 597 bailout: 598 return retval; 599 } 600 601 602 DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride, 603 int height, int subsamp) 604 { 605 unsigned long retval = 0; 606 int pw, ph; 607 608 if (width < 1 || height < 1 || subsamp < 0 || subsamp >= NUMSUBOPT) 609 _throwg("tjPlaneSizeYUV(): Invalid argument"); 610 611 pw = tjPlaneWidth(componentID, width, subsamp); 612 ph = tjPlaneHeight(componentID, height, subsamp); 613 if (pw < 0 || ph < 0) return -1; 614 615 if (stride == 0) stride = pw; 616 else stride = abs(stride); 617 618 retval = stride * (ph - 1) + pw; 619 620 bailout: 621 return retval; 622 } 623 624 625 DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf, 626 int width, int pitch, int height, int pixelFormat, 627 unsigned char **jpegBuf, unsigned long *jpegSize, 628 int jpegSubsamp, int jpegQual, int flags) 629 { 630 int i, retval = 0, alloc = 1; 631 JSAMPROW *row_pointer = NULL; 632 633 getcinstance(handle) 634 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE; 635 if ((this->init & COMPRESS) == 0) 636 _throw("tjCompress2(): Instance has not been initialized for compression"); 637 638 if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 || 639 pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL || 640 jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT || 641 jpegQual < 0 || jpegQual > 100) 642 _throw("tjCompress2(): Invalid argument"); 643 644 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat]; 645 646 if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * height)) == NULL) 647 _throw("tjCompress2(): Memory allocation failure"); 648 649 if (setjmp(this->jerr.setjmp_buffer)) { 650 /* If we get here, the JPEG code has signaled an error. */ 651 retval = -1; goto bailout; 652 } 653 654 cinfo->image_width = width; 655 cinfo->image_height = height; 656 657 #ifndef NO_PUTENV 658 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 659 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 660 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 661 #endif 662 663 if (flags & TJFLAG_NOREALLOC) { 664 alloc = 0; *jpegSize = tjBufSize(width, height, jpegSubsamp); 665 } 666 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc); 667 if (setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags) == -1) 668 return -1; 669 670 jpeg_start_compress(cinfo, TRUE); 671 for (i = 0; i < height; i++) { 672 if (flags & TJFLAG_BOTTOMUP) 673 row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * pitch]; 674 else 675 row_pointer[i] = (JSAMPROW)&srcBuf[i * pitch]; 676 } 677 while (cinfo->next_scanline < cinfo->image_height) 678 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline], 679 cinfo->image_height - cinfo->next_scanline); 680 jpeg_finish_compress(cinfo); 681 682 bailout: 683 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo); 684 if (row_pointer) free(row_pointer); 685 if (this->jerr.warning) retval = -1; 686 this->jerr.stopOnWarning = FALSE; 687 return retval; 688 } 689 690 DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width, 691 int pitch, int height, int pixelSize, 692 unsigned char *jpegBuf, unsigned long *jpegSize, 693 int jpegSubsamp, int jpegQual, int flags) 694 { 695 int retval = 0; 696 unsigned long size; 697 698 if (flags & TJ_YUV) { 699 size = tjBufSizeYUV(width, height, jpegSubsamp); 700 retval = tjEncodeYUV2(handle, srcBuf, width, pitch, height, 701 getPixelFormat(pixelSize, flags), jpegBuf, 702 jpegSubsamp, flags); 703 } else { 704 retval = tjCompress2(handle, srcBuf, width, pitch, height, 705 getPixelFormat(pixelSize, flags), &jpegBuf, &size, 706 jpegSubsamp, jpegQual, flags | TJFLAG_NOREALLOC); 707 } 708 *jpegSize = size; 709 return retval; 710 } 711 712 713 DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf, 714 int width, int pitch, int height, 715 int pixelFormat, unsigned char **dstPlanes, 716 int *strides, int subsamp, int flags) 717 { 718 JSAMPROW *row_pointer = NULL; 719 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS]; 720 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS]; 721 JSAMPROW *outbuf[MAX_COMPONENTS]; 722 int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS]; 723 JSAMPLE *ptr; 724 jpeg_component_info *compptr; 725 726 getcinstance(handle); 727 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE; 728 729 for (i = 0; i < MAX_COMPONENTS; i++) { 730 tmpbuf[i] = NULL; _tmpbuf[i] = NULL; 731 tmpbuf2[i] = NULL; _tmpbuf2[i] = NULL; outbuf[i] = NULL; 732 } 733 734 if ((this->init & COMPRESS) == 0) 735 _throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression"); 736 737 if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 || 738 pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes || 739 !dstPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT) 740 _throw("tjEncodeYUVPlanes(): Invalid argument"); 741 if (subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2])) 742 _throw("tjEncodeYUVPlanes(): Invalid argument"); 743 744 if (pixelFormat == TJPF_CMYK) 745 _throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels"); 746 747 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat]; 748 749 if (setjmp(this->jerr.setjmp_buffer)) { 750 /* If we get here, the JPEG code has signaled an error. */ 751 retval = -1; goto bailout; 752 } 753 754 cinfo->image_width = width; 755 cinfo->image_height = height; 756 757 #ifndef NO_PUTENV 758 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 759 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 760 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 761 #endif 762 763 if (setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags) == -1) return -1; 764 765 /* Execute only the parts of jpeg_start_compress() that we need. If we 766 were to call the whole jpeg_start_compress() function, then it would try 767 to write the file headers, which could overflow the output buffer if the 768 YUV image were very small. */ 769 if (cinfo->global_state != CSTATE_START) 770 _throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state"); 771 (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo); 772 jinit_c_master_control(cinfo, FALSE); 773 jinit_color_converter(cinfo); 774 jinit_downsampler(cinfo); 775 (*cinfo->cconvert->start_pass) (cinfo); 776 777 pw0 = PAD(width, cinfo->max_h_samp_factor); 778 ph0 = PAD(height, cinfo->max_v_samp_factor); 779 780 if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL) 781 _throw("tjEncodeYUVPlanes(): Memory allocation failure"); 782 for (i = 0; i < height; i++) { 783 if (flags & TJFLAG_BOTTOMUP) 784 row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * pitch]; 785 else 786 row_pointer[i] = (JSAMPROW)&srcBuf[i * pitch]; 787 } 788 if (height < ph0) 789 for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1]; 790 791 for (i = 0; i < cinfo->num_components; i++) { 792 compptr = &cinfo->comp_info[i]; 793 _tmpbuf[i] = (JSAMPLE *)malloc( 794 PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) / 795 compptr->h_samp_factor, 32) * 796 cinfo->max_v_samp_factor + 32); 797 if (!_tmpbuf[i]) 798 _throw("tjEncodeYUVPlanes(): Memory allocation failure"); 799 tmpbuf[i] = 800 (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor); 801 if (!tmpbuf[i]) 802 _throw("tjEncodeYUVPlanes(): Memory allocation failure"); 803 for (row = 0; row < cinfo->max_v_samp_factor; row++) { 804 unsigned char *_tmpbuf_aligned = 805 (unsigned char *)PAD((size_t)_tmpbuf[i], 32); 806 807 tmpbuf[i][row] = &_tmpbuf_aligned[ 808 PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) / 809 compptr->h_samp_factor, 32) * row]; 810 } 811 _tmpbuf2[i] = 812 (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) * 813 compptr->v_samp_factor + 32); 814 if (!_tmpbuf2[i]) 815 _throw("tjEncodeYUVPlanes(): Memory allocation failure"); 816 tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor); 817 if (!tmpbuf2[i]) 818 _throw("tjEncodeYUVPlanes(): Memory allocation failure"); 819 for (row = 0; row < compptr->v_samp_factor; row++) { 820 unsigned char *_tmpbuf2_aligned = 821 (unsigned char *)PAD((size_t)_tmpbuf2[i], 32); 822 823 tmpbuf2[i][row] = 824 &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row]; 825 } 826 pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor; 827 ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor; 828 outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]); 829 if (!outbuf[i]) 830 _throw("tjEncodeYUVPlanes(): Memory allocation failure"); 831 ptr = dstPlanes[i]; 832 for (row = 0; row < ph[i]; row++) { 833 outbuf[i][row] = ptr; 834 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i]; 835 } 836 } 837 838 if (setjmp(this->jerr.setjmp_buffer)) { 839 /* If we get here, the JPEG code has signaled an error. */ 840 retval = -1; goto bailout; 841 } 842 843 for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) { 844 (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0, 845 cinfo->max_v_samp_factor); 846 (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0); 847 for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components; 848 i++, compptr++) 849 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i], 850 row * compptr->v_samp_factor / cinfo->max_v_samp_factor, 851 compptr->v_samp_factor, pw[i]); 852 } 853 cinfo->next_scanline += height; 854 jpeg_abort_compress(cinfo); 855 856 bailout: 857 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo); 858 if (row_pointer) free(row_pointer); 859 for (i = 0; i < MAX_COMPONENTS; i++) { 860 if (tmpbuf[i] != NULL) free(tmpbuf[i]); 861 if (_tmpbuf[i] != NULL) free(_tmpbuf[i]); 862 if (tmpbuf2[i] != NULL) free(tmpbuf2[i]); 863 if (_tmpbuf2[i] != NULL) free(_tmpbuf2[i]); 864 if (outbuf[i] != NULL) free(outbuf[i]); 865 } 866 if (this->jerr.warning) retval = -1; 867 this->jerr.stopOnWarning = FALSE; 868 return retval; 869 } 870 871 DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf, 872 int width, int pitch, int height, int pixelFormat, 873 unsigned char *dstBuf, int pad, int subsamp, 874 int flags) 875 { 876 unsigned char *dstPlanes[3]; 877 int pw0, ph0, strides[3], retval = -1; 878 tjinstance *this = (tjinstance *)handle; 879 880 if (!this) _throwg("tjEncodeYUV3(): Invalid handle"); 881 this->isInstanceError = FALSE; 882 883 if (width <= 0 || height <= 0 || dstBuf == NULL || pad < 0 || !isPow2(pad) || 884 subsamp < 0 || subsamp >= NUMSUBOPT) 885 _throw("tjEncodeYUV3(): Invalid argument"); 886 887 pw0 = tjPlaneWidth(0, width, subsamp); 888 ph0 = tjPlaneHeight(0, height, subsamp); 889 dstPlanes[0] = dstBuf; 890 strides[0] = PAD(pw0, pad); 891 if (subsamp == TJSAMP_GRAY) { 892 strides[1] = strides[2] = 0; 893 dstPlanes[1] = dstPlanes[2] = NULL; 894 } else { 895 int pw1 = tjPlaneWidth(1, width, subsamp); 896 int ph1 = tjPlaneHeight(1, height, subsamp); 897 898 strides[1] = strides[2] = PAD(pw1, pad); 899 dstPlanes[1] = dstPlanes[0] + strides[0] * ph0; 900 dstPlanes[2] = dstPlanes[1] + strides[1] * ph1; 901 } 902 903 return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat, 904 dstPlanes, strides, subsamp, flags); 905 906 bailout: 907 return retval; 908 } 909 910 DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width, 911 int pitch, int height, int pixelFormat, 912 unsigned char *dstBuf, int subsamp, int flags) 913 { 914 return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat, 915 dstBuf, 4, subsamp, flags); 916 } 917 918 DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width, 919 int pitch, int height, int pixelSize, 920 unsigned char *dstBuf, int subsamp, int flags) 921 { 922 return tjEncodeYUV2(handle, srcBuf, width, pitch, height, 923 getPixelFormat(pixelSize, flags), dstBuf, subsamp, 924 flags); 925 } 926 927 928 DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle, 929 const unsigned char **srcPlanes, 930 int width, const int *strides, 931 int height, int subsamp, 932 unsigned char **jpegBuf, 933 unsigned long *jpegSize, int jpegQual, 934 int flags) 935 { 936 int i, row, retval = 0, alloc = 1; 937 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS], 938 tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS]; 939 JSAMPLE *_tmpbuf = NULL, *ptr; 940 JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS]; 941 942 getcinstance(handle) 943 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE; 944 945 for (i = 0; i < MAX_COMPONENTS; i++) { 946 tmpbuf[i] = NULL; inbuf[i] = NULL; 947 } 948 949 if ((this->init & COMPRESS) == 0) 950 _throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression"); 951 952 if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 || 953 subsamp < 0 || subsamp >= NUMSUBOPT || jpegBuf == NULL || 954 jpegSize == NULL || jpegQual < 0 || jpegQual > 100) 955 _throw("tjCompressFromYUVPlanes(): Invalid argument"); 956 if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2])) 957 _throw("tjCompressFromYUVPlanes(): Invalid argument"); 958 959 if (setjmp(this->jerr.setjmp_buffer)) { 960 /* If we get here, the JPEG code has signaled an error. */ 961 retval = -1; goto bailout; 962 } 963 964 cinfo->image_width = width; 965 cinfo->image_height = height; 966 967 #ifndef NO_PUTENV 968 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 969 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 970 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 971 #endif 972 973 if (flags & TJFLAG_NOREALLOC) { 974 alloc = 0; *jpegSize = tjBufSize(width, height, subsamp); 975 } 976 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc); 977 if (setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags) == -1) 978 return -1; 979 cinfo->raw_data_in = TRUE; 980 981 jpeg_start_compress(cinfo, TRUE); 982 for (i = 0; i < cinfo->num_components; i++) { 983 jpeg_component_info *compptr = &cinfo->comp_info[i]; 984 int ih; 985 986 iw[i] = compptr->width_in_blocks * DCTSIZE; 987 ih = compptr->height_in_blocks * DCTSIZE; 988 pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) * 989 compptr->h_samp_factor / cinfo->max_h_samp_factor; 990 ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) * 991 compptr->v_samp_factor / cinfo->max_v_samp_factor; 992 if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1; 993 th[i] = compptr->v_samp_factor * DCTSIZE; 994 tmpbufsize += iw[i] * th[i]; 995 if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL) 996 _throw("tjCompressFromYUVPlanes(): Memory allocation failure"); 997 ptr = (JSAMPLE *)srcPlanes[i]; 998 for (row = 0; row < ph[i]; row++) { 999 inbuf[i][row] = ptr; 1000 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i]; 1001 } 1002 } 1003 if (usetmpbuf) { 1004 if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL) 1005 _throw("tjCompressFromYUVPlanes(): Memory allocation failure"); 1006 ptr = _tmpbuf; 1007 for (i = 0; i < cinfo->num_components; i++) { 1008 if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL) 1009 _throw("tjCompressFromYUVPlanes(): Memory allocation failure"); 1010 for (row = 0; row < th[i]; row++) { 1011 tmpbuf[i][row] = ptr; 1012 ptr += iw[i]; 1013 } 1014 } 1015 } 1016 1017 if (setjmp(this->jerr.setjmp_buffer)) { 1018 /* If we get here, the JPEG code has signaled an error. */ 1019 retval = -1; goto bailout; 1020 } 1021 1022 for (row = 0; row < (int)cinfo->image_height; 1023 row += cinfo->max_v_samp_factor * DCTSIZE) { 1024 JSAMPARRAY yuvptr[MAX_COMPONENTS]; 1025 int crow[MAX_COMPONENTS]; 1026 1027 for (i = 0; i < cinfo->num_components; i++) { 1028 jpeg_component_info *compptr = &cinfo->comp_info[i]; 1029 1030 crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor; 1031 if (usetmpbuf) { 1032 int j, k; 1033 1034 for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) { 1035 memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]); 1036 /* Duplicate last sample in row to fill out MCU */ 1037 for (k = pw[i]; k < iw[i]; k++) 1038 tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1]; 1039 } 1040 /* Duplicate last row to fill out MCU */ 1041 for (j = ph[i] - crow[i]; j < th[i]; j++) 1042 memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]); 1043 yuvptr[i] = tmpbuf[i]; 1044 } else 1045 yuvptr[i] = &inbuf[i][crow[i]]; 1046 } 1047 jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE); 1048 } 1049 jpeg_finish_compress(cinfo); 1050 1051 bailout: 1052 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo); 1053 for (i = 0; i < MAX_COMPONENTS; i++) { 1054 if (tmpbuf[i]) free(tmpbuf[i]); 1055 if (inbuf[i]) free(inbuf[i]); 1056 } 1057 if (_tmpbuf) free(_tmpbuf); 1058 if (this->jerr.warning) retval = -1; 1059 this->jerr.stopOnWarning = FALSE; 1060 return retval; 1061 } 1062 1063 DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf, 1064 int width, int pad, int height, int subsamp, 1065 unsigned char **jpegBuf, 1066 unsigned long *jpegSize, int jpegQual, 1067 int flags) 1068 { 1069 const unsigned char *srcPlanes[3]; 1070 int pw0, ph0, strides[3], retval = -1; 1071 tjinstance *this = (tjinstance *)handle; 1072 1073 if (!this) _throwg("tjCompressFromYUV(): Invalid handle"); 1074 this->isInstanceError = FALSE; 1075 1076 if (srcBuf == NULL || width <= 0 || pad < 1 || height <= 0 || subsamp < 0 || 1077 subsamp >= NUMSUBOPT) 1078 _throw("tjCompressFromYUV(): Invalid argument"); 1079 1080 pw0 = tjPlaneWidth(0, width, subsamp); 1081 ph0 = tjPlaneHeight(0, height, subsamp); 1082 srcPlanes[0] = srcBuf; 1083 strides[0] = PAD(pw0, pad); 1084 if (subsamp == TJSAMP_GRAY) { 1085 strides[1] = strides[2] = 0; 1086 srcPlanes[1] = srcPlanes[2] = NULL; 1087 } else { 1088 int pw1 = tjPlaneWidth(1, width, subsamp); 1089 int ph1 = tjPlaneHeight(1, height, subsamp); 1090 1091 strides[1] = strides[2] = PAD(pw1, pad); 1092 srcPlanes[1] = srcPlanes[0] + strides[0] * ph0; 1093 srcPlanes[2] = srcPlanes[1] + strides[1] * ph1; 1094 } 1095 1096 return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height, 1097 subsamp, jpegBuf, jpegSize, jpegQual, flags); 1098 1099 bailout: 1100 return retval; 1101 } 1102 1103 1104 /* Decompressor */ 1105 1106 static tjhandle _tjInitDecompress(tjinstance *this) 1107 { 1108 static unsigned char buffer[1]; 1109 1110 /* This is also straight out of example.txt */ 1111 this->dinfo.err = jpeg_std_error(&this->jerr.pub); 1112 this->jerr.pub.error_exit = my_error_exit; 1113 this->jerr.pub.output_message = my_output_message; 1114 this->jerr.emit_message = this->jerr.pub.emit_message; 1115 this->jerr.pub.emit_message = my_emit_message; 1116 this->jerr.pub.addon_message_table = turbojpeg_message_table; 1117 this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE; 1118 this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE; 1119 1120 if (setjmp(this->jerr.setjmp_buffer)) { 1121 /* If we get here, the JPEG code has signaled an error. */ 1122 if (this) free(this); 1123 return NULL; 1124 } 1125 1126 jpeg_create_decompress(&this->dinfo); 1127 /* Make an initial call so it will create the source manager */ 1128 jpeg_mem_src_tj(&this->dinfo, buffer, 1); 1129 1130 this->init |= DECOMPRESS; 1131 return (tjhandle)this; 1132 } 1133 1134 DLLEXPORT tjhandle tjInitDecompress(void) 1135 { 1136 tjinstance *this; 1137 1138 if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) { 1139 snprintf(errStr, JMSG_LENGTH_MAX, 1140 "tjInitDecompress(): Memory allocation failure"); 1141 return NULL; 1142 } 1143 MEMZERO(this, sizeof(tjinstance)); 1144 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error"); 1145 return _tjInitDecompress(this); 1146 } 1147 1148 1149 DLLEXPORT int tjDecompressHeader3(tjhandle handle, 1150 const unsigned char *jpegBuf, 1151 unsigned long jpegSize, int *width, 1152 int *height, int *jpegSubsamp, 1153 int *jpegColorspace) 1154 { 1155 int retval = 0; 1156 1157 getdinstance(handle); 1158 if ((this->init & DECOMPRESS) == 0) 1159 _throw("tjDecompressHeader3(): Instance has not been initialized for decompression"); 1160 1161 if (jpegBuf == NULL || jpegSize <= 0 || width == NULL || height == NULL || 1162 jpegSubsamp == NULL || jpegColorspace == NULL) 1163 _throw("tjDecompressHeader3(): Invalid argument"); 1164 1165 if (setjmp(this->jerr.setjmp_buffer)) { 1166 /* If we get here, the JPEG code has signaled an error. */ 1167 return -1; 1168 } 1169 1170 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); 1171 jpeg_read_header(dinfo, TRUE); 1172 1173 *width = dinfo->image_width; 1174 *height = dinfo->image_height; 1175 *jpegSubsamp = getSubsamp(dinfo); 1176 switch (dinfo->jpeg_color_space) { 1177 case JCS_GRAYSCALE: *jpegColorspace = TJCS_GRAY; break; 1178 case JCS_RGB: *jpegColorspace = TJCS_RGB; break; 1179 case JCS_YCbCr: *jpegColorspace = TJCS_YCbCr; break; 1180 case JCS_CMYK: *jpegColorspace = TJCS_CMYK; break; 1181 case JCS_YCCK: *jpegColorspace = TJCS_YCCK; break; 1182 default: *jpegColorspace = -1; break; 1183 } 1184 1185 jpeg_abort_decompress(dinfo); 1186 1187 if (*jpegSubsamp < 0) 1188 _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image"); 1189 if (*jpegColorspace < 0) 1190 _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image"); 1191 if (*width < 1 || *height < 1) 1192 _throw("tjDecompressHeader3(): Invalid data returned in header"); 1193 1194 bailout: 1195 if (this->jerr.warning) retval = -1; 1196 return retval; 1197 } 1198 1199 DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf, 1200 unsigned long jpegSize, int *width, 1201 int *height, int *jpegSubsamp) 1202 { 1203 int jpegColorspace; 1204 1205 return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height, 1206 jpegSubsamp, &jpegColorspace); 1207 } 1208 1209 DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf, 1210 unsigned long jpegSize, int *width, 1211 int *height) 1212 { 1213 int jpegSubsamp; 1214 1215 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height, 1216 &jpegSubsamp); 1217 } 1218 1219 1220 DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numscalingfactors) 1221 { 1222 if (numscalingfactors == NULL) { 1223 snprintf(errStr, JMSG_LENGTH_MAX, 1224 "tjGetScalingFactors(): Invalid argument"); 1225 return NULL; 1226 } 1227 1228 *numscalingfactors = NUMSF; 1229 return (tjscalingfactor *)sf; 1230 } 1231 1232 1233 DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf, 1234 unsigned long jpegSize, unsigned char *dstBuf, 1235 int width, int pitch, int height, int pixelFormat, 1236 int flags) 1237 { 1238 JSAMPROW *row_pointer = NULL; 1239 int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh; 1240 1241 getdinstance(handle); 1242 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE; 1243 if ((this->init & DECOMPRESS) == 0) 1244 _throw("tjDecompress2(): Instance has not been initialized for decompression"); 1245 1246 if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 || 1247 pitch < 0 || height < 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF) 1248 _throw("tjDecompress2(): Invalid argument"); 1249 1250 #ifndef NO_PUTENV 1251 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 1252 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 1253 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 1254 #endif 1255 1256 if (setjmp(this->jerr.setjmp_buffer)) { 1257 /* If we get here, the JPEG code has signaled an error. */ 1258 retval = -1; goto bailout; 1259 } 1260 1261 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); 1262 jpeg_read_header(dinfo, TRUE); 1263 this->dinfo.out_color_space = pf2cs[pixelFormat]; 1264 if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST; 1265 if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE; 1266 1267 jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height; 1268 if (width == 0) width = jpegwidth; 1269 if (height == 0) height = jpegheight; 1270 for (i = 0; i < NUMSF; i++) { 1271 scaledw = TJSCALED(jpegwidth, sf[i]); 1272 scaledh = TJSCALED(jpegheight, sf[i]); 1273 if (scaledw <= width && scaledh <= height) 1274 break; 1275 } 1276 if (i >= NUMSF) 1277 _throw("tjDecompress2(): Could not scale down to desired image dimensions"); 1278 width = scaledw; height = scaledh; 1279 dinfo->scale_num = sf[i].num; 1280 dinfo->scale_denom = sf[i].denom; 1281 1282 jpeg_start_decompress(dinfo); 1283 if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat]; 1284 1285 if ((row_pointer = 1286 (JSAMPROW *)malloc(sizeof(JSAMPROW) * dinfo->output_height)) == NULL) 1287 _throw("tjDecompress2(): Memory allocation failure"); 1288 if (setjmp(this->jerr.setjmp_buffer)) { 1289 /* If we get here, the JPEG code has signaled an error. */ 1290 retval = -1; goto bailout; 1291 } 1292 for (i = 0; i < (int)dinfo->output_height; i++) { 1293 if (flags & TJFLAG_BOTTOMUP) 1294 row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * pitch]; 1295 else 1296 row_pointer[i] = &dstBuf[i * pitch]; 1297 } 1298 while (dinfo->output_scanline < dinfo->output_height) 1299 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline], 1300 dinfo->output_height - dinfo->output_scanline); 1301 jpeg_finish_decompress(dinfo); 1302 1303 bailout: 1304 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo); 1305 if (row_pointer) free(row_pointer); 1306 if (this->jerr.warning) retval = -1; 1307 this->jerr.stopOnWarning = FALSE; 1308 return retval; 1309 } 1310 1311 DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf, 1312 unsigned long jpegSize, unsigned char *dstBuf, 1313 int width, int pitch, int height, int pixelSize, 1314 int flags) 1315 { 1316 if (flags & TJ_YUV) 1317 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags); 1318 else 1319 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch, 1320 height, getPixelFormat(pixelSize, flags), flags); 1321 } 1322 1323 1324 static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo, 1325 int pixelFormat, int subsamp, int flags) 1326 { 1327 int i; 1328 1329 dinfo->scale_num = dinfo->scale_denom = 1; 1330 1331 if (subsamp == TJSAMP_GRAY) { 1332 dinfo->num_components = dinfo->comps_in_scan = 1; 1333 dinfo->jpeg_color_space = JCS_GRAYSCALE; 1334 } else { 1335 dinfo->num_components = dinfo->comps_in_scan = 3; 1336 dinfo->jpeg_color_space = JCS_YCbCr; 1337 } 1338 1339 dinfo->comp_info = (jpeg_component_info *) 1340 (*dinfo->mem->alloc_small) ((j_common_ptr)dinfo, JPOOL_IMAGE, 1341 dinfo->num_components * 1342 sizeof(jpeg_component_info)); 1343 1344 for (i = 0; i < dinfo->num_components; i++) { 1345 jpeg_component_info *compptr = &dinfo->comp_info[i]; 1346 1347 compptr->h_samp_factor = (i == 0) ? tjMCUWidth[subsamp] / 8 : 1; 1348 compptr->v_samp_factor = (i == 0) ? tjMCUHeight[subsamp] / 8 : 1; 1349 compptr->component_index = i; 1350 compptr->component_id = i + 1; 1351 compptr->quant_tbl_no = compptr->dc_tbl_no = 1352 compptr->ac_tbl_no = (i == 0) ? 0 : 1; 1353 dinfo->cur_comp_info[i] = compptr; 1354 } 1355 dinfo->data_precision = 8; 1356 for (i = 0; i < 2; i++) { 1357 if (dinfo->quant_tbl_ptrs[i] == NULL) 1358 dinfo->quant_tbl_ptrs[i] = jpeg_alloc_quant_table((j_common_ptr)dinfo); 1359 } 1360 1361 return 0; 1362 } 1363 1364 1365 int my_read_markers(j_decompress_ptr dinfo) 1366 { 1367 return JPEG_REACHED_SOS; 1368 } 1369 1370 void my_reset_marker_reader(j_decompress_ptr dinfo) 1371 { 1372 } 1373 1374 DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle, 1375 const unsigned char **srcPlanes, 1376 const int *strides, int subsamp, 1377 unsigned char *dstBuf, int width, int pitch, 1378 int height, int pixelFormat, int flags) 1379 { 1380 JSAMPROW *row_pointer = NULL; 1381 JSAMPLE *_tmpbuf[MAX_COMPONENTS]; 1382 JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS]; 1383 int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS]; 1384 JSAMPLE *ptr; 1385 jpeg_component_info *compptr; 1386 int (*old_read_markers) (j_decompress_ptr); 1387 void (*old_reset_marker_reader) (j_decompress_ptr); 1388 1389 getdinstance(handle); 1390 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE; 1391 1392 for (i = 0; i < MAX_COMPONENTS; i++) { 1393 tmpbuf[i] = NULL; _tmpbuf[i] = NULL; inbuf[i] = NULL; 1394 } 1395 1396 if ((this->init & DECOMPRESS) == 0) 1397 _throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression"); 1398 1399 if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT || 1400 dstBuf == NULL || width <= 0 || pitch < 0 || height <= 0 || 1401 pixelFormat < 0 || pixelFormat >= TJ_NUMPF) 1402 _throw("tjDecodeYUVPlanes(): Invalid argument"); 1403 if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2])) 1404 _throw("tjDecodeYUVPlanes(): Invalid argument"); 1405 1406 if (setjmp(this->jerr.setjmp_buffer)) { 1407 /* If we get here, the JPEG code has signaled an error. */ 1408 retval = -1; goto bailout; 1409 } 1410 1411 if (pixelFormat == TJPF_CMYK) 1412 _throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels."); 1413 1414 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat]; 1415 dinfo->image_width = width; 1416 dinfo->image_height = height; 1417 1418 #ifndef NO_PUTENV 1419 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 1420 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 1421 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 1422 #endif 1423 1424 if (setDecodeDefaults(dinfo, pixelFormat, subsamp, flags) == -1) { 1425 retval = -1; goto bailout; 1426 } 1427 old_read_markers = dinfo->marker->read_markers; 1428 dinfo->marker->read_markers = my_read_markers; 1429 old_reset_marker_reader = dinfo->marker->reset_marker_reader; 1430 dinfo->marker->reset_marker_reader = my_reset_marker_reader; 1431 jpeg_read_header(dinfo, TRUE); 1432 dinfo->marker->read_markers = old_read_markers; 1433 dinfo->marker->reset_marker_reader = old_reset_marker_reader; 1434 1435 this->dinfo.out_color_space = pf2cs[pixelFormat]; 1436 if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST; 1437 dinfo->do_fancy_upsampling = FALSE; 1438 dinfo->Se = DCTSIZE2 - 1; 1439 jinit_master_decompress(dinfo); 1440 (*dinfo->upsample->start_pass) (dinfo); 1441 1442 pw0 = PAD(width, dinfo->max_h_samp_factor); 1443 ph0 = PAD(height, dinfo->max_v_samp_factor); 1444 1445 if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat]; 1446 1447 if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL) 1448 _throw("tjDecodeYUVPlanes(): Memory allocation failure"); 1449 for (i = 0; i < height; i++) { 1450 if (flags & TJFLAG_BOTTOMUP) 1451 row_pointer[i] = &dstBuf[(height - i - 1) * pitch]; 1452 else 1453 row_pointer[i] = &dstBuf[i * pitch]; 1454 } 1455 if (height < ph0) 1456 for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1]; 1457 1458 for (i = 0; i < dinfo->num_components; i++) { 1459 compptr = &dinfo->comp_info[i]; 1460 _tmpbuf[i] = 1461 (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) * 1462 compptr->v_samp_factor + 32); 1463 if (!_tmpbuf[i]) 1464 _throw("tjDecodeYUVPlanes(): Memory allocation failure"); 1465 tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor); 1466 if (!tmpbuf[i]) 1467 _throw("tjDecodeYUVPlanes(): Memory allocation failure"); 1468 for (row = 0; row < compptr->v_samp_factor; row++) { 1469 unsigned char *_tmpbuf_aligned = 1470 (unsigned char *)PAD((size_t)_tmpbuf[i], 32); 1471 1472 tmpbuf[i][row] = 1473 &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row]; 1474 } 1475 pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor; 1476 ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor; 1477 inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]); 1478 if (!inbuf[i]) 1479 _throw("tjDecodeYUVPlanes(): Memory allocation failure"); 1480 ptr = (JSAMPLE *)srcPlanes[i]; 1481 for (row = 0; row < ph[i]; row++) { 1482 inbuf[i][row] = ptr; 1483 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i]; 1484 } 1485 } 1486 1487 if (setjmp(this->jerr.setjmp_buffer)) { 1488 /* If we get here, the JPEG code has signaled an error. */ 1489 retval = -1; goto bailout; 1490 } 1491 1492 for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) { 1493 JDIMENSION inrow = 0, outrow = 0; 1494 1495 for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components; 1496 i++, compptr++) 1497 jcopy_sample_rows(inbuf[i], 1498 row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0, 1499 compptr->v_samp_factor, pw[i]); 1500 (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow, 1501 dinfo->max_v_samp_factor, &row_pointer[row], 1502 &outrow, dinfo->max_v_samp_factor); 1503 } 1504 jpeg_abort_decompress(dinfo); 1505 1506 bailout: 1507 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo); 1508 if (row_pointer) free(row_pointer); 1509 for (i = 0; i < MAX_COMPONENTS; i++) { 1510 if (tmpbuf[i] != NULL) free(tmpbuf[i]); 1511 if (_tmpbuf[i] != NULL) free(_tmpbuf[i]); 1512 if (inbuf[i] != NULL) free(inbuf[i]); 1513 } 1514 if (this->jerr.warning) retval = -1; 1515 this->jerr.stopOnWarning = FALSE; 1516 return retval; 1517 } 1518 1519 DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf, 1520 int pad, int subsamp, unsigned char *dstBuf, 1521 int width, int pitch, int height, int pixelFormat, 1522 int flags) 1523 { 1524 const unsigned char *srcPlanes[3]; 1525 int pw0, ph0, strides[3], retval = -1; 1526 tjinstance *this = (tjinstance *)handle; 1527 1528 if (!this) _throwg("tjDecodeYUV(): Invalid handle"); 1529 this->isInstanceError = FALSE; 1530 1531 if (srcBuf == NULL || pad < 0 || !isPow2(pad) || subsamp < 0 || 1532 subsamp >= NUMSUBOPT || width <= 0 || height <= 0) 1533 _throw("tjDecodeYUV(): Invalid argument"); 1534 1535 pw0 = tjPlaneWidth(0, width, subsamp); 1536 ph0 = tjPlaneHeight(0, height, subsamp); 1537 srcPlanes[0] = srcBuf; 1538 strides[0] = PAD(pw0, pad); 1539 if (subsamp == TJSAMP_GRAY) { 1540 strides[1] = strides[2] = 0; 1541 srcPlanes[1] = srcPlanes[2] = NULL; 1542 } else { 1543 int pw1 = tjPlaneWidth(1, width, subsamp); 1544 int ph1 = tjPlaneHeight(1, height, subsamp); 1545 1546 strides[1] = strides[2] = PAD(pw1, pad); 1547 srcPlanes[1] = srcPlanes[0] + strides[0] * ph0; 1548 srcPlanes[2] = srcPlanes[1] + strides[1] * ph1; 1549 } 1550 1551 return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width, 1552 pitch, height, pixelFormat, flags); 1553 1554 bailout: 1555 return retval; 1556 } 1557 1558 DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle, 1559 const unsigned char *jpegBuf, 1560 unsigned long jpegSize, 1561 unsigned char **dstPlanes, int width, 1562 int *strides, int height, int flags) 1563 { 1564 int i, sfi, row, retval = 0; 1565 int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh; 1566 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS], 1567 tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS]; 1568 JSAMPLE *_tmpbuf = NULL, *ptr; 1569 JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS]; 1570 int dctsize; 1571 1572 getdinstance(handle); 1573 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE; 1574 1575 for (i = 0; i < MAX_COMPONENTS; i++) { 1576 tmpbuf[i] = NULL; outbuf[i] = NULL; 1577 } 1578 1579 if ((this->init & DECOMPRESS) == 0) 1580 _throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression"); 1581 1582 if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0] || 1583 width < 0 || height < 0) 1584 _throw("tjDecompressToYUVPlanes(): Invalid argument"); 1585 1586 #ifndef NO_PUTENV 1587 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 1588 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 1589 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 1590 #endif 1591 1592 if (setjmp(this->jerr.setjmp_buffer)) { 1593 /* If we get here, the JPEG code has signaled an error. */ 1594 retval = -1; goto bailout; 1595 } 1596 1597 if (!this->headerRead) { 1598 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); 1599 jpeg_read_header(dinfo, TRUE); 1600 } 1601 this->headerRead = 0; 1602 jpegSubsamp = getSubsamp(dinfo); 1603 if (jpegSubsamp < 0) 1604 _throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image"); 1605 1606 if (jpegSubsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2])) 1607 _throw("tjDecompressToYUVPlanes(): Invalid argument"); 1608 1609 jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height; 1610 if (width == 0) width = jpegwidth; 1611 if (height == 0) height = jpegheight; 1612 for (i = 0; i < NUMSF; i++) { 1613 scaledw = TJSCALED(jpegwidth, sf[i]); 1614 scaledh = TJSCALED(jpegheight, sf[i]); 1615 if (scaledw <= width && scaledh <= height) 1616 break; 1617 } 1618 if (i >= NUMSF) 1619 _throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions"); 1620 if (dinfo->num_components > 3) 1621 _throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components"); 1622 1623 width = scaledw; height = scaledh; 1624 dinfo->scale_num = sf[i].num; 1625 dinfo->scale_denom = sf[i].denom; 1626 sfi = i; 1627 jpeg_calc_output_dimensions(dinfo); 1628 1629 dctsize = DCTSIZE * sf[sfi].num / sf[sfi].denom; 1630 1631 for (i = 0; i < dinfo->num_components; i++) { 1632 jpeg_component_info *compptr = &dinfo->comp_info[i]; 1633 int ih; 1634 1635 iw[i] = compptr->width_in_blocks * dctsize; 1636 ih = compptr->height_in_blocks * dctsize; 1637 pw[i] = PAD(dinfo->output_width, dinfo->max_h_samp_factor) * 1638 compptr->h_samp_factor / dinfo->max_h_samp_factor; 1639 ph[i] = PAD(dinfo->output_height, dinfo->max_v_samp_factor) * 1640 compptr->v_samp_factor / dinfo->max_v_samp_factor; 1641 if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1; 1642 th[i] = compptr->v_samp_factor * dctsize; 1643 tmpbufsize += iw[i] * th[i]; 1644 if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL) 1645 _throw("tjDecompressToYUVPlanes(): Memory allocation failure"); 1646 ptr = dstPlanes[i]; 1647 for (row = 0; row < ph[i]; row++) { 1648 outbuf[i][row] = ptr; 1649 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i]; 1650 } 1651 } 1652 if (usetmpbuf) { 1653 if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL) 1654 _throw("tjDecompressToYUVPlanes(): Memory allocation failure"); 1655 ptr = _tmpbuf; 1656 for (i = 0; i < dinfo->num_components; i++) { 1657 if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL) 1658 _throw("tjDecompressToYUVPlanes(): Memory allocation failure"); 1659 for (row = 0; row < th[i]; row++) { 1660 tmpbuf[i][row] = ptr; 1661 ptr += iw[i]; 1662 } 1663 } 1664 } 1665 1666 if (setjmp(this->jerr.setjmp_buffer)) { 1667 /* If we get here, the JPEG code has signaled an error. */ 1668 retval = -1; goto bailout; 1669 } 1670 1671 if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE; 1672 if (flags & TJFLAG_FASTDCT) dinfo->dct_method = JDCT_FASTEST; 1673 dinfo->raw_data_out = TRUE; 1674 1675 jpeg_start_decompress(dinfo); 1676 for (row = 0; row < (int)dinfo->output_height; 1677 row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) { 1678 JSAMPARRAY yuvptr[MAX_COMPONENTS]; 1679 int crow[MAX_COMPONENTS]; 1680 1681 for (i = 0; i < dinfo->num_components; i++) { 1682 jpeg_component_info *compptr = &dinfo->comp_info[i]; 1683 1684 if (jpegSubsamp == TJ_420) { 1685 /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try 1686 to be clever and use the IDCT to perform upsampling on the U and V 1687 planes. For instance, if the output image is to be scaled by 1/2 1688 relative to the JPEG image, then the scaling factor and upsampling 1689 effectively cancel each other, so a normal 8x8 IDCT can be used. 1690 However, this is not desirable when using the decompress-to-YUV 1691 functionality in TurboJPEG, since we want to output the U and V 1692 planes in their subsampled form. Thus, we have to override some 1693 internal libjpeg parameters to force it to use the "scaled" IDCT 1694 functions on the U and V planes. */ 1695 compptr->_DCT_scaled_size = dctsize; 1696 compptr->MCU_sample_width = tjMCUWidth[jpegSubsamp] * 1697 sf[sfi].num / sf[sfi].denom * 1698 compptr->v_samp_factor / dinfo->max_v_samp_factor; 1699 dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0]; 1700 } 1701 crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor; 1702 if (usetmpbuf) yuvptr[i] = tmpbuf[i]; 1703 else yuvptr[i] = &outbuf[i][crow[i]]; 1704 } 1705 jpeg_read_raw_data(dinfo, yuvptr, 1706 dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size); 1707 if (usetmpbuf) { 1708 int j; 1709 1710 for (i = 0; i < dinfo->num_components; i++) { 1711 for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) { 1712 memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]); 1713 } 1714 } 1715 } 1716 } 1717 jpeg_finish_decompress(dinfo); 1718 1719 bailout: 1720 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo); 1721 for (i = 0; i < MAX_COMPONENTS; i++) { 1722 if (tmpbuf[i]) free(tmpbuf[i]); 1723 if (outbuf[i]) free(outbuf[i]); 1724 } 1725 if (_tmpbuf) free(_tmpbuf); 1726 if (this->jerr.warning) retval = -1; 1727 this->jerr.stopOnWarning = FALSE; 1728 return retval; 1729 } 1730 1731 DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf, 1732 unsigned long jpegSize, unsigned char *dstBuf, 1733 int width, int pad, int height, int flags) 1734 { 1735 unsigned char *dstPlanes[3]; 1736 int pw0, ph0, strides[3], retval = -1, jpegSubsamp = -1; 1737 int i, jpegwidth, jpegheight, scaledw, scaledh; 1738 1739 getdinstance(handle); 1740 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE; 1741 1742 if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 || 1743 pad < 1 || !isPow2(pad) || height < 0) 1744 _throw("tjDecompressToYUV2(): Invalid argument"); 1745 1746 if (setjmp(this->jerr.setjmp_buffer)) { 1747 /* If we get here, the JPEG code has signaled an error. */ 1748 return -1; 1749 } 1750 1751 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); 1752 jpeg_read_header(dinfo, TRUE); 1753 jpegSubsamp = getSubsamp(dinfo); 1754 if (jpegSubsamp < 0) 1755 _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image"); 1756 1757 jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height; 1758 if (width == 0) width = jpegwidth; 1759 if (height == 0) height = jpegheight; 1760 1761 for (i = 0; i < NUMSF; i++) { 1762 scaledw = TJSCALED(jpegwidth, sf[i]); 1763 scaledh = TJSCALED(jpegheight, sf[i]); 1764 if (scaledw <= width && scaledh <= height) 1765 break; 1766 } 1767 if (i >= NUMSF) 1768 _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions"); 1769 1770 pw0 = tjPlaneWidth(0, width, jpegSubsamp); 1771 ph0 = tjPlaneHeight(0, height, jpegSubsamp); 1772 dstPlanes[0] = dstBuf; 1773 strides[0] = PAD(pw0, pad); 1774 if (jpegSubsamp == TJSAMP_GRAY) { 1775 strides[1] = strides[2] = 0; 1776 dstPlanes[1] = dstPlanes[2] = NULL; 1777 } else { 1778 int pw1 = tjPlaneWidth(1, width, jpegSubsamp); 1779 int ph1 = tjPlaneHeight(1, height, jpegSubsamp); 1780 1781 strides[1] = strides[2] = PAD(pw1, pad); 1782 dstPlanes[1] = dstPlanes[0] + strides[0] * ph0; 1783 dstPlanes[2] = dstPlanes[1] + strides[1] * ph1; 1784 } 1785 1786 this->headerRead = 1; 1787 return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width, 1788 strides, height, flags); 1789 1790 bailout: 1791 this->jerr.stopOnWarning = FALSE; 1792 return retval; 1793 } 1794 1795 DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf, 1796 unsigned long jpegSize, unsigned char *dstBuf, 1797 int flags) 1798 { 1799 return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags); 1800 } 1801 1802 1803 /* Transformer */ 1804 1805 DLLEXPORT tjhandle tjInitTransform(void) 1806 { 1807 tjinstance *this = NULL; 1808 tjhandle handle = NULL; 1809 1810 if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) { 1811 snprintf(errStr, JMSG_LENGTH_MAX, 1812 "tjInitTransform(): Memory allocation failure"); 1813 return NULL; 1814 } 1815 MEMZERO(this, sizeof(tjinstance)); 1816 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error"); 1817 handle = _tjInitCompress(this); 1818 if (!handle) return NULL; 1819 handle = _tjInitDecompress(this); 1820 return handle; 1821 } 1822 1823 1824 DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf, 1825 unsigned long jpegSize, int n, 1826 unsigned char **dstBufs, unsigned long *dstSizes, 1827 tjtransform *t, int flags) 1828 { 1829 jpeg_transform_info *xinfo = NULL; 1830 jvirt_barray_ptr *srccoefs, *dstcoefs; 1831 int retval = 0, i, jpegSubsamp, saveMarkers = 0; 1832 1833 getinstance(handle); 1834 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE; 1835 if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0) 1836 _throw("tjTransform(): Instance has not been initialized for transformation"); 1837 1838 if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL || 1839 dstSizes == NULL || t == NULL || flags < 0) 1840 _throw("tjTransform(): Invalid argument"); 1841 1842 #ifndef NO_PUTENV 1843 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); 1844 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); 1845 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); 1846 #endif 1847 1848 if ((xinfo = 1849 (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL) 1850 _throw("tjTransform(): Memory allocation failure"); 1851 MEMZERO(xinfo, sizeof(jpeg_transform_info) * n); 1852 1853 if (setjmp(this->jerr.setjmp_buffer)) { 1854 /* If we get here, the JPEG code has signaled an error. */ 1855 retval = -1; goto bailout; 1856 } 1857 1858 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); 1859 1860 for (i = 0; i < n; i++) { 1861 xinfo[i].transform = xformtypes[t[i].op]; 1862 xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0; 1863 xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0; 1864 xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0; 1865 xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0; 1866 if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1; 1867 else xinfo[i].slow_hflip = 0; 1868 1869 if (xinfo[i].crop) { 1870 xinfo[i].crop_xoffset = t[i].r.x; xinfo[i].crop_xoffset_set = JCROP_POS; 1871 xinfo[i].crop_yoffset = t[i].r.y; xinfo[i].crop_yoffset_set = JCROP_POS; 1872 if (t[i].r.w != 0) { 1873 xinfo[i].crop_width = t[i].r.w; xinfo[i].crop_width_set = JCROP_POS; 1874 } else 1875 xinfo[i].crop_width = JCROP_UNSET; 1876 if (t[i].r.h != 0) { 1877 xinfo[i].crop_height = t[i].r.h; xinfo[i].crop_height_set = JCROP_POS; 1878 } else 1879 xinfo[i].crop_height = JCROP_UNSET; 1880 } 1881 if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1; 1882 } 1883 1884 jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE); 1885 jpeg_read_header(dinfo, TRUE); 1886 jpegSubsamp = getSubsamp(dinfo); 1887 if (jpegSubsamp < 0) 1888 _throw("tjTransform(): Could not determine subsampling type for JPEG image"); 1889 1890 for (i = 0; i < n; i++) { 1891 if (!jtransform_request_workspace(dinfo, &xinfo[i])) 1892 _throw("tjTransform(): Transform is not perfect"); 1893 1894 if (xinfo[i].crop) { 1895 if ((t[i].r.x % xinfo[i].iMCU_sample_width) != 0 || 1896 (t[i].r.y % xinfo[i].iMCU_sample_height) != 0) { 1897 snprintf(errStr, JMSG_LENGTH_MAX, 1898 "To crop this JPEG image, x must be a multiple of %d\n" 1899 "and y must be a multiple of %d.\n", 1900 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height); 1901 retval = -1; goto bailout; 1902 } 1903 } 1904 } 1905 1906 srccoefs = jpeg_read_coefficients(dinfo); 1907 1908 for (i = 0; i < n; i++) { 1909 int w, h, alloc = 1; 1910 1911 if (!xinfo[i].crop) { 1912 w = dinfo->image_width; h = dinfo->image_height; 1913 } else { 1914 w = xinfo[i].crop_width; h = xinfo[i].crop_height; 1915 } 1916 if (flags & TJFLAG_NOREALLOC) { 1917 alloc = 0; dstSizes[i] = tjBufSize(w, h, jpegSubsamp); 1918 } 1919 if (!(t[i].options & TJXOPT_NOOUTPUT)) 1920 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc); 1921 jpeg_copy_critical_parameters(dinfo, cinfo); 1922 dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]); 1923 if (flags & TJFLAG_PROGRESSIVE || t[i].options & TJXOPT_PROGRESSIVE) 1924 jpeg_simple_progression(cinfo); 1925 if (!(t[i].options & TJXOPT_NOOUTPUT)) { 1926 jpeg_write_coefficients(cinfo, dstcoefs); 1927 jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ? 1928 JCOPYOPT_NONE : JCOPYOPT_ALL); 1929 } else 1930 jinit_c_master_control(cinfo, TRUE); 1931 jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]); 1932 if (t[i].customFilter) { 1933 int ci, y; 1934 JDIMENSION by; 1935 1936 for (ci = 0; ci < cinfo->num_components; ci++) { 1937 jpeg_component_info *compptr = &cinfo->comp_info[ci]; 1938 tjregion arrayRegion = { 1939 0, 0, compptr->width_in_blocks * DCTSIZE, DCTSIZE 1940 }; 1941 tjregion planeRegion = { 1942 0, 0, compptr->width_in_blocks * DCTSIZE, 1943 compptr->height_in_blocks * DCTSIZE 1944 }; 1945 1946 for (by = 0; by < compptr->height_in_blocks; 1947 by += compptr->v_samp_factor) { 1948 JBLOCKARRAY barray = (dinfo->mem->access_virt_barray) 1949 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor, 1950 TRUE); 1951 1952 for (y = 0; y < compptr->v_samp_factor; y++) { 1953 if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci, 1954 i, &t[i]) == -1) 1955 _throw("tjTransform(): Error in custom filter"); 1956 arrayRegion.y += DCTSIZE; 1957 } 1958 } 1959 } 1960 } 1961 if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo); 1962 } 1963 1964 jpeg_finish_decompress(dinfo); 1965 1966 bailout: 1967 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo); 1968 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo); 1969 if (xinfo) free(xinfo); 1970 if (this->jerr.warning) retval = -1; 1971 this->jerr.stopOnWarning = FALSE; 1972 return retval; 1973 } 1974 1975 1976 DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width, 1977 int align, int *height, int *pixelFormat, 1978 int flags) 1979 { 1980 int retval = 0, tempc; 1981 size_t pitch; 1982 tjhandle handle = NULL; 1983 tjinstance *this; 1984 j_compress_ptr cinfo = NULL; 1985 cjpeg_source_ptr src; 1986 unsigned char *dstBuf = NULL; 1987 FILE *file = NULL; 1988 boolean invert; 1989 1990 if (!filename || !width || align < 1 || !height || !pixelFormat || 1991 *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF) 1992 _throwg("tjLoadImage(): Invalid argument"); 1993 if ((align & (align - 1)) != 0) 1994 _throwg("tjLoadImage(): Alignment must be a power of 2"); 1995 1996 if ((handle = tjInitCompress()) == NULL) return NULL; 1997 this = (tjinstance *)handle; 1998 cinfo = &this->cinfo; 1999 2000 if ((file = fopen(filename, "rb")) == NULL) 2001 _throwunix("tjLoadImage(): Cannot open input file"); 2002 2003 if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF) 2004 _throwunix("tjLoadImage(): Could not read input file") 2005 else if (tempc == EOF) 2006 _throwg("tjLoadImage(): Input file contains no data"); 2007 2008 if (setjmp(this->jerr.setjmp_buffer)) { 2009 /* If we get here, the JPEG code has signaled an error. */ 2010 retval = -1; goto bailout; 2011 } 2012 2013 if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN; 2014 else cinfo->in_color_space = pf2cs[*pixelFormat]; 2015 if (tempc == 'B') { 2016 if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL) 2017 _throwg("tjLoadImage(): Could not initialize bitmap loader"); 2018 invert = (flags & TJFLAG_BOTTOMUP) == 0; 2019 } else if (tempc == 'P') { 2020 if ((src = jinit_read_ppm(cinfo)) == NULL) 2021 _throwg("tjLoadImage(): Could not initialize bitmap loader"); 2022 invert = (flags & TJFLAG_BOTTOMUP) != 0; 2023 } else 2024 _throwg("tjLoadImage(): Unsupported file type"); 2025 2026 src->input_file = file; 2027 (*src->start_input) (cinfo, src); 2028 (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo); 2029 2030 *width = cinfo->image_width; *height = cinfo->image_height; 2031 *pixelFormat = cs2pf[cinfo->in_color_space]; 2032 2033 pitch = PAD((*width) * tjPixelSize[*pixelFormat], align); 2034 if ((unsigned long long)pitch * (unsigned long long)(*height) > 2035 (unsigned long long)((size_t)-1) || 2036 (dstBuf = (unsigned char *)malloc(pitch * (*height))) == NULL) 2037 _throwg("tjLoadImage(): Memory allocation failure"); 2038 2039 if (setjmp(this->jerr.setjmp_buffer)) { 2040 /* If we get here, the JPEG code has signaled an error. */ 2041 retval = -1; goto bailout; 2042 } 2043 2044 while (cinfo->next_scanline < cinfo->image_height) { 2045 int i, nlines = (*src->get_pixel_rows) (cinfo, src); 2046 2047 for (i = 0; i < nlines; i++) { 2048 unsigned char *dstptr; 2049 int row; 2050 2051 row = cinfo->next_scanline + i; 2052 if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch]; 2053 else dstptr = &dstBuf[row * pitch]; 2054 memcpy(dstptr, src->buffer[i], (*width) * tjPixelSize[*pixelFormat]); 2055 } 2056 cinfo->next_scanline += nlines; 2057 } 2058 2059 (*src->finish_input) (cinfo, src); 2060 2061 bailout: 2062 if (handle) tjDestroy(handle); 2063 if (file) fclose(file); 2064 if (retval < 0 && dstBuf) { free(dstBuf); dstBuf = NULL; } 2065 return dstBuf; 2066 } 2067 2068 2069 DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer, 2070 int width, int pitch, int height, int pixelFormat, 2071 int flags) 2072 { 2073 int retval = 0; 2074 tjhandle handle = NULL; 2075 tjinstance *this; 2076 j_decompress_ptr dinfo = NULL; 2077 djpeg_dest_ptr dst; 2078 FILE *file = NULL; 2079 char *ptr = NULL; 2080 boolean invert; 2081 2082 if (!filename || !buffer || width < 1 || pitch < 0 || height < 1 || 2083 pixelFormat < 0 || pixelFormat >= TJ_NUMPF) 2084 _throwg("tjSaveImage(): Invalid argument"); 2085 2086 if ((handle = tjInitDecompress()) == NULL) 2087 return -1; 2088 this = (tjinstance *)handle; 2089 dinfo = &this->dinfo; 2090 2091 if ((file = fopen(filename, "wb")) == NULL) 2092 _throwunix("tjSaveImage(): Cannot open output file"); 2093 2094 if (setjmp(this->jerr.setjmp_buffer)) { 2095 /* If we get here, the JPEG code has signaled an error. */ 2096 retval = -1; goto bailout; 2097 } 2098 2099 this->dinfo.out_color_space = pf2cs[pixelFormat]; 2100 dinfo->image_width = width; dinfo->image_height = height; 2101 dinfo->global_state = DSTATE_READY; 2102 dinfo->scale_num = dinfo->scale_denom = 1; 2103 2104 ptr = strrchr(filename, '.'); 2105 if (ptr && !strcasecmp(ptr, ".bmp")) { 2106 if ((dst = jinit_write_bmp(dinfo, FALSE, FALSE)) == NULL) 2107 _throwg("tjSaveImage(): Could not initialize bitmap writer"); 2108 invert = (flags & TJFLAG_BOTTOMUP) == 0; 2109 } else { 2110 if ((dst = jinit_write_ppm(dinfo)) == NULL) 2111 _throwg("tjSaveImage(): Could not initialize PPM writer"); 2112 invert = (flags & TJFLAG_BOTTOMUP) != 0; 2113 } 2114 2115 dst->output_file = file; 2116 (*dst->start_output) (dinfo, dst); 2117 (*dinfo->mem->realize_virt_arrays) ((j_common_ptr)dinfo); 2118 2119 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat]; 2120 2121 while (dinfo->output_scanline < dinfo->output_height) { 2122 unsigned char *rowptr; 2123 2124 if (invert) 2125 rowptr = &buffer[(height - dinfo->output_scanline - 1) * pitch]; 2126 else 2127 rowptr = &buffer[dinfo->output_scanline * pitch]; 2128 memcpy(dst->buffer[0], rowptr, width * tjPixelSize[pixelFormat]); 2129 (*dst->put_pixel_rows) (dinfo, dst, 1); 2130 dinfo->output_scanline++; 2131 } 2132 2133 (*dst->finish_output) (dinfo, dst); 2134 2135 bailout: 2136 if (handle) tjDestroy(handle); 2137 if (file) fclose(file); 2138 return retval; 2139 } 2140