blob: 9fc60cecd9605d87518a705d6a5d4a19cb782b07 [file] [log] [blame]
DRC9b28def2011-05-21 14:37:15 +00001/*
2 * Copyright (C)2009-2011 D. R. Commander. All Rights Reserved.
DRC2e7b76b2009-04-03 12:04:24 +00003 *
DRC9b28def2011-05-21 14:37:15 +00004 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
DRC2e7b76b2009-04-03 12:04:24 +00006 *
DRC9b28def2011-05-21 14:37:15 +00007 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of the libjpeg-turbo Project nor the names of its
13 * contributors may be used to endorse or promote products derived from this
14 * software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
DRC2e7b76b2009-04-03 12:04:24 +000027 */
28
DRC9b28def2011-05-21 14:37:15 +000029/* TurboJPEG/OSS: this implements the TurboJPEG API using libjpeg-turbo */
DRC2e7b76b2009-04-03 12:04:24 +000030
31#include <stdio.h>
32#include <stdlib.h>
DRC296c71b2011-05-25 04:12:52 +000033#include <jinclude.h>
DRCfbb67472010-11-24 04:02:37 +000034#define JPEG_INTERNALS
DRC2e7b76b2009-04-03 12:04:24 +000035#include <jpeglib.h>
36#include <jerror.h>
37#include <setjmp.h>
38#include "./turbojpeg.h"
DRCa29294a2011-05-24 09:17:57 +000039#include "./tjutil.h"
DRC890f1e02011-02-26 22:02:37 +000040#include "transupp.h"
DRC2a2e4512011-01-05 22:33:24 +000041
DRC9b28def2011-05-21 14:37:15 +000042extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
43 unsigned long *, boolean);
44extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
45
DRCfbb67472010-11-24 04:02:37 +000046#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
DRC2e7b76b2009-04-03 12:04:24 +000047
48
DRC9b28def2011-05-21 14:37:15 +000049/* Error handling (based on example in example.c) */
DRC2e7b76b2009-04-03 12:04:24 +000050
DRC9b28def2011-05-21 14:37:15 +000051static char errStr[JMSG_LENGTH_MAX]="No error";
DRC2e7b76b2009-04-03 12:04:24 +000052
DRC9b28def2011-05-21 14:37:15 +000053struct my_error_mgr
DRC2e7b76b2009-04-03 12:04:24 +000054{
55 struct jpeg_error_mgr pub;
DRC9b28def2011-05-21 14:37:15 +000056 jmp_buf setjmp_buffer;
57};
58typedef struct my_error_mgr *my_error_ptr;
DRC2e7b76b2009-04-03 12:04:24 +000059
60static void my_error_exit(j_common_ptr cinfo)
61{
DRC9b28def2011-05-21 14:37:15 +000062 my_error_ptr myerr=(my_error_ptr)cinfo->err;
DRC2e7b76b2009-04-03 12:04:24 +000063 (*cinfo->err->output_message)(cinfo);
DRC9b28def2011-05-21 14:37:15 +000064 longjmp(myerr->setjmp_buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +000065}
66
DRC9b28def2011-05-21 14:37:15 +000067/* Based on output_message() in jerror.c */
68
DRC2e7b76b2009-04-03 12:04:24 +000069static void my_output_message(j_common_ptr cinfo)
70{
DRC9b28def2011-05-21 14:37:15 +000071 (*cinfo->err->format_message)(cinfo, errStr);
DRC2e7b76b2009-04-03 12:04:24 +000072}
73
74
DRC9b28def2011-05-21 14:37:15 +000075/* Global structures, macros, etc. */
DRC2e7b76b2009-04-03 12:04:24 +000076
DRC9b28def2011-05-21 14:37:15 +000077enum {COMPRESS=1, DECOMPRESS=2};
78
79typedef struct _tjinstance
DRC2e7b76b2009-04-03 12:04:24 +000080{
81 struct jpeg_compress_struct cinfo;
82 struct jpeg_decompress_struct dinfo;
DRC9b28def2011-05-21 14:37:15 +000083 struct my_error_mgr jerr;
84 int init;
85} tjinstance;
DRC2e7b76b2009-04-03 12:04:24 +000086
DRC007a42c2011-05-22 13:55:56 +000087static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
DRC9b28def2011-05-21 14:37:15 +000088
DRC007a42c2011-05-22 13:55:56 +000089static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
90{
DRC890f1e02011-02-26 22:02:37 +000091 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
92 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
93};
DRC9b28def2011-05-21 14:37:15 +000094
DRC109a5782011-03-01 09:53:07 +000095#define NUMSF 4
96static const tjscalingfactor sf[NUMSF]={
97 {1, 1},
98 {1, 2},
99 {1, 4},
100 {1, 8}
101};
DRC2e7b76b2009-04-03 12:04:24 +0000102
DRCa29294a2011-05-24 09:17:57 +0000103#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
DRCda5220a2011-03-02 02:17:30 +0000104 retval=-1; goto bailout;}
DRC9b28def2011-05-21 14:37:15 +0000105#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
106 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
107 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
108 return -1;} \
109 cinfo=&this->cinfo; dinfo=&this->dinfo;
DRC2e7b76b2009-04-03 12:04:24 +0000110
DRC9b28def2011-05-21 14:37:15 +0000111static int getPixelFormat(int pixelSize, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000112{
DRC25b995a2011-05-21 15:34:54 +0000113 if(pixelSize==1) return TJPF_GRAY;
DRC9b28def2011-05-21 14:37:15 +0000114 if(pixelSize==3)
115 {
DRC25b995a2011-05-21 15:34:54 +0000116 if(flags&TJ_BGR) return TJPF_BGR;
117 else return TJPF_RGB;
DRC9b28def2011-05-21 14:37:15 +0000118 }
119 if(pixelSize==4)
120 {
121 if(flags&TJ_ALPHAFIRST)
122 {
DRC25b995a2011-05-21 15:34:54 +0000123 if(flags&TJ_BGR) return TJPF_XBGR;
124 else return TJPF_XRGB;
DRC9b28def2011-05-21 14:37:15 +0000125 }
126 else
127 {
DRC25b995a2011-05-21 15:34:54 +0000128 if(flags&TJ_BGR) return TJPF_BGRX;
129 else return TJPF_RGBX;
DRC9b28def2011-05-21 14:37:15 +0000130 }
131 }
132 return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000133}
134
DRCf12bb302011-09-07 05:03:18 +0000135static int setCompDefaults(struct jpeg_compress_struct *cinfo,
DRC9b28def2011-05-21 14:37:15 +0000136 int pixelFormat, int subsamp, int jpegQual)
DRC2e7b76b2009-04-03 12:04:24 +0000137{
DRCf12bb302011-09-07 05:03:18 +0000138 int retval=0;
139
DRC9b28def2011-05-21 14:37:15 +0000140 switch(pixelFormat)
141 {
DRC25b995a2011-05-21 15:34:54 +0000142 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000143 cinfo->in_color_space=JCS_GRAYSCALE; break;
144 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000145 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000146 cinfo->in_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000147 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000148 cinfo->in_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000149 case TJPF_RGBX:
DRC9b28def2011-05-21 14:37:15 +0000150 cinfo->in_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000151 case TJPF_BGRX:
DRC9b28def2011-05-21 14:37:15 +0000152 cinfo->in_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000153 case TJPF_XRGB:
DRC9b28def2011-05-21 14:37:15 +0000154 cinfo->in_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000155 case TJPF_XBGR:
DRC9b28def2011-05-21 14:37:15 +0000156 cinfo->in_color_space=JCS_EXT_XBGR; break;
157 #else
DRC25b995a2011-05-21 15:34:54 +0000158 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000159 if(RGB_RED==0 && RGB_GREEN==1 && RGB_BLUE==2 && RGB_PIXELSIZE==3)
160 {
161 cinfo->in_color_space=JCS_RGB; break;
162 }
163 default:
164 _throw("Unsupported pixel format");
165 #endif
DRCefa4ddc2010-10-13 19:22:50 +0000166 }
DRC2e7b76b2009-04-03 12:04:24 +0000167
DRC9b28def2011-05-21 14:37:15 +0000168 cinfo->input_components=tjPixelSize[pixelFormat];
169 jpeg_set_defaults(cinfo);
170 if(jpegQual>=0)
171 {
172 jpeg_set_quality(cinfo, jpegQual, TRUE);
173 if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW;
174 else cinfo->dct_method=JDCT_FASTEST;
175 }
DRC25b995a2011-05-21 15:34:54 +0000176 if(subsamp==TJSAMP_GRAY)
DRC9b28def2011-05-21 14:37:15 +0000177 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
178 else
179 jpeg_set_colorspace(cinfo, JCS_YCbCr);
DRC2e7b76b2009-04-03 12:04:24 +0000180
DRC9b28def2011-05-21 14:37:15 +0000181 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
182 cinfo->comp_info[1].h_samp_factor=1;
183 cinfo->comp_info[2].h_samp_factor=1;
184 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
185 cinfo->comp_info[1].v_samp_factor=1;
186 cinfo->comp_info[2].v_samp_factor=1;
DRCf12bb302011-09-07 05:03:18 +0000187
188 #if JCS_EXTENSIONS!=1
189 bailout:
190 #endif
191 return retval;
DRC9b28def2011-05-21 14:37:15 +0000192}
193
DRCf12bb302011-09-07 05:03:18 +0000194static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
DRC9b28def2011-05-21 14:37:15 +0000195 int pixelFormat)
196{
DRCf12bb302011-09-07 05:03:18 +0000197 int retval=0;
198
DRC9b28def2011-05-21 14:37:15 +0000199 switch(pixelFormat)
200 {
DRC25b995a2011-05-21 15:34:54 +0000201 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000202 dinfo->out_color_space=JCS_GRAYSCALE; break;
203 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000204 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000205 dinfo->out_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000206 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000207 dinfo->out_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000208 case TJPF_RGBX:
DRC9b28def2011-05-21 14:37:15 +0000209 dinfo->out_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000210 case TJPF_BGRX:
DRC9b28def2011-05-21 14:37:15 +0000211 dinfo->out_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000212 case TJPF_XRGB:
DRC9b28def2011-05-21 14:37:15 +0000213 dinfo->out_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000214 case TJPF_XBGR:
DRC9b28def2011-05-21 14:37:15 +0000215 dinfo->out_color_space=JCS_EXT_XBGR; break;
216 #else
DRC25b995a2011-05-21 15:34:54 +0000217 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000218 if(RGB_RED==0 && RGB_GREEN==1 && RGB_BLUE==2 && RGB_PIXELSIZE==3)
219 {
220 dinfo->out_color_space=JCS_RGB; break;
221 }
222 default:
223 _throw("Unsupported pixel format");
224 #endif
225 }
DRCf12bb302011-09-07 05:03:18 +0000226
227 #if JCS_EXTENSIONS!=1
228 bailout:
229 #endif
230 return retval;
DRC9b28def2011-05-21 14:37:15 +0000231}
232
233
DRC9b49f0e2011-07-12 03:17:23 +0000234static int getSubsamp(j_decompress_ptr dinfo)
235{
236 int retval=-1, i, k;
237 for(i=0; i<NUMSUBOPT; i++)
238 {
239 if(dinfo->num_components==pixelsize[i])
240 {
241 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
242 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
243 {
244 int match=0;
245 for(k=1; k<dinfo->num_components; k++)
246 {
247 if(dinfo->comp_info[k].h_samp_factor==1
248 && dinfo->comp_info[k].v_samp_factor==1)
249 match++;
250 }
251 if(match==dinfo->num_components-1)
252 {
253 retval=i; break;
254 }
255 }
256 }
257 }
258 return retval;
259}
260
261
DRC9b28def2011-05-21 14:37:15 +0000262/* General API functions */
263
264DLLEXPORT char* DLLCALL tjGetErrorStr(void)
265{
266 return errStr;
267}
268
269
270DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
271{
272 getinstance(handle);
273 if(setjmp(this->jerr.setjmp_buffer)) return -1;
274 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
275 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
276 free(this);
277 return 0;
278}
279
280
DRC6b76f752011-05-24 16:52:47 +0000281/* These are exposed mainly because Windows can't malloc() and free() across
282 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
283 with turbojpeg.dll for compatibility reasons. However, these functions
284 can potentially be used for other purposes by different implementations. */
285
286DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
287{
288 if(buf) free(buf);
289}
290
291
292DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
293{
294 return (unsigned char *)malloc(bytes);
295}
296
297
DRC9b28def2011-05-21 14:37:15 +0000298/* Compressor */
299
300static tjhandle _tjInitCompress(tjinstance *this)
301{
302 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
303
304 /* This is also straight out of example.c */
305 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
306 this->jerr.pub.error_exit=my_error_exit;
307 this->jerr.pub.output_message=my_output_message;
308
309 if(setjmp(this->jerr.setjmp_buffer))
310 {
311 /* If we get here, the JPEG code has signaled an error. */
312 if(this) free(this); return NULL;
313 }
314
315 jpeg_create_compress(&this->cinfo);
316 /* Make an initial call so it will create the destination manager */
317 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
318
DRC007a42c2011-05-22 13:55:56 +0000319 this->init|=COMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000320 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000321}
322
DRC890f1e02011-02-26 22:02:37 +0000323DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
324{
DRC9b28def2011-05-21 14:37:15 +0000325 tjinstance *this=NULL;
326 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000327 {
DRC007a42c2011-05-22 13:55:56 +0000328 snprintf(errStr, JMSG_LENGTH_MAX,
329 "tjInitCompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000330 return NULL;
331 }
DRC007a42c2011-05-22 13:55:56 +0000332 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000333 return _tjInitCompress(this);
DRC890f1e02011-02-26 22:02:37 +0000334}
335
DRC84241602011-02-25 02:08:23 +0000336
DRC9b49f0e2011-07-12 03:17:23 +0000337DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
338 int jpegSubsamp)
339{
340 unsigned long retval=0; int mcuw, mcuh, chromasf;
341 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
342 _throw("tjBufSize(): Invalid argument");
343
344 // This allows for rare corner cases in which a JPEG image can actually be
345 // larger than the uncompressed input (we wouldn't mention it if it hadn't
346 // happened before.)
347 mcuw=tjMCUWidth[jpegSubsamp];
348 mcuh=tjMCUHeight[jpegSubsamp];
349 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
350 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
351
352 bailout:
353 return retval;
354}
355
356
DRC2e7b76b2009-04-03 12:04:24 +0000357DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
358{
DRCf3cf9732011-02-22 00:16:14 +0000359 unsigned long retval=0;
360 if(width<1 || height<1)
DRC007a42c2011-05-22 13:55:56 +0000361 _throw("TJBUFSIZE(): Invalid argument");
DRCf3cf9732011-02-22 00:16:14 +0000362
363 // This allows for rare corner cases in which a JPEG image can actually be
364 // larger than the uncompressed input (we wouldn't mention it if it hadn't
DRCb28fc572011-02-22 06:41:29 +0000365 // happened before.)
DRC007a42c2011-05-22 13:55:56 +0000366 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
DRCf3cf9732011-02-22 00:16:14 +0000367
368 bailout:
369 return retval;
370}
371
DRC84241602011-02-25 02:08:23 +0000372
DRC9b49f0e2011-07-12 03:17:23 +0000373DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
DRCf3cf9732011-02-22 00:16:14 +0000374 int subsamp)
375{
376 unsigned long retval=0;
377 int pw, ph, cw, ch;
378 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
DRC9b49f0e2011-07-12 03:17:23 +0000379 _throw("tjBufSizeYUV(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000380 pw=PAD(width, tjMCUWidth[subsamp]/8);
381 ph=PAD(height, tjMCUHeight[subsamp]/8);
382 cw=pw*8/tjMCUWidth[subsamp]; ch=ph*8/tjMCUHeight[subsamp];
DRC25b995a2011-05-21 15:34:54 +0000383 retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2);
DRCf3cf9732011-02-22 00:16:14 +0000384
385 bailout:
386 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000387}
388
DRC84241602011-02-25 02:08:23 +0000389
DRC9b49f0e2011-07-12 03:17:23 +0000390DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
391 int subsamp)
392{
393 return tjBufSizeYUV(width, height, subsamp);
394}
395
396
DRC9b28def2011-05-21 14:37:15 +0000397DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
398 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
399 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
400{
DRCff78e372011-05-24 10:17:32 +0000401 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
DRC9b28def2011-05-21 14:37:15 +0000402
403 getinstance(handle)
404 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000405 _throw("tjCompress2(): Instance has not been initialized for compression");
DRC9b28def2011-05-21 14:37:15 +0000406
407 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
408 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
409 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
DRC007a42c2011-05-22 13:55:56 +0000410 _throw("tjCompress2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000411
412 if(setjmp(this->jerr.setjmp_buffer))
413 {
414 /* If we get here, the JPEG code has signaled an error. */
415 retval=-1;
416 goto bailout;
417 }
418
419 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
420
421 cinfo->image_width=width;
422 cinfo->image_height=height;
423
DRC25b995a2011-05-21 15:34:54 +0000424 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
425 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
426 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000427
DRCff78e372011-05-24 10:17:32 +0000428 if(flags&TJFLAG_NOREALLOC)
429 {
DRC9b49f0e2011-07-12 03:17:23 +0000430 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +0000431 }
432 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
DRCf12bb302011-09-07 05:03:18 +0000433 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1)
434 return -1;
DRC9b28def2011-05-21 14:37:15 +0000435
436 jpeg_start_compress(cinfo, TRUE);
437 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000438 _throw("tjCompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000439 for(i=0; i<height; i++)
440 {
DRC25b995a2011-05-21 15:34:54 +0000441 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000442 else row_pointer[i]=&srcBuf[i*pitch];
443 }
444 while(cinfo->next_scanline<cinfo->image_height)
445 {
446 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
447 cinfo->image_height-cinfo->next_scanline);
448 }
449 jpeg_finish_compress(cinfo);
450
451 bailout:
452 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
453 if(row_pointer) free(row_pointer);
454 return retval;
455}
456
457DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
458 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
459 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
460{
461 int retval=0; unsigned long size;
462 if(flags&TJ_YUV)
463 {
DRC9b49f0e2011-07-12 03:17:23 +0000464 size=tjBufSizeYUV(width, height, jpegSubsamp);
DRC9b28def2011-05-21 14:37:15 +0000465 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
466 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
467 }
468 else
469 {
DRC9b28def2011-05-21 14:37:15 +0000470 retval=tjCompress2(handle, srcBuf, width, pitch, height,
471 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
DRC25b995a2011-05-21 15:34:54 +0000472 flags|TJFLAG_NOREALLOC);
DRC9b28def2011-05-21 14:37:15 +0000473 }
474 *jpegSize=size;
475 return retval;
476}
477
478
479DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
480 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
481 int subsamp, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000482{
DRC91e86ba2011-02-15 05:24:08 +0000483 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000484 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
485 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
486 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC9b28def2011-05-21 14:37:15 +0000487 int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
488 JSAMPLE *ptr=dstBuf;
489 unsigned long yuvsize=0;
490 jpeg_component_info *compptr;
DRC2e7b76b2009-04-03 12:04:24 +0000491
DRC9b28def2011-05-21 14:37:15 +0000492 getinstance(handle);
493 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000494 _throw("tjEncodeYUV2(): Instance has not been initialized for compression");
DRC2e7b76b2009-04-03 12:04:24 +0000495
DRCfbb67472010-11-24 04:02:37 +0000496 for(i=0; i<MAX_COMPONENTS; i++)
497 {
498 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
499 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
500 }
501
DRC9b28def2011-05-21 14:37:15 +0000502 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
503 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
504 || subsamp>=NUMSUBOPT)
505 _throw("tjEncodeYUV2(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000506
DRC9b28def2011-05-21 14:37:15 +0000507 if(setjmp(this->jerr.setjmp_buffer))
508 {
509 /* If we get here, the JPEG code has signaled an error. */
510 retval=-1;
511 goto bailout;
512 }
DRC2e7b76b2009-04-03 12:04:24 +0000513
DRC9b28def2011-05-21 14:37:15 +0000514 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC2e7b76b2009-04-03 12:04:24 +0000515
DRC9b28def2011-05-21 14:37:15 +0000516 cinfo->image_width=width;
517 cinfo->image_height=height;
DRC2e7b76b2009-04-03 12:04:24 +0000518
DRC25b995a2011-05-21 15:34:54 +0000519 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
520 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
521 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000522
DRC9b49f0e2011-07-12 03:17:23 +0000523 yuvsize=tjBufSizeYUV(width, height, subsamp);
DRC9b28def2011-05-21 14:37:15 +0000524 jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0);
DRCf12bb302011-09-07 05:03:18 +0000525 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1)==-1) return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000526
DRC9b28def2011-05-21 14:37:15 +0000527 jpeg_start_compress(cinfo, TRUE);
528 pw=PAD(width, cinfo->max_h_samp_factor);
529 ph=PAD(height, cinfo->max_v_samp_factor);
DRC2e7b76b2009-04-03 12:04:24 +0000530
DRC9b28def2011-05-21 14:37:15 +0000531 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000532 _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000533 for(i=0; i<height; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000534 {
DRC25b995a2011-05-21 15:34:54 +0000535 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000536 else row_pointer[i]=&srcBuf[i*pitch];
537 }
538 if(height<ph)
539 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
DRCfbb67472010-11-24 04:02:37 +0000540
DRC9b28def2011-05-21 14:37:15 +0000541 for(i=0; i<cinfo->num_components; i++)
542 {
543 compptr=&cinfo->comp_info[i];
544 _tmpbuf[i]=(JSAMPLE *)malloc(
545 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
546 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRC007a42c2011-05-22 13:55:56 +0000547 if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000548 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRC007a42c2011-05-22 13:55:56 +0000549 if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000550 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRCfbb67472010-11-24 04:02:37 +0000551 {
DRC9b28def2011-05-21 14:37:15 +0000552 unsigned char *_tmpbuf_aligned=
553 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
554 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000555 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC9b28def2011-05-21 14:37:15 +0000556 /compptr->h_samp_factor, 16) * row];
DRCfbb67472010-11-24 04:02:37 +0000557 }
DRC9b28def2011-05-21 14:37:15 +0000558 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
559 * compptr->v_samp_factor + 16);
DRC007a42c2011-05-22 13:55:56 +0000560 if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000561 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRC007a42c2011-05-22 13:55:56 +0000562 if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000563 for(row=0; row<compptr->v_samp_factor; row++)
564 {
565 unsigned char *_tmpbuf2_aligned=
566 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
567 tmpbuf2[i][row]=&_tmpbuf2_aligned[
568 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
569 }
570 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
571 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
572 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
DRC007a42c2011-05-22 13:55:56 +0000573 if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000574 for(row=0; row<ch[i]; row++)
575 {
576 outbuf[i][row]=ptr;
577 ptr+=PAD(cw[i], 4);
578 }
579 }
580 if(yuvsize!=(unsigned long)(ptr-dstBuf))
581 _throw("tjEncodeYUV2(): Generated image is not the correct size");
DRCfbb67472010-11-24 04:02:37 +0000582
DRC9b28def2011-05-21 14:37:15 +0000583 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
DRCfbb67472010-11-24 04:02:37 +0000584 {
DRC9b28def2011-05-21 14:37:15 +0000585 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
586 cinfo->max_v_samp_factor);
587 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
588 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
589 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
590 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
591 compptr->v_samp_factor, cw[i]);
DRC6ee54592011-03-01 08:18:30 +0000592 }
DRC9b28def2011-05-21 14:37:15 +0000593 cinfo->next_scanline+=height;
594 jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000595
DRC91e86ba2011-02-15 05:24:08 +0000596 bailout:
DRC9b28def2011-05-21 14:37:15 +0000597 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000598 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000599 for(i=0; i<MAX_COMPONENTS; i++)
600 {
601 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000602 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000603 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000604 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000605 if(outbuf[i]!=NULL) free(outbuf[i]);
606 }
DRC91e86ba2011-02-15 05:24:08 +0000607 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000608}
609
DRC9b28def2011-05-21 14:37:15 +0000610DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
611 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
612 int subsamp, int flags)
DRC84241602011-02-25 02:08:23 +0000613{
DRC9b28def2011-05-21 14:37:15 +0000614 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
615 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
DRC84241602011-02-25 02:08:23 +0000616}
617
618
DRC9b28def2011-05-21 14:37:15 +0000619/* Decompressor */
DRC2e7b76b2009-04-03 12:04:24 +0000620
DRC9b28def2011-05-21 14:37:15 +0000621static tjhandle _tjInitDecompress(tjinstance *this)
DRC2e7b76b2009-04-03 12:04:24 +0000622{
DRC9b28def2011-05-21 14:37:15 +0000623 unsigned char buffer[1];
DRC2e7b76b2009-04-03 12:04:24 +0000624
DRC9b28def2011-05-21 14:37:15 +0000625 /* This is also straight out of example.c */
626 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
627 this->jerr.pub.error_exit=my_error_exit;
628 this->jerr.pub.output_message=my_output_message;
DRC2e7b76b2009-04-03 12:04:24 +0000629
DRC9b28def2011-05-21 14:37:15 +0000630 if(setjmp(this->jerr.setjmp_buffer))
631 {
632 /* If we get here, the JPEG code has signaled an error. */
633 if(this) free(this); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +0000634 }
DRC2e7b76b2009-04-03 12:04:24 +0000635
DRC9b28def2011-05-21 14:37:15 +0000636 jpeg_create_decompress(&this->dinfo);
637 /* Make an initial call so it will create the source manager */
638 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +0000639
DRC007a42c2011-05-22 13:55:56 +0000640 this->init|=DECOMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000641 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000642}
643
DRC890f1e02011-02-26 22:02:37 +0000644DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
645{
DRC9b28def2011-05-21 14:37:15 +0000646 tjinstance *this;
647 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000648 {
DRC007a42c2011-05-22 13:55:56 +0000649 snprintf(errStr, JMSG_LENGTH_MAX,
650 "tjInitDecompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000651 return NULL;
652 }
DRC007a42c2011-05-22 13:55:56 +0000653 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000654 return _tjInitDecompress(this);
DRC890f1e02011-02-26 22:02:37 +0000655}
656
DRC2e7b76b2009-04-03 12:04:24 +0000657
DRC9b28def2011-05-21 14:37:15 +0000658DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
659 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
660 int *jpegSubsamp)
DRC1fe80f82010-12-14 01:21:29 +0000661{
DRC9b49f0e2011-07-12 03:17:23 +0000662 int retval=0;
DRC1fe80f82010-12-14 01:21:29 +0000663
DRC9b28def2011-05-21 14:37:15 +0000664 getinstance(handle);
665 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000666 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
DRC1fe80f82010-12-14 01:21:29 +0000667
DRC9b28def2011-05-21 14:37:15 +0000668 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
669 || jpegSubsamp==NULL)
670 _throw("tjDecompressHeader2(): Invalid argument");
DRC1fe80f82010-12-14 01:21:29 +0000671
DRC9b28def2011-05-21 14:37:15 +0000672 if(setjmp(this->jerr.setjmp_buffer))
673 {
674 /* If we get here, the JPEG code has signaled an error. */
DRC1fe80f82010-12-14 01:21:29 +0000675 return -1;
676 }
677
DRC9b28def2011-05-21 14:37:15 +0000678 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
679 jpeg_read_header(dinfo, TRUE);
DRC1fe80f82010-12-14 01:21:29 +0000680
DRC9b28def2011-05-21 14:37:15 +0000681 *width=dinfo->image_width;
682 *height=dinfo->image_height;
DRC9b49f0e2011-07-12 03:17:23 +0000683 *jpegSubsamp=getSubsamp(dinfo);
DRC1fe80f82010-12-14 01:21:29 +0000684
DRC9b28def2011-05-21 14:37:15 +0000685 jpeg_abort_decompress(dinfo);
DRC1fe80f82010-12-14 01:21:29 +0000686
DRC9b28def2011-05-21 14:37:15 +0000687 if(*jpegSubsamp<0)
DRC007a42c2011-05-22 13:55:56 +0000688 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
689 if(*width<1 || *height<1)
690 _throw("tjDecompressHeader2(): Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +0000691
692 bailout:
693 return retval;
694}
695
DRC9b28def2011-05-21 14:37:15 +0000696DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
697 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
DRC91e86ba2011-02-15 05:24:08 +0000698{
DRC9b28def2011-05-21 14:37:15 +0000699 int jpegSubsamp;
700 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
701 &jpegSubsamp);
DRC1fe80f82010-12-14 01:21:29 +0000702}
703
704
DRC109a5782011-03-01 09:53:07 +0000705DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +0000706{
DRC109a5782011-03-01 09:53:07 +0000707 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +0000708 {
DRC9b28def2011-05-21 14:37:15 +0000709 snprintf(errStr, JMSG_LENGTH_MAX,
DRC007a42c2011-05-22 13:55:56 +0000710 "tjGetScalingFactors(): Invalid argument");
DRC109a5782011-03-01 09:53:07 +0000711 return NULL;
DRCb28fc572011-02-22 06:41:29 +0000712 }
713
DRC109a5782011-03-01 09:53:07 +0000714 *numscalingfactors=NUMSF;
715 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +0000716}
717
718
DRC9b28def2011-05-21 14:37:15 +0000719DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
720 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
721 int height, int pixelFormat, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000722{
DRC9b28def2011-05-21 14:37:15 +0000723 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRC109a5782011-03-01 09:53:07 +0000724 int jpegwidth, jpegheight, scaledw, scaledh;
DRC2e7b76b2009-04-03 12:04:24 +0000725
DRC9b28def2011-05-21 14:37:15 +0000726 getinstance(handle);
727 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000728 _throw("tjDecompress2(): Instance has not been initialized for decompression");
DRC9b28def2011-05-21 14:37:15 +0000729
730 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
731 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
732 _throw("tjDecompress2(): Invalid argument");
733
DRC25b995a2011-05-21 15:34:54 +0000734 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
735 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
736 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000737
738 if(setjmp(this->jerr.setjmp_buffer))
739 {
740 /* If we get here, the JPEG code has signaled an error. */
741 retval=-1;
742 goto bailout;
743 }
744
745 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
746 jpeg_read_header(dinfo, TRUE);
DRCf12bb302011-09-07 05:03:18 +0000747 if(setDecompDefaults(dinfo, pixelFormat)==-1) return -1;
DRC9b28def2011-05-21 14:37:15 +0000748
DRC25b995a2011-05-21 15:34:54 +0000749 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +0000750
751 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
752 if(width==0) width=jpegwidth;
753 if(height==0) height=jpegheight;
754 for(i=0; i<NUMSF; i++)
755 {
756 scaledw=TJSCALED(jpegwidth, sf[i]);
757 scaledh=TJSCALED(jpegheight, sf[i]);
758 if(scaledw<=width && scaledh<=height)
759 break;
760 }
761 if(scaledw>width || scaledh>height)
DRC007a42c2011-05-22 13:55:56 +0000762 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
DRC9b28def2011-05-21 14:37:15 +0000763 width=scaledw; height=scaledh;
764 dinfo->scale_num=sf[i].num;
765 dinfo->scale_denom=sf[i].denom;
766
767 jpeg_start_decompress(dinfo);
768 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
769 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
770 *dinfo->output_height))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000771 _throw("tjDecompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000772 for(i=0; i<(int)dinfo->output_height; i++)
773 {
DRC25b995a2011-05-21 15:34:54 +0000774 if(flags&TJFLAG_BOTTOMUP)
DRC9b28def2011-05-21 14:37:15 +0000775 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
776 else row_pointer[i]=&dstBuf[i*pitch];
777 }
778 while(dinfo->output_scanline<dinfo->output_height)
779 {
780 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
781 dinfo->output_height-dinfo->output_scanline);
782 }
783 jpeg_finish_decompress(dinfo);
784
785 bailout:
786 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
787 if(row_pointer) free(row_pointer);
788 return retval;
789}
790
791DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
792 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
793 int height, int pixelSize, int flags)
794{
795 if(flags&TJ_YUV)
796 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
797 else
798 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
799 height, getPixelFormat(pixelSize, flags), flags);
800}
801
802
803DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
804 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
805 int flags)
806{
807 int i, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
808 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
809 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
810 JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS];
811
812 getinstance(handle);
813 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000814 _throw("tjDecompressToYUV(): Instance has not been initialized for decompression");
DRC2e7b76b2009-04-03 12:04:24 +0000815
DRCf9cf5c72010-12-10 10:58:49 +0000816 for(i=0; i<MAX_COMPONENTS; i++)
817 {
818 tmpbuf[i]=NULL; outbuf[i]=NULL;
819 }
DRC9e17f7d2010-12-10 04:59:13 +0000820
DRC9b28def2011-05-21 14:37:15 +0000821 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
822 _throw("tjDecompressToYUV(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000823
DRC25b995a2011-05-21 15:34:54 +0000824 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
825 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
826 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000827
DRC9b28def2011-05-21 14:37:15 +0000828 if(setjmp(this->jerr.setjmp_buffer))
829 {
830 /* If we get here, the JPEG code has signaled an error. */
DRC91e86ba2011-02-15 05:24:08 +0000831 retval=-1;
832 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +0000833 }
DRC2e7b76b2009-04-03 12:04:24 +0000834
DRC9b28def2011-05-21 14:37:15 +0000835 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
836 jpeg_read_header(dinfo, TRUE);
DRC2e7b76b2009-04-03 12:04:24 +0000837
DRC9b28def2011-05-21 14:37:15 +0000838 for(i=0; i<dinfo->num_components; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000839 {
DRC9b28def2011-05-21 14:37:15 +0000840 jpeg_component_info *compptr=&dinfo->comp_info[i];
841 int ih;
842 iw[i]=compptr->width_in_blocks*DCTSIZE;
843 ih=compptr->height_in_blocks*DCTSIZE;
844 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
845 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
846 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
847 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
848 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
849 th[i]=compptr->v_samp_factor*DCTSIZE;
850 tmpbufsize+=iw[i]*th[i];
851 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000852 _throw("tjDecompressToYUV(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000853 for(row=0; row<ch[i]; row++)
854 {
855 outbuf[i][row]=ptr;
856 ptr+=PAD(cw[i], 4);
857 }
858 }
859 if(usetmpbuf)
860 {
861 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000862 _throw("tjDecompressToYUV(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000863 ptr=_tmpbuf;
864 for(i=0; i<dinfo->num_components; i++)
865 {
866 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000867 _throw("tjDecompressToYUV(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000868 for(row=0; row<th[i]; row++)
869 {
870 tmpbuf[i][row]=ptr;
871 ptr+=iw[i];
872 }
873 }
874 }
DRC9e17f7d2010-12-10 04:59:13 +0000875
DRC25b995a2011-05-21 15:34:54 +0000876 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +0000877 dinfo->raw_data_out=TRUE;
878
879 jpeg_start_decompress(dinfo);
880 for(row=0; row<(int)dinfo->output_height;
881 row+=dinfo->max_v_samp_factor*DCTSIZE)
882 {
883 JSAMPARRAY yuvptr[MAX_COMPONENTS];
884 int crow[MAX_COMPONENTS];
DRC9e17f7d2010-12-10 04:59:13 +0000885 for(i=0; i<dinfo->num_components; i++)
886 {
887 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRC9b28def2011-05-21 14:37:15 +0000888 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
889 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
890 else yuvptr[i]=&outbuf[i][crow[i]];
DRCf9cf5c72010-12-10 10:58:49 +0000891 }
DRC9b28def2011-05-21 14:37:15 +0000892 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
DRCf9cf5c72010-12-10 10:58:49 +0000893 if(usetmpbuf)
894 {
DRC9b28def2011-05-21 14:37:15 +0000895 int j;
DRCf9cf5c72010-12-10 10:58:49 +0000896 for(i=0; i<dinfo->num_components; i++)
897 {
DRC9b28def2011-05-21 14:37:15 +0000898 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +0000899 {
DRC9b28def2011-05-21 14:37:15 +0000900 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000901 }
DRC9e17f7d2010-12-10 04:59:13 +0000902 }
903 }
904 }
DRC9b28def2011-05-21 14:37:15 +0000905 jpeg_finish_decompress(dinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000906
DRC91e86ba2011-02-15 05:24:08 +0000907 bailout:
DRC9b28def2011-05-21 14:37:15 +0000908 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC9e17f7d2010-12-10 04:59:13 +0000909 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +0000910 {
911 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +0000912 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000913 }
914 if(_tmpbuf) free(_tmpbuf);
DRC91e86ba2011-02-15 05:24:08 +0000915 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000916}
917
918
DRC9b28def2011-05-21 14:37:15 +0000919/* Transformer */
DRC890f1e02011-02-26 22:02:37 +0000920
921DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
922{
DRC9b28def2011-05-21 14:37:15 +0000923 tjinstance *this=NULL; tjhandle handle=NULL;
924 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000925 {
DRC007a42c2011-05-22 13:55:56 +0000926 snprintf(errStr, JMSG_LENGTH_MAX,
927 "tjInitTransform(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000928 return NULL;
929 }
DRC007a42c2011-05-22 13:55:56 +0000930 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000931 handle=_tjInitCompress(this);
932 if(!handle) return NULL;
933 handle=_tjInitDecompress(this);
934 return handle;
DRC890f1e02011-02-26 22:02:37 +0000935}
936
937
DRC9b28def2011-05-21 14:37:15 +0000938DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
939 unsigned long jpegSize, int n, unsigned char **dstBufs,
940 unsigned long *dstSizes, tjtransform *t, int flags)
DRC890f1e02011-02-26 22:02:37 +0000941{
DRC0a325192011-03-02 09:22:41 +0000942 jpeg_transform_info *xinfo=NULL;
DRC890f1e02011-02-26 22:02:37 +0000943 jvirt_barray_ptr *srccoefs, *dstcoefs;
DRC9b49f0e2011-07-12 03:17:23 +0000944 int retval=0, i, jpegSubsamp;
DRC890f1e02011-02-26 22:02:37 +0000945
DRC9b28def2011-05-21 14:37:15 +0000946 getinstance(handle);
947 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000948 _throw("tjTransform(): Instance has not been initialized for transformation");
DRC890f1e02011-02-26 22:02:37 +0000949
DRC9b28def2011-05-21 14:37:15 +0000950 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
951 || t==NULL || flags<0)
952 _throw("tjTransform(): Invalid argument");
953
DRC25b995a2011-05-21 15:34:54 +0000954 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
955 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
956 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC890f1e02011-02-26 22:02:37 +0000957
DRC9b28def2011-05-21 14:37:15 +0000958 if(setjmp(this->jerr.setjmp_buffer))
959 {
960 /* If we get here, the JPEG code has signaled an error. */
DRC890f1e02011-02-26 22:02:37 +0000961 retval=-1;
962 goto bailout;
963 }
964
DRC9b28def2011-05-21 14:37:15 +0000965 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
DRC890f1e02011-02-26 22:02:37 +0000966
DRC0a325192011-03-02 09:22:41 +0000967 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
968 ==NULL)
DRC007a42c2011-05-22 13:55:56 +0000969 _throw("tjTransform(): Memory allocation failure");
970 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
DRC890f1e02011-02-26 22:02:37 +0000971
DRC0a325192011-03-02 09:22:41 +0000972 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +0000973 {
DRC0a325192011-03-02 09:22:41 +0000974 xinfo[i].transform=xformtypes[t[i].op];
DRC25b995a2011-05-21 15:34:54 +0000975 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
976 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
977 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
978 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
979 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
DRCba5ea512011-03-04 03:20:34 +0000980 else xinfo[i].slow_hflip=0;
DRC0a325192011-03-02 09:22:41 +0000981
982 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +0000983 {
DRC0a325192011-03-02 09:22:41 +0000984 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
985 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
986 if(t[i].r.w!=0)
987 {
988 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
989 }
DRCd932e582011-03-15 20:09:47 +0000990 else xinfo[i].crop_width=JCROP_UNSET;
DRC0a325192011-03-02 09:22:41 +0000991 if(t[i].r.h!=0)
992 {
993 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
994 }
DRCd932e582011-03-15 20:09:47 +0000995 else xinfo[i].crop_height=JCROP_UNSET;
DRC890f1e02011-02-26 22:02:37 +0000996 }
997 }
998
DRC9b28def2011-05-21 14:37:15 +0000999 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1000 jpeg_read_header(dinfo, TRUE);
DRC9b49f0e2011-07-12 03:17:23 +00001001 jpegSubsamp=getSubsamp(dinfo);
1002 if(jpegSubsamp<0)
1003 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC890f1e02011-02-26 22:02:37 +00001004
DRC0a325192011-03-02 09:22:41 +00001005 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001006 {
DRC9b28def2011-05-21 14:37:15 +00001007 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
DRC007a42c2011-05-22 13:55:56 +00001008 _throw("tjTransform(): Transform is not perfect");
DRC890f1e02011-02-26 22:02:37 +00001009
DRC0a325192011-03-02 09:22:41 +00001010 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001011 {
DRC0a325192011-03-02 09:22:41 +00001012 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1013 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1014 {
DRC9b28def2011-05-21 14:37:15 +00001015 snprintf(errStr, JMSG_LENGTH_MAX,
DRC0a325192011-03-02 09:22:41 +00001016 "To crop this JPEG image, x must be a multiple of %d\n"
1017 "and y must be a multiple of %d.\n",
1018 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1019 retval=-1; goto bailout;
1020 }
DRC890f1e02011-02-26 22:02:37 +00001021 }
1022 }
1023
DRC9b28def2011-05-21 14:37:15 +00001024 srccoefs=jpeg_read_coefficients(dinfo);
DRC890f1e02011-02-26 22:02:37 +00001025
DRC0a325192011-03-02 09:22:41 +00001026 for(i=0; i<n; i++)
1027 {
DRCff78e372011-05-24 10:17:32 +00001028 int w, h, alloc=1;
DRC0a325192011-03-02 09:22:41 +00001029 if(!xinfo[i].crop)
1030 {
DRC9b28def2011-05-21 14:37:15 +00001031 w=dinfo->image_width; h=dinfo->image_height;
DRC0a325192011-03-02 09:22:41 +00001032 }
1033 else
1034 {
1035 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
1036 }
DRCff78e372011-05-24 10:17:32 +00001037 if(flags&TJFLAG_NOREALLOC)
1038 {
DRC9b49f0e2011-07-12 03:17:23 +00001039 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +00001040 }
DRC7bf04d32011-09-17 00:18:31 +00001041 if(!(t[i].options&TJXOPT_NOOUTPUT))
1042 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
DRC9b28def2011-05-21 14:37:15 +00001043 jpeg_copy_critical_parameters(dinfo, cinfo);
1044 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00001045 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00001046 if(!(t[i].options&TJXOPT_NOOUTPUT))
1047 {
1048 jpeg_write_coefficients(cinfo, dstcoefs);
1049 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1050 }
1051 else jinit_c_master_control(cinfo, TRUE);
DRC9b28def2011-05-21 14:37:15 +00001052 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00001053 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00001054 if(t[i].customFilter)
1055 {
1056 int ci, by, y;
1057 for(ci=0; ci<cinfo->num_components; ci++)
1058 {
1059 jpeg_component_info *compptr=&cinfo->comp_info[ci];
1060 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1061 DCTSIZE};
1062 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1063 compptr->height_in_blocks*DCTSIZE};
1064 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1065 {
1066 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1067 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1068 TRUE);
1069 for(y=0; y<compptr->v_samp_factor; y++)
1070 {
1071 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
DRCf5467112011-09-20 05:02:19 +00001072 ci, i, &t[i])==-1)
DRC7bf04d32011-09-17 00:18:31 +00001073 _throw("tjTransform(): Error in custom filter");
1074 arrayRegion.y+=DCTSIZE;
1075 }
1076 }
1077 }
1078 }
1079 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
DRC0a325192011-03-02 09:22:41 +00001080 }
1081
DRC9b28def2011-05-21 14:37:15 +00001082 jpeg_finish_decompress(dinfo);
DRC890f1e02011-02-26 22:02:37 +00001083
DRC890f1e02011-02-26 22:02:37 +00001084 bailout:
DRC9b28def2011-05-21 14:37:15 +00001085 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1086 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC0a325192011-03-02 09:22:41 +00001087 if(xinfo) free(xinfo);
DRC890f1e02011-02-26 22:02:37 +00001088 return retval;
1089}