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