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