blob: 2d5959a361150a036fdba2ceb8e581a5e78fcf0b [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:
DRC67ce3b22011-12-19 02:21:03 +0000150 case TJPF_RGBA:
DRC9b28def2011-05-21 14:37:15 +0000151 cinfo->in_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000152 case TJPF_BGRX:
DRC67ce3b22011-12-19 02:21:03 +0000153 case TJPF_BGRA:
DRC9b28def2011-05-21 14:37:15 +0000154 cinfo->in_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000155 case TJPF_XRGB:
DRC67ce3b22011-12-19 02:21:03 +0000156 case TJPF_ARGB:
DRC9b28def2011-05-21 14:37:15 +0000157 cinfo->in_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000158 case TJPF_XBGR:
DRC67ce3b22011-12-19 02:21:03 +0000159 case TJPF_ABGR:
DRC9b28def2011-05-21 14:37:15 +0000160 cinfo->in_color_space=JCS_EXT_XBGR; break;
161 #else
DRC25b995a2011-05-21 15:34:54 +0000162 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000163 if(RGB_RED==0 && RGB_GREEN==1 && RGB_BLUE==2 && RGB_PIXELSIZE==3)
164 {
165 cinfo->in_color_space=JCS_RGB; break;
166 }
167 default:
168 _throw("Unsupported pixel format");
169 #endif
DRCefa4ddc2010-10-13 19:22:50 +0000170 }
DRC2e7b76b2009-04-03 12:04:24 +0000171
DRC9b28def2011-05-21 14:37:15 +0000172 cinfo->input_components=tjPixelSize[pixelFormat];
173 jpeg_set_defaults(cinfo);
174 if(jpegQual>=0)
175 {
176 jpeg_set_quality(cinfo, jpegQual, TRUE);
177 if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW;
178 else cinfo->dct_method=JDCT_FASTEST;
179 }
DRC25b995a2011-05-21 15:34:54 +0000180 if(subsamp==TJSAMP_GRAY)
DRC9b28def2011-05-21 14:37:15 +0000181 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
182 else
183 jpeg_set_colorspace(cinfo, JCS_YCbCr);
DRC2e7b76b2009-04-03 12:04:24 +0000184
DRC9b28def2011-05-21 14:37:15 +0000185 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
186 cinfo->comp_info[1].h_samp_factor=1;
187 cinfo->comp_info[2].h_samp_factor=1;
188 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
189 cinfo->comp_info[1].v_samp_factor=1;
190 cinfo->comp_info[2].v_samp_factor=1;
DRCf12bb302011-09-07 05:03:18 +0000191
192 #if JCS_EXTENSIONS!=1
193 bailout:
194 #endif
195 return retval;
DRC9b28def2011-05-21 14:37:15 +0000196}
197
DRCf12bb302011-09-07 05:03:18 +0000198static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
DRC9b28def2011-05-21 14:37:15 +0000199 int pixelFormat)
200{
DRCf12bb302011-09-07 05:03:18 +0000201 int retval=0;
202
DRC9b28def2011-05-21 14:37:15 +0000203 switch(pixelFormat)
204 {
DRC25b995a2011-05-21 15:34:54 +0000205 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000206 dinfo->out_color_space=JCS_GRAYSCALE; break;
207 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000208 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000209 dinfo->out_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000210 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000211 dinfo->out_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000212 case TJPF_RGBX:
DRC9b28def2011-05-21 14:37:15 +0000213 dinfo->out_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000214 case TJPF_BGRX:
DRC9b28def2011-05-21 14:37:15 +0000215 dinfo->out_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000216 case TJPF_XRGB:
DRC9b28def2011-05-21 14:37:15 +0000217 dinfo->out_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000218 case TJPF_XBGR:
DRC9b28def2011-05-21 14:37:15 +0000219 dinfo->out_color_space=JCS_EXT_XBGR; break;
DRC67ce3b22011-12-19 02:21:03 +0000220 #if JCS_ALPHA_EXTENSIONS==1
221 case TJPF_RGBA:
222 dinfo->out_color_space=JCS_EXT_RGBA; break;
223 case TJPF_BGRA:
224 dinfo->out_color_space=JCS_EXT_BGRA; break;
225 case TJPF_ARGB:
226 dinfo->out_color_space=JCS_EXT_ARGB; break;
227 case TJPF_ABGR:
228 dinfo->out_color_space=JCS_EXT_ABGR; break;
229 #endif
DRC9b28def2011-05-21 14:37:15 +0000230 #else
DRC25b995a2011-05-21 15:34:54 +0000231 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000232 if(RGB_RED==0 && RGB_GREEN==1 && RGB_BLUE==2 && RGB_PIXELSIZE==3)
233 {
234 dinfo->out_color_space=JCS_RGB; break;
235 }
DRC67ce3b22011-12-19 02:21:03 +0000236 #endif
DRC9b28def2011-05-21 14:37:15 +0000237 default:
238 _throw("Unsupported pixel format");
DRC9b28def2011-05-21 14:37:15 +0000239 }
DRCf12bb302011-09-07 05:03:18 +0000240
DRCf12bb302011-09-07 05:03:18 +0000241 bailout:
DRCf12bb302011-09-07 05:03:18 +0000242 return retval;
DRC9b28def2011-05-21 14:37:15 +0000243}
244
245
DRC9b49f0e2011-07-12 03:17:23 +0000246static int getSubsamp(j_decompress_ptr dinfo)
247{
248 int retval=-1, i, k;
249 for(i=0; i<NUMSUBOPT; i++)
250 {
251 if(dinfo->num_components==pixelsize[i])
252 {
253 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
254 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
255 {
256 int match=0;
257 for(k=1; k<dinfo->num_components; k++)
258 {
259 if(dinfo->comp_info[k].h_samp_factor==1
260 && dinfo->comp_info[k].v_samp_factor==1)
261 match++;
262 }
263 if(match==dinfo->num_components-1)
264 {
265 retval=i; break;
266 }
267 }
268 }
269 }
270 return retval;
271}
272
273
DRC9b28def2011-05-21 14:37:15 +0000274/* General API functions */
275
276DLLEXPORT char* DLLCALL tjGetErrorStr(void)
277{
278 return errStr;
279}
280
281
282DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
283{
284 getinstance(handle);
285 if(setjmp(this->jerr.setjmp_buffer)) return -1;
286 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
287 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
288 free(this);
289 return 0;
290}
291
292
DRC6b76f752011-05-24 16:52:47 +0000293/* These are exposed mainly because Windows can't malloc() and free() across
294 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
295 with turbojpeg.dll for compatibility reasons. However, these functions
296 can potentially be used for other purposes by different implementations. */
297
298DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
299{
300 if(buf) free(buf);
301}
302
303
304DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
305{
306 return (unsigned char *)malloc(bytes);
307}
308
309
DRC9b28def2011-05-21 14:37:15 +0000310/* Compressor */
311
312static tjhandle _tjInitCompress(tjinstance *this)
313{
314 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
315
316 /* This is also straight out of example.c */
317 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
318 this->jerr.pub.error_exit=my_error_exit;
319 this->jerr.pub.output_message=my_output_message;
320
321 if(setjmp(this->jerr.setjmp_buffer))
322 {
323 /* If we get here, the JPEG code has signaled an error. */
324 if(this) free(this); return NULL;
325 }
326
327 jpeg_create_compress(&this->cinfo);
328 /* Make an initial call so it will create the destination manager */
329 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
330
DRC007a42c2011-05-22 13:55:56 +0000331 this->init|=COMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000332 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000333}
334
DRC890f1e02011-02-26 22:02:37 +0000335DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
336{
DRC9b28def2011-05-21 14:37:15 +0000337 tjinstance *this=NULL;
338 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000339 {
DRC007a42c2011-05-22 13:55:56 +0000340 snprintf(errStr, JMSG_LENGTH_MAX,
341 "tjInitCompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000342 return NULL;
343 }
DRC007a42c2011-05-22 13:55:56 +0000344 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000345 return _tjInitCompress(this);
DRC890f1e02011-02-26 22:02:37 +0000346}
347
DRC84241602011-02-25 02:08:23 +0000348
DRC9b49f0e2011-07-12 03:17:23 +0000349DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
350 int jpegSubsamp)
351{
352 unsigned long retval=0; int mcuw, mcuh, chromasf;
353 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
354 _throw("tjBufSize(): Invalid argument");
355
356 // This allows for rare corner cases in which a JPEG image can actually be
357 // larger than the uncompressed input (we wouldn't mention it if it hadn't
358 // happened before.)
359 mcuw=tjMCUWidth[jpegSubsamp];
360 mcuh=tjMCUHeight[jpegSubsamp];
361 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
362 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
363
364 bailout:
365 return retval;
366}
367
368
DRC2e7b76b2009-04-03 12:04:24 +0000369DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
370{
DRCf3cf9732011-02-22 00:16:14 +0000371 unsigned long retval=0;
372 if(width<1 || height<1)
DRC007a42c2011-05-22 13:55:56 +0000373 _throw("TJBUFSIZE(): Invalid argument");
DRCf3cf9732011-02-22 00:16:14 +0000374
375 // This allows for rare corner cases in which a JPEG image can actually be
376 // larger than the uncompressed input (we wouldn't mention it if it hadn't
DRCb28fc572011-02-22 06:41:29 +0000377 // happened before.)
DRC007a42c2011-05-22 13:55:56 +0000378 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
DRCf3cf9732011-02-22 00:16:14 +0000379
380 bailout:
381 return retval;
382}
383
DRC84241602011-02-25 02:08:23 +0000384
DRC9b49f0e2011-07-12 03:17:23 +0000385DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
DRCf3cf9732011-02-22 00:16:14 +0000386 int subsamp)
387{
388 unsigned long retval=0;
389 int pw, ph, cw, ch;
390 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
DRC9b49f0e2011-07-12 03:17:23 +0000391 _throw("tjBufSizeYUV(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000392 pw=PAD(width, tjMCUWidth[subsamp]/8);
393 ph=PAD(height, tjMCUHeight[subsamp]/8);
394 cw=pw*8/tjMCUWidth[subsamp]; ch=ph*8/tjMCUHeight[subsamp];
DRC25b995a2011-05-21 15:34:54 +0000395 retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2);
DRCf3cf9732011-02-22 00:16:14 +0000396
397 bailout:
398 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000399}
400
DRC84241602011-02-25 02:08:23 +0000401
DRC9b49f0e2011-07-12 03:17:23 +0000402DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
403 int subsamp)
404{
405 return tjBufSizeYUV(width, height, subsamp);
406}
407
408
DRC9b28def2011-05-21 14:37:15 +0000409DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
410 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
411 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
412{
DRCff78e372011-05-24 10:17:32 +0000413 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
DRC9b28def2011-05-21 14:37:15 +0000414
415 getinstance(handle)
416 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000417 _throw("tjCompress2(): Instance has not been initialized for compression");
DRC9b28def2011-05-21 14:37:15 +0000418
419 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
420 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
421 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
DRC007a42c2011-05-22 13:55:56 +0000422 _throw("tjCompress2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000423
424 if(setjmp(this->jerr.setjmp_buffer))
425 {
426 /* If we get here, the JPEG code has signaled an error. */
427 retval=-1;
428 goto bailout;
429 }
430
431 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
432
433 cinfo->image_width=width;
434 cinfo->image_height=height;
435
DRC25b995a2011-05-21 15:34:54 +0000436 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
437 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
438 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000439
DRCff78e372011-05-24 10:17:32 +0000440 if(flags&TJFLAG_NOREALLOC)
441 {
DRC9b49f0e2011-07-12 03:17:23 +0000442 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +0000443 }
444 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
DRCf12bb302011-09-07 05:03:18 +0000445 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1)
446 return -1;
DRC9b28def2011-05-21 14:37:15 +0000447
448 jpeg_start_compress(cinfo, TRUE);
449 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000450 _throw("tjCompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000451 for(i=0; i<height; i++)
452 {
DRC25b995a2011-05-21 15:34:54 +0000453 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000454 else row_pointer[i]=&srcBuf[i*pitch];
455 }
456 while(cinfo->next_scanline<cinfo->image_height)
457 {
458 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
459 cinfo->image_height-cinfo->next_scanline);
460 }
461 jpeg_finish_compress(cinfo);
462
463 bailout:
464 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
465 if(row_pointer) free(row_pointer);
466 return retval;
467}
468
469DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
470 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
471 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
472{
473 int retval=0; unsigned long size;
474 if(flags&TJ_YUV)
475 {
DRC9b49f0e2011-07-12 03:17:23 +0000476 size=tjBufSizeYUV(width, height, jpegSubsamp);
DRC9b28def2011-05-21 14:37:15 +0000477 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
478 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
479 }
480 else
481 {
DRC9b28def2011-05-21 14:37:15 +0000482 retval=tjCompress2(handle, srcBuf, width, pitch, height,
483 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
DRC25b995a2011-05-21 15:34:54 +0000484 flags|TJFLAG_NOREALLOC);
DRC9b28def2011-05-21 14:37:15 +0000485 }
486 *jpegSize=size;
487 return retval;
488}
489
490
491DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
492 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
493 int subsamp, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000494{
DRC91e86ba2011-02-15 05:24:08 +0000495 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000496 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
497 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
498 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC9b28def2011-05-21 14:37:15 +0000499 int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
500 JSAMPLE *ptr=dstBuf;
501 unsigned long yuvsize=0;
502 jpeg_component_info *compptr;
DRC2e7b76b2009-04-03 12:04:24 +0000503
DRC9b28def2011-05-21 14:37:15 +0000504 getinstance(handle);
505 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000506 _throw("tjEncodeYUV2(): Instance has not been initialized for compression");
DRC2e7b76b2009-04-03 12:04:24 +0000507
DRCfbb67472010-11-24 04:02:37 +0000508 for(i=0; i<MAX_COMPONENTS; i++)
509 {
510 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
511 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
512 }
513
DRC9b28def2011-05-21 14:37:15 +0000514 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
515 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
516 || subsamp>=NUMSUBOPT)
517 _throw("tjEncodeYUV2(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000518
DRC9b28def2011-05-21 14:37:15 +0000519 if(setjmp(this->jerr.setjmp_buffer))
520 {
521 /* If we get here, the JPEG code has signaled an error. */
522 retval=-1;
523 goto bailout;
524 }
DRC2e7b76b2009-04-03 12:04:24 +0000525
DRC9b28def2011-05-21 14:37:15 +0000526 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC2e7b76b2009-04-03 12:04:24 +0000527
DRC9b28def2011-05-21 14:37:15 +0000528 cinfo->image_width=width;
529 cinfo->image_height=height;
DRC2e7b76b2009-04-03 12:04:24 +0000530
DRC25b995a2011-05-21 15:34:54 +0000531 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
532 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
533 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000534
DRC9b49f0e2011-07-12 03:17:23 +0000535 yuvsize=tjBufSizeYUV(width, height, subsamp);
DRC9b28def2011-05-21 14:37:15 +0000536 jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0);
DRCf12bb302011-09-07 05:03:18 +0000537 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1)==-1) return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000538
DRC9b28def2011-05-21 14:37:15 +0000539 jpeg_start_compress(cinfo, TRUE);
540 pw=PAD(width, cinfo->max_h_samp_factor);
541 ph=PAD(height, cinfo->max_v_samp_factor);
DRC2e7b76b2009-04-03 12:04:24 +0000542
DRC9b28def2011-05-21 14:37:15 +0000543 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000544 _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000545 for(i=0; i<height; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000546 {
DRC25b995a2011-05-21 15:34:54 +0000547 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000548 else row_pointer[i]=&srcBuf[i*pitch];
549 }
550 if(height<ph)
551 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
DRCfbb67472010-11-24 04:02:37 +0000552
DRC9b28def2011-05-21 14:37:15 +0000553 for(i=0; i<cinfo->num_components; i++)
554 {
555 compptr=&cinfo->comp_info[i];
556 _tmpbuf[i]=(JSAMPLE *)malloc(
557 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
558 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRC007a42c2011-05-22 13:55:56 +0000559 if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000560 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRC007a42c2011-05-22 13:55:56 +0000561 if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000562 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRCfbb67472010-11-24 04:02:37 +0000563 {
DRC9b28def2011-05-21 14:37:15 +0000564 unsigned char *_tmpbuf_aligned=
565 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
566 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000567 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC9b28def2011-05-21 14:37:15 +0000568 /compptr->h_samp_factor, 16) * row];
DRCfbb67472010-11-24 04:02:37 +0000569 }
DRC9b28def2011-05-21 14:37:15 +0000570 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
571 * compptr->v_samp_factor + 16);
DRC007a42c2011-05-22 13:55:56 +0000572 if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000573 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRC007a42c2011-05-22 13:55:56 +0000574 if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000575 for(row=0; row<compptr->v_samp_factor; row++)
576 {
577 unsigned char *_tmpbuf2_aligned=
578 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
579 tmpbuf2[i][row]=&_tmpbuf2_aligned[
580 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
581 }
582 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
583 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
584 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
DRC007a42c2011-05-22 13:55:56 +0000585 if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000586 for(row=0; row<ch[i]; row++)
587 {
588 outbuf[i][row]=ptr;
589 ptr+=PAD(cw[i], 4);
590 }
591 }
592 if(yuvsize!=(unsigned long)(ptr-dstBuf))
593 _throw("tjEncodeYUV2(): Generated image is not the correct size");
DRCfbb67472010-11-24 04:02:37 +0000594
DRC9b28def2011-05-21 14:37:15 +0000595 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
DRCfbb67472010-11-24 04:02:37 +0000596 {
DRC9b28def2011-05-21 14:37:15 +0000597 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
598 cinfo->max_v_samp_factor);
599 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
600 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
601 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
602 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
603 compptr->v_samp_factor, cw[i]);
DRC6ee54592011-03-01 08:18:30 +0000604 }
DRC9b28def2011-05-21 14:37:15 +0000605 cinfo->next_scanline+=height;
606 jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000607
DRC91e86ba2011-02-15 05:24:08 +0000608 bailout:
DRC9b28def2011-05-21 14:37:15 +0000609 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000610 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000611 for(i=0; i<MAX_COMPONENTS; i++)
612 {
613 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000614 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000615 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000616 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000617 if(outbuf[i]!=NULL) free(outbuf[i]);
618 }
DRC91e86ba2011-02-15 05:24:08 +0000619 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000620}
621
DRC9b28def2011-05-21 14:37:15 +0000622DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
623 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
624 int subsamp, int flags)
DRC84241602011-02-25 02:08:23 +0000625{
DRC9b28def2011-05-21 14:37:15 +0000626 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
627 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
DRC84241602011-02-25 02:08:23 +0000628}
629
630
DRC9b28def2011-05-21 14:37:15 +0000631/* Decompressor */
DRC2e7b76b2009-04-03 12:04:24 +0000632
DRC9b28def2011-05-21 14:37:15 +0000633static tjhandle _tjInitDecompress(tjinstance *this)
DRC2e7b76b2009-04-03 12:04:24 +0000634{
DRC9b28def2011-05-21 14:37:15 +0000635 unsigned char buffer[1];
DRC2e7b76b2009-04-03 12:04:24 +0000636
DRC9b28def2011-05-21 14:37:15 +0000637 /* This is also straight out of example.c */
638 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
639 this->jerr.pub.error_exit=my_error_exit;
640 this->jerr.pub.output_message=my_output_message;
DRC2e7b76b2009-04-03 12:04:24 +0000641
DRC9b28def2011-05-21 14:37:15 +0000642 if(setjmp(this->jerr.setjmp_buffer))
643 {
644 /* If we get here, the JPEG code has signaled an error. */
645 if(this) free(this); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +0000646 }
DRC2e7b76b2009-04-03 12:04:24 +0000647
DRC9b28def2011-05-21 14:37:15 +0000648 jpeg_create_decompress(&this->dinfo);
649 /* Make an initial call so it will create the source manager */
650 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +0000651
DRC007a42c2011-05-22 13:55:56 +0000652 this->init|=DECOMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000653 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000654}
655
DRC890f1e02011-02-26 22:02:37 +0000656DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
657{
DRC9b28def2011-05-21 14:37:15 +0000658 tjinstance *this;
659 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000660 {
DRC007a42c2011-05-22 13:55:56 +0000661 snprintf(errStr, JMSG_LENGTH_MAX,
662 "tjInitDecompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000663 return NULL;
664 }
DRC007a42c2011-05-22 13:55:56 +0000665 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000666 return _tjInitDecompress(this);
DRC890f1e02011-02-26 22:02:37 +0000667}
668
DRC2e7b76b2009-04-03 12:04:24 +0000669
DRC9b28def2011-05-21 14:37:15 +0000670DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
671 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
672 int *jpegSubsamp)
DRC1fe80f82010-12-14 01:21:29 +0000673{
DRC9b49f0e2011-07-12 03:17:23 +0000674 int retval=0;
DRC1fe80f82010-12-14 01:21:29 +0000675
DRC9b28def2011-05-21 14:37:15 +0000676 getinstance(handle);
677 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000678 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
DRC1fe80f82010-12-14 01:21:29 +0000679
DRC9b28def2011-05-21 14:37:15 +0000680 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
681 || jpegSubsamp==NULL)
682 _throw("tjDecompressHeader2(): Invalid argument");
DRC1fe80f82010-12-14 01:21:29 +0000683
DRC9b28def2011-05-21 14:37:15 +0000684 if(setjmp(this->jerr.setjmp_buffer))
685 {
686 /* If we get here, the JPEG code has signaled an error. */
DRC1fe80f82010-12-14 01:21:29 +0000687 return -1;
688 }
689
DRC9b28def2011-05-21 14:37:15 +0000690 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
691 jpeg_read_header(dinfo, TRUE);
DRC1fe80f82010-12-14 01:21:29 +0000692
DRC9b28def2011-05-21 14:37:15 +0000693 *width=dinfo->image_width;
694 *height=dinfo->image_height;
DRC9b49f0e2011-07-12 03:17:23 +0000695 *jpegSubsamp=getSubsamp(dinfo);
DRC1fe80f82010-12-14 01:21:29 +0000696
DRC9b28def2011-05-21 14:37:15 +0000697 jpeg_abort_decompress(dinfo);
DRC1fe80f82010-12-14 01:21:29 +0000698
DRC9b28def2011-05-21 14:37:15 +0000699 if(*jpegSubsamp<0)
DRC007a42c2011-05-22 13:55:56 +0000700 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
701 if(*width<1 || *height<1)
702 _throw("tjDecompressHeader2(): Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +0000703
704 bailout:
705 return retval;
706}
707
DRC9b28def2011-05-21 14:37:15 +0000708DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
709 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
DRC91e86ba2011-02-15 05:24:08 +0000710{
DRC9b28def2011-05-21 14:37:15 +0000711 int jpegSubsamp;
712 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
713 &jpegSubsamp);
DRC1fe80f82010-12-14 01:21:29 +0000714}
715
716
DRC109a5782011-03-01 09:53:07 +0000717DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +0000718{
DRC109a5782011-03-01 09:53:07 +0000719 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +0000720 {
DRC9b28def2011-05-21 14:37:15 +0000721 snprintf(errStr, JMSG_LENGTH_MAX,
DRC007a42c2011-05-22 13:55:56 +0000722 "tjGetScalingFactors(): Invalid argument");
DRC109a5782011-03-01 09:53:07 +0000723 return NULL;
DRCb28fc572011-02-22 06:41:29 +0000724 }
725
DRC109a5782011-03-01 09:53:07 +0000726 *numscalingfactors=NUMSF;
727 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +0000728}
729
730
DRC9b28def2011-05-21 14:37:15 +0000731DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
732 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
733 int height, int pixelFormat, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000734{
DRC9b28def2011-05-21 14:37:15 +0000735 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRC109a5782011-03-01 09:53:07 +0000736 int jpegwidth, jpegheight, scaledw, scaledh;
DRC2e7b76b2009-04-03 12:04:24 +0000737
DRC9b28def2011-05-21 14:37:15 +0000738 getinstance(handle);
739 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000740 _throw("tjDecompress2(): Instance has not been initialized for decompression");
DRC9b28def2011-05-21 14:37:15 +0000741
742 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
743 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
744 _throw("tjDecompress2(): Invalid argument");
745
DRC25b995a2011-05-21 15:34:54 +0000746 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
747 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
748 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000749
750 if(setjmp(this->jerr.setjmp_buffer))
751 {
752 /* If we get here, the JPEG code has signaled an error. */
753 retval=-1;
754 goto bailout;
755 }
756
757 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
758 jpeg_read_header(dinfo, TRUE);
DRCf12bb302011-09-07 05:03:18 +0000759 if(setDecompDefaults(dinfo, pixelFormat)==-1) return -1;
DRC9b28def2011-05-21 14:37:15 +0000760
DRC25b995a2011-05-21 15:34:54 +0000761 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +0000762
763 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
764 if(width==0) width=jpegwidth;
765 if(height==0) height=jpegheight;
766 for(i=0; i<NUMSF; i++)
767 {
768 scaledw=TJSCALED(jpegwidth, sf[i]);
769 scaledh=TJSCALED(jpegheight, sf[i]);
770 if(scaledw<=width && scaledh<=height)
771 break;
772 }
773 if(scaledw>width || scaledh>height)
DRC007a42c2011-05-22 13:55:56 +0000774 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
DRC9b28def2011-05-21 14:37:15 +0000775 width=scaledw; height=scaledh;
776 dinfo->scale_num=sf[i].num;
777 dinfo->scale_denom=sf[i].denom;
778
779 jpeg_start_decompress(dinfo);
780 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
781 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
782 *dinfo->output_height))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000783 _throw("tjDecompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000784 for(i=0; i<(int)dinfo->output_height; i++)
785 {
DRC25b995a2011-05-21 15:34:54 +0000786 if(flags&TJFLAG_BOTTOMUP)
DRC9b28def2011-05-21 14:37:15 +0000787 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
788 else row_pointer[i]=&dstBuf[i*pitch];
789 }
790 while(dinfo->output_scanline<dinfo->output_height)
791 {
792 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
793 dinfo->output_height-dinfo->output_scanline);
794 }
795 jpeg_finish_decompress(dinfo);
796
797 bailout:
798 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
799 if(row_pointer) free(row_pointer);
800 return retval;
801}
802
803DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
804 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
805 int height, int pixelSize, int flags)
806{
807 if(flags&TJ_YUV)
808 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
809 else
810 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
811 height, getPixelFormat(pixelSize, flags), flags);
812}
813
814
815DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
816 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
817 int flags)
818{
819 int i, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
820 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
821 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
822 JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS];
823
824 getinstance(handle);
825 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000826 _throw("tjDecompressToYUV(): Instance has not been initialized for decompression");
DRC2e7b76b2009-04-03 12:04:24 +0000827
DRCf9cf5c72010-12-10 10:58:49 +0000828 for(i=0; i<MAX_COMPONENTS; i++)
829 {
830 tmpbuf[i]=NULL; outbuf[i]=NULL;
831 }
DRC9e17f7d2010-12-10 04:59:13 +0000832
DRC9b28def2011-05-21 14:37:15 +0000833 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
834 _throw("tjDecompressToYUV(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000835
DRC25b995a2011-05-21 15:34:54 +0000836 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
837 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
838 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000839
DRC9b28def2011-05-21 14:37:15 +0000840 if(setjmp(this->jerr.setjmp_buffer))
841 {
842 /* If we get here, the JPEG code has signaled an error. */
DRC91e86ba2011-02-15 05:24:08 +0000843 retval=-1;
844 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +0000845 }
DRC2e7b76b2009-04-03 12:04:24 +0000846
DRC9b28def2011-05-21 14:37:15 +0000847 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
848 jpeg_read_header(dinfo, TRUE);
DRC2e7b76b2009-04-03 12:04:24 +0000849
DRC9b28def2011-05-21 14:37:15 +0000850 for(i=0; i<dinfo->num_components; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000851 {
DRC9b28def2011-05-21 14:37:15 +0000852 jpeg_component_info *compptr=&dinfo->comp_info[i];
853 int ih;
854 iw[i]=compptr->width_in_blocks*DCTSIZE;
855 ih=compptr->height_in_blocks*DCTSIZE;
856 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
857 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
858 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
859 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
860 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
861 th[i]=compptr->v_samp_factor*DCTSIZE;
862 tmpbufsize+=iw[i]*th[i];
863 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000864 _throw("tjDecompressToYUV(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000865 for(row=0; row<ch[i]; row++)
866 {
867 outbuf[i][row]=ptr;
868 ptr+=PAD(cw[i], 4);
869 }
870 }
871 if(usetmpbuf)
872 {
873 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000874 _throw("tjDecompressToYUV(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000875 ptr=_tmpbuf;
876 for(i=0; i<dinfo->num_components; i++)
877 {
878 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000879 _throw("tjDecompressToYUV(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000880 for(row=0; row<th[i]; row++)
881 {
882 tmpbuf[i][row]=ptr;
883 ptr+=iw[i];
884 }
885 }
886 }
DRC9e17f7d2010-12-10 04:59:13 +0000887
DRC25b995a2011-05-21 15:34:54 +0000888 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +0000889 dinfo->raw_data_out=TRUE;
890
891 jpeg_start_decompress(dinfo);
892 for(row=0; row<(int)dinfo->output_height;
893 row+=dinfo->max_v_samp_factor*DCTSIZE)
894 {
895 JSAMPARRAY yuvptr[MAX_COMPONENTS];
896 int crow[MAX_COMPONENTS];
DRC9e17f7d2010-12-10 04:59:13 +0000897 for(i=0; i<dinfo->num_components; i++)
898 {
899 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRC9b28def2011-05-21 14:37:15 +0000900 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
901 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
902 else yuvptr[i]=&outbuf[i][crow[i]];
DRCf9cf5c72010-12-10 10:58:49 +0000903 }
DRC9b28def2011-05-21 14:37:15 +0000904 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
DRCf9cf5c72010-12-10 10:58:49 +0000905 if(usetmpbuf)
906 {
DRC9b28def2011-05-21 14:37:15 +0000907 int j;
DRCf9cf5c72010-12-10 10:58:49 +0000908 for(i=0; i<dinfo->num_components; i++)
909 {
DRC9b28def2011-05-21 14:37:15 +0000910 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +0000911 {
DRC9b28def2011-05-21 14:37:15 +0000912 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000913 }
DRC9e17f7d2010-12-10 04:59:13 +0000914 }
915 }
916 }
DRC9b28def2011-05-21 14:37:15 +0000917 jpeg_finish_decompress(dinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000918
DRC91e86ba2011-02-15 05:24:08 +0000919 bailout:
DRC9b28def2011-05-21 14:37:15 +0000920 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC9e17f7d2010-12-10 04:59:13 +0000921 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +0000922 {
923 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +0000924 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000925 }
926 if(_tmpbuf) free(_tmpbuf);
DRC91e86ba2011-02-15 05:24:08 +0000927 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000928}
929
930
DRC9b28def2011-05-21 14:37:15 +0000931/* Transformer */
DRC890f1e02011-02-26 22:02:37 +0000932
933DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
934{
DRC9b28def2011-05-21 14:37:15 +0000935 tjinstance *this=NULL; tjhandle handle=NULL;
936 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000937 {
DRC007a42c2011-05-22 13:55:56 +0000938 snprintf(errStr, JMSG_LENGTH_MAX,
939 "tjInitTransform(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000940 return NULL;
941 }
DRC007a42c2011-05-22 13:55:56 +0000942 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000943 handle=_tjInitCompress(this);
944 if(!handle) return NULL;
945 handle=_tjInitDecompress(this);
946 return handle;
DRC890f1e02011-02-26 22:02:37 +0000947}
948
949
DRC9b28def2011-05-21 14:37:15 +0000950DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
951 unsigned long jpegSize, int n, unsigned char **dstBufs,
952 unsigned long *dstSizes, tjtransform *t, int flags)
DRC890f1e02011-02-26 22:02:37 +0000953{
DRC0a325192011-03-02 09:22:41 +0000954 jpeg_transform_info *xinfo=NULL;
DRC890f1e02011-02-26 22:02:37 +0000955 jvirt_barray_ptr *srccoefs, *dstcoefs;
DRC9b49f0e2011-07-12 03:17:23 +0000956 int retval=0, i, jpegSubsamp;
DRC890f1e02011-02-26 22:02:37 +0000957
DRC9b28def2011-05-21 14:37:15 +0000958 getinstance(handle);
959 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000960 _throw("tjTransform(): Instance has not been initialized for transformation");
DRC890f1e02011-02-26 22:02:37 +0000961
DRC9b28def2011-05-21 14:37:15 +0000962 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
963 || t==NULL || flags<0)
964 _throw("tjTransform(): Invalid argument");
965
DRC25b995a2011-05-21 15:34:54 +0000966 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
967 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
968 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC890f1e02011-02-26 22:02:37 +0000969
DRC9b28def2011-05-21 14:37:15 +0000970 if(setjmp(this->jerr.setjmp_buffer))
971 {
972 /* If we get here, the JPEG code has signaled an error. */
DRC890f1e02011-02-26 22:02:37 +0000973 retval=-1;
974 goto bailout;
975 }
976
DRC9b28def2011-05-21 14:37:15 +0000977 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
DRC890f1e02011-02-26 22:02:37 +0000978
DRC0a325192011-03-02 09:22:41 +0000979 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
980 ==NULL)
DRC007a42c2011-05-22 13:55:56 +0000981 _throw("tjTransform(): Memory allocation failure");
982 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
DRC890f1e02011-02-26 22:02:37 +0000983
DRC0a325192011-03-02 09:22:41 +0000984 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +0000985 {
DRC0a325192011-03-02 09:22:41 +0000986 xinfo[i].transform=xformtypes[t[i].op];
DRC25b995a2011-05-21 15:34:54 +0000987 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
988 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
989 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
990 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
991 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
DRCba5ea512011-03-04 03:20:34 +0000992 else xinfo[i].slow_hflip=0;
DRC0a325192011-03-02 09:22:41 +0000993
994 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +0000995 {
DRC0a325192011-03-02 09:22:41 +0000996 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
997 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
998 if(t[i].r.w!=0)
999 {
1000 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
1001 }
DRCd932e582011-03-15 20:09:47 +00001002 else xinfo[i].crop_width=JCROP_UNSET;
DRC0a325192011-03-02 09:22:41 +00001003 if(t[i].r.h!=0)
1004 {
1005 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
1006 }
DRCd932e582011-03-15 20:09:47 +00001007 else xinfo[i].crop_height=JCROP_UNSET;
DRC890f1e02011-02-26 22:02:37 +00001008 }
1009 }
1010
DRC9b28def2011-05-21 14:37:15 +00001011 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1012 jpeg_read_header(dinfo, TRUE);
DRC9b49f0e2011-07-12 03:17:23 +00001013 jpegSubsamp=getSubsamp(dinfo);
1014 if(jpegSubsamp<0)
1015 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC890f1e02011-02-26 22:02:37 +00001016
DRC0a325192011-03-02 09:22:41 +00001017 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001018 {
DRC9b28def2011-05-21 14:37:15 +00001019 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
DRC007a42c2011-05-22 13:55:56 +00001020 _throw("tjTransform(): Transform is not perfect");
DRC890f1e02011-02-26 22:02:37 +00001021
DRC0a325192011-03-02 09:22:41 +00001022 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001023 {
DRC0a325192011-03-02 09:22:41 +00001024 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1025 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1026 {
DRC9b28def2011-05-21 14:37:15 +00001027 snprintf(errStr, JMSG_LENGTH_MAX,
DRC0a325192011-03-02 09:22:41 +00001028 "To crop this JPEG image, x must be a multiple of %d\n"
1029 "and y must be a multiple of %d.\n",
1030 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1031 retval=-1; goto bailout;
1032 }
DRC890f1e02011-02-26 22:02:37 +00001033 }
1034 }
1035
DRC9b28def2011-05-21 14:37:15 +00001036 srccoefs=jpeg_read_coefficients(dinfo);
DRC890f1e02011-02-26 22:02:37 +00001037
DRC0a325192011-03-02 09:22:41 +00001038 for(i=0; i<n; i++)
1039 {
DRCff78e372011-05-24 10:17:32 +00001040 int w, h, alloc=1;
DRC0a325192011-03-02 09:22:41 +00001041 if(!xinfo[i].crop)
1042 {
DRC9b28def2011-05-21 14:37:15 +00001043 w=dinfo->image_width; h=dinfo->image_height;
DRC0a325192011-03-02 09:22:41 +00001044 }
1045 else
1046 {
1047 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
1048 }
DRCff78e372011-05-24 10:17:32 +00001049 if(flags&TJFLAG_NOREALLOC)
1050 {
DRC9b49f0e2011-07-12 03:17:23 +00001051 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +00001052 }
DRC7bf04d32011-09-17 00:18:31 +00001053 if(!(t[i].options&TJXOPT_NOOUTPUT))
1054 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
DRC9b28def2011-05-21 14:37:15 +00001055 jpeg_copy_critical_parameters(dinfo, cinfo);
1056 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00001057 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00001058 if(!(t[i].options&TJXOPT_NOOUTPUT))
1059 {
1060 jpeg_write_coefficients(cinfo, dstcoefs);
1061 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1062 }
1063 else jinit_c_master_control(cinfo, TRUE);
DRC9b28def2011-05-21 14:37:15 +00001064 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00001065 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00001066 if(t[i].customFilter)
1067 {
DRCefe28ce2012-01-17 11:48:38 +00001068 int ci, y; JDIMENSION by;
DRC7bf04d32011-09-17 00:18:31 +00001069 for(ci=0; ci<cinfo->num_components; ci++)
1070 {
1071 jpeg_component_info *compptr=&cinfo->comp_info[ci];
1072 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1073 DCTSIZE};
1074 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1075 compptr->height_in_blocks*DCTSIZE};
1076 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1077 {
1078 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1079 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1080 TRUE);
1081 for(y=0; y<compptr->v_samp_factor; y++)
1082 {
1083 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
DRCf5467112011-09-20 05:02:19 +00001084 ci, i, &t[i])==-1)
DRC7bf04d32011-09-17 00:18:31 +00001085 _throw("tjTransform(): Error in custom filter");
1086 arrayRegion.y+=DCTSIZE;
1087 }
1088 }
1089 }
1090 }
1091 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
DRC0a325192011-03-02 09:22:41 +00001092 }
1093
DRC9b28def2011-05-21 14:37:15 +00001094 jpeg_finish_decompress(dinfo);
DRC890f1e02011-02-26 22:02:37 +00001095
DRC890f1e02011-02-26 22:02:37 +00001096 bailout:
DRC9b28def2011-05-21 14:37:15 +00001097 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1098 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC0a325192011-03-02 09:22:41 +00001099 if(xinfo) free(xinfo);
DRC890f1e02011-02-26 22:02:37 +00001100 return retval;
1101}