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