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