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