Home | History | Annotate | Download | only in libjpeg-turbo
      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