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