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