blob: c875fd93be8066eca0ef2d1d94a9db40f3c69251 [file] [log] [blame]
DRC9b28def2011-05-21 14:37:15 +00001/*
DRC2eda8212012-03-23 19:32:38 +00002 * Copyright (C)2009-2012 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
DRCab2df6e2012-01-28 06:49:56 +000095#define NUMSF 16
DRC109a5782011-03-01 09:53:07 +000096static const tjscalingfactor sf[NUMSF]={
DRCab2df6e2012-01-28 06:49:56 +000097 {2, 1},
98 {15, 8},
99 {7, 4},
100 {13, 8},
101 {3, 2},
102 {11, 8},
103 {5, 4},
104 {9, 8},
DRC109a5782011-03-01 09:53:07 +0000105 {1, 1},
DRCab2df6e2012-01-28 06:49:56 +0000106 {7, 8},
107 {3, 4},
108 {5, 8},
DRC109a5782011-03-01 09:53:07 +0000109 {1, 2},
DRCab2df6e2012-01-28 06:49:56 +0000110 {3, 8},
DRC109a5782011-03-01 09:53:07 +0000111 {1, 4},
112 {1, 8}
113};
DRC2e7b76b2009-04-03 12:04:24 +0000114
DRCa29294a2011-05-24 09:17:57 +0000115#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
DRCda5220a2011-03-02 02:17:30 +0000116 retval=-1; goto bailout;}
DRC9b28def2011-05-21 14:37:15 +0000117#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
118 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
119 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
120 return -1;} \
121 cinfo=&this->cinfo; dinfo=&this->dinfo;
DRC2e7b76b2009-04-03 12:04:24 +0000122
DRC9b28def2011-05-21 14:37:15 +0000123static int getPixelFormat(int pixelSize, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000124{
DRC25b995a2011-05-21 15:34:54 +0000125 if(pixelSize==1) return TJPF_GRAY;
DRC9b28def2011-05-21 14:37:15 +0000126 if(pixelSize==3)
127 {
DRC25b995a2011-05-21 15:34:54 +0000128 if(flags&TJ_BGR) return TJPF_BGR;
129 else return TJPF_RGB;
DRC9b28def2011-05-21 14:37:15 +0000130 }
131 if(pixelSize==4)
132 {
133 if(flags&TJ_ALPHAFIRST)
134 {
DRC25b995a2011-05-21 15:34:54 +0000135 if(flags&TJ_BGR) return TJPF_XBGR;
136 else return TJPF_XRGB;
DRC9b28def2011-05-21 14:37:15 +0000137 }
138 else
139 {
DRC25b995a2011-05-21 15:34:54 +0000140 if(flags&TJ_BGR) return TJPF_BGRX;
141 else return TJPF_RGBX;
DRC9b28def2011-05-21 14:37:15 +0000142 }
143 }
144 return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000145}
146
DRCf12bb302011-09-07 05:03:18 +0000147static int setCompDefaults(struct jpeg_compress_struct *cinfo,
DRC9b28def2011-05-21 14:37:15 +0000148 int pixelFormat, int subsamp, int jpegQual)
DRC2e7b76b2009-04-03 12:04:24 +0000149{
DRCf12bb302011-09-07 05:03:18 +0000150 int retval=0;
151
DRC9b28def2011-05-21 14:37:15 +0000152 switch(pixelFormat)
153 {
DRC25b995a2011-05-21 15:34:54 +0000154 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000155 cinfo->in_color_space=JCS_GRAYSCALE; break;
156 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000157 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000158 cinfo->in_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000159 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000160 cinfo->in_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000161 case TJPF_RGBX:
DRC67ce3b22011-12-19 02:21:03 +0000162 case TJPF_RGBA:
DRC9b28def2011-05-21 14:37:15 +0000163 cinfo->in_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000164 case TJPF_BGRX:
DRC67ce3b22011-12-19 02:21:03 +0000165 case TJPF_BGRA:
DRC9b28def2011-05-21 14:37:15 +0000166 cinfo->in_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000167 case TJPF_XRGB:
DRC67ce3b22011-12-19 02:21:03 +0000168 case TJPF_ARGB:
DRC9b28def2011-05-21 14:37:15 +0000169 cinfo->in_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000170 case TJPF_XBGR:
DRC67ce3b22011-12-19 02:21:03 +0000171 case TJPF_ABGR:
DRC9b28def2011-05-21 14:37:15 +0000172 cinfo->in_color_space=JCS_EXT_XBGR; break;
173 #else
DRC25b995a2011-05-21 15:34:54 +0000174 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000175 case TJPF_BGR:
176 case TJPF_RGBX:
177 case TJPF_BGRX:
178 case TJPF_XRGB:
179 case TJPF_XBGR:
180 case TJPF_RGBA:
181 case TJPF_BGRA:
182 case TJPF_ARGB:
183 case TJPF_ABGR:
184 cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
185 break;
DRC9b28def2011-05-21 14:37:15 +0000186 #endif
DRCefa4ddc2010-10-13 19:22:50 +0000187 }
DRC2e7b76b2009-04-03 12:04:24 +0000188
DRC9b28def2011-05-21 14:37:15 +0000189 cinfo->input_components=tjPixelSize[pixelFormat];
190 jpeg_set_defaults(cinfo);
191 if(jpegQual>=0)
192 {
193 jpeg_set_quality(cinfo, jpegQual, TRUE);
194 if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW;
195 else cinfo->dct_method=JDCT_FASTEST;
196 }
DRC25b995a2011-05-21 15:34:54 +0000197 if(subsamp==TJSAMP_GRAY)
DRC9b28def2011-05-21 14:37:15 +0000198 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
199 else
200 jpeg_set_colorspace(cinfo, JCS_YCbCr);
DRC2e7b76b2009-04-03 12:04:24 +0000201
DRC9b28def2011-05-21 14:37:15 +0000202 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
203 cinfo->comp_info[1].h_samp_factor=1;
204 cinfo->comp_info[2].h_samp_factor=1;
205 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
206 cinfo->comp_info[1].v_samp_factor=1;
207 cinfo->comp_info[2].v_samp_factor=1;
DRCf12bb302011-09-07 05:03:18 +0000208
DRCf12bb302011-09-07 05:03:18 +0000209 return retval;
DRC9b28def2011-05-21 14:37:15 +0000210}
211
DRCf12bb302011-09-07 05:03:18 +0000212static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
DRC9b28def2011-05-21 14:37:15 +0000213 int pixelFormat)
214{
DRCf12bb302011-09-07 05:03:18 +0000215 int retval=0;
216
DRC9b28def2011-05-21 14:37:15 +0000217 switch(pixelFormat)
218 {
DRC25b995a2011-05-21 15:34:54 +0000219 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000220 dinfo->out_color_space=JCS_GRAYSCALE; break;
221 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000222 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000223 dinfo->out_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000224 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000225 dinfo->out_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000226 case TJPF_RGBX:
DRC9b28def2011-05-21 14:37:15 +0000227 dinfo->out_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000228 case TJPF_BGRX:
DRC9b28def2011-05-21 14:37:15 +0000229 dinfo->out_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000230 case TJPF_XRGB:
DRC9b28def2011-05-21 14:37:15 +0000231 dinfo->out_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000232 case TJPF_XBGR:
DRC9b28def2011-05-21 14:37:15 +0000233 dinfo->out_color_space=JCS_EXT_XBGR; break;
DRC67ce3b22011-12-19 02:21:03 +0000234 #if JCS_ALPHA_EXTENSIONS==1
235 case TJPF_RGBA:
236 dinfo->out_color_space=JCS_EXT_RGBA; break;
237 case TJPF_BGRA:
238 dinfo->out_color_space=JCS_EXT_BGRA; break;
239 case TJPF_ARGB:
240 dinfo->out_color_space=JCS_EXT_ARGB; break;
241 case TJPF_ABGR:
242 dinfo->out_color_space=JCS_EXT_ABGR; break;
243 #endif
DRC9b28def2011-05-21 14:37:15 +0000244 #else
DRC25b995a2011-05-21 15:34:54 +0000245 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000246 case TJPF_BGR:
247 case TJPF_RGBX:
248 case TJPF_BGRX:
249 case TJPF_XRGB:
250 case TJPF_XBGR:
251 case TJPF_RGBA:
252 case TJPF_BGRA:
253 case TJPF_ARGB:
254 case TJPF_ABGR:
255 dinfo->out_color_space=JCS_RGB; break;
DRC67ce3b22011-12-19 02:21:03 +0000256 #endif
DRC9b28def2011-05-21 14:37:15 +0000257 default:
258 _throw("Unsupported pixel format");
DRC9b28def2011-05-21 14:37:15 +0000259 }
DRCf12bb302011-09-07 05:03:18 +0000260
DRCf12bb302011-09-07 05:03:18 +0000261 bailout:
DRCf12bb302011-09-07 05:03:18 +0000262 return retval;
DRC9b28def2011-05-21 14:37:15 +0000263}
264
265
DRC9b49f0e2011-07-12 03:17:23 +0000266static int getSubsamp(j_decompress_ptr dinfo)
267{
268 int retval=-1, i, k;
269 for(i=0; i<NUMSUBOPT; i++)
270 {
271 if(dinfo->num_components==pixelsize[i])
272 {
273 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
274 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
275 {
276 int match=0;
277 for(k=1; k<dinfo->num_components; k++)
278 {
279 if(dinfo->comp_info[k].h_samp_factor==1
280 && dinfo->comp_info[k].v_samp_factor==1)
281 match++;
282 }
283 if(match==dinfo->num_components-1)
284 {
285 retval=i; break;
286 }
287 }
288 }
289 }
290 return retval;
291}
292
293
DRCafc06922012-03-23 19:47:57 +0000294#ifndef JCS_EXTENSIONS
295
296/* Conversion functions to emulate the colorspace extensions. This allows the
297 TurboJPEG wrapper to be used with libjpeg */
298
299#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
300 int rowPad=pitch-width*PS; \
301 while(height--) \
302 { \
303 unsigned char *endOfRow=src+width*PS; \
304 while(src<endOfRow) \
305 { \
306 dst[RGB_RED]=src[ROFFSET]; \
307 dst[RGB_GREEN]=src[GOFFSET]; \
308 dst[RGB_BLUE]=src[BOFFSET]; \
309 dst+=RGB_PIXELSIZE; src+=PS; \
310 } \
311 src+=rowPad; \
312 } \
313}
314
315static unsigned char *toRGB(unsigned char *src, int width, int pitch,
316 int height, int pixelFormat, unsigned char *dst)
317{
318 unsigned char *retval=src;
319 switch(pixelFormat)
320 {
321 case TJPF_RGB:
322 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
323 retval=dst; TORGB(3, 0, 1, 2);
324 #endif
325 break;
326 case TJPF_BGR:
327 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
328 retval=dst; TORGB(3, 2, 1, 0);
329 #endif
330 break;
331 case TJPF_RGBX:
332 case TJPF_RGBA:
333 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
334 retval=dst; TORGB(4, 0, 1, 2);
335 #endif
336 break;
337 case TJPF_BGRX:
338 case TJPF_BGRA:
339 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
340 retval=dst; TORGB(4, 2, 1, 0);
341 #endif
342 break;
343 case TJPF_XRGB:
344 case TJPF_ARGB:
345 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
346 retval=dst; TORGB(4, 1, 2, 3);
347 #endif
348 break;
349 case TJPF_XBGR:
350 case TJPF_ABGR:
351 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
352 retval=dst; TORGB(4, 3, 2, 1);
353 #endif
354 break;
355 }
356 return retval;
357}
358
359#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
360 int rowPad=pitch-width*PS; \
361 while(height--) \
362 { \
363 unsigned char *endOfRow=dst+width*PS; \
364 while(dst<endOfRow) \
365 { \
366 dst[ROFFSET]=src[RGB_RED]; \
367 dst[GOFFSET]=src[RGB_GREEN]; \
368 dst[BOFFSET]=src[RGB_BLUE]; \
369 SETALPHA \
370 dst+=PS; src+=RGB_PIXELSIZE; \
371 } \
372 dst+=rowPad; \
373 } \
374}
375
376static void fromRGB(unsigned char *src, unsigned char *dst, int width,
377 int pitch, int height, int pixelFormat)
378{
379 switch(pixelFormat)
380 {
381 case TJPF_RGB:
382 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
383 FROMRGB(3, 0, 1, 2,);
384 #endif
385 break;
386 case TJPF_BGR:
387 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
388 FROMRGB(3, 2, 1, 0,);
389 #endif
390 break;
391 case TJPF_RGBX:
392 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
393 FROMRGB(4, 0, 1, 2,);
394 #endif
395 break;
396 case TJPF_RGBA:
397 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
398 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
399 #endif
400 break;
401 case TJPF_BGRX:
402 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
403 FROMRGB(4, 2, 1, 0,);
404 #endif
405 break;
406 case TJPF_BGRA:
407 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
408 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
409 #endif
410 break;
411 case TJPF_XRGB:
412 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
413 FROMRGB(4, 1, 2, 3,); return;
414 #endif
415 break;
416 case TJPF_ARGB:
417 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
418 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
419 #endif
420 break;
421 case TJPF_XBGR:
422 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
423 FROMRGB(4, 3, 2, 1,); return;
424 #endif
425 break;
426 case TJPF_ABGR:
427 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
428 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
429 #endif
430 break;
431 }
432}
433
434#endif
435
436
DRC9b28def2011-05-21 14:37:15 +0000437/* General API functions */
438
439DLLEXPORT char* DLLCALL tjGetErrorStr(void)
440{
441 return errStr;
442}
443
444
445DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
446{
447 getinstance(handle);
448 if(setjmp(this->jerr.setjmp_buffer)) return -1;
449 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
450 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
451 free(this);
452 return 0;
453}
454
455
DRC6b76f752011-05-24 16:52:47 +0000456/* These are exposed mainly because Windows can't malloc() and free() across
457 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
458 with turbojpeg.dll for compatibility reasons. However, these functions
459 can potentially be used for other purposes by different implementations. */
460
461DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
462{
463 if(buf) free(buf);
464}
465
466
467DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
468{
469 return (unsigned char *)malloc(bytes);
470}
471
472
DRC9b28def2011-05-21 14:37:15 +0000473/* Compressor */
474
475static tjhandle _tjInitCompress(tjinstance *this)
476{
477 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
478
479 /* This is also straight out of example.c */
480 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
481 this->jerr.pub.error_exit=my_error_exit;
482 this->jerr.pub.output_message=my_output_message;
483
484 if(setjmp(this->jerr.setjmp_buffer))
485 {
486 /* If we get here, the JPEG code has signaled an error. */
487 if(this) free(this); return NULL;
488 }
489
490 jpeg_create_compress(&this->cinfo);
491 /* Make an initial call so it will create the destination manager */
492 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
493
DRC007a42c2011-05-22 13:55:56 +0000494 this->init|=COMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000495 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000496}
497
DRC890f1e02011-02-26 22:02:37 +0000498DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
499{
DRC9b28def2011-05-21 14:37:15 +0000500 tjinstance *this=NULL;
501 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000502 {
DRC007a42c2011-05-22 13:55:56 +0000503 snprintf(errStr, JMSG_LENGTH_MAX,
504 "tjInitCompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000505 return NULL;
506 }
DRC007a42c2011-05-22 13:55:56 +0000507 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000508 return _tjInitCompress(this);
DRC890f1e02011-02-26 22:02:37 +0000509}
510
DRC84241602011-02-25 02:08:23 +0000511
DRC9b49f0e2011-07-12 03:17:23 +0000512DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
513 int jpegSubsamp)
514{
515 unsigned long retval=0; int mcuw, mcuh, chromasf;
516 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
517 _throw("tjBufSize(): Invalid argument");
518
519 // This allows for rare corner cases in which a JPEG image can actually be
520 // larger than the uncompressed input (we wouldn't mention it if it hadn't
521 // happened before.)
522 mcuw=tjMCUWidth[jpegSubsamp];
523 mcuh=tjMCUHeight[jpegSubsamp];
524 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
525 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
526
527 bailout:
528 return retval;
529}
530
531
DRC2e7b76b2009-04-03 12:04:24 +0000532DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
533{
DRCf3cf9732011-02-22 00:16:14 +0000534 unsigned long retval=0;
535 if(width<1 || height<1)
DRC007a42c2011-05-22 13:55:56 +0000536 _throw("TJBUFSIZE(): Invalid argument");
DRCf3cf9732011-02-22 00:16:14 +0000537
538 // This allows for rare corner cases in which a JPEG image can actually be
539 // larger than the uncompressed input (we wouldn't mention it if it hadn't
DRCb28fc572011-02-22 06:41:29 +0000540 // happened before.)
DRC007a42c2011-05-22 13:55:56 +0000541 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
DRCf3cf9732011-02-22 00:16:14 +0000542
543 bailout:
544 return retval;
545}
546
DRC84241602011-02-25 02:08:23 +0000547
DRC9b49f0e2011-07-12 03:17:23 +0000548DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
DRCf3cf9732011-02-22 00:16:14 +0000549 int subsamp)
550{
551 unsigned long retval=0;
552 int pw, ph, cw, ch;
553 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
DRC9b49f0e2011-07-12 03:17:23 +0000554 _throw("tjBufSizeYUV(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000555 pw=PAD(width, tjMCUWidth[subsamp]/8);
556 ph=PAD(height, tjMCUHeight[subsamp]/8);
557 cw=pw*8/tjMCUWidth[subsamp]; ch=ph*8/tjMCUHeight[subsamp];
DRC25b995a2011-05-21 15:34:54 +0000558 retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2);
DRCf3cf9732011-02-22 00:16:14 +0000559
560 bailout:
561 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000562}
563
DRC84241602011-02-25 02:08:23 +0000564
DRC9b49f0e2011-07-12 03:17:23 +0000565DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
566 int subsamp)
567{
568 return tjBufSizeYUV(width, height, subsamp);
569}
570
571
DRC9b28def2011-05-21 14:37:15 +0000572DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
573 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
574 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
575{
DRCff78e372011-05-24 10:17:32 +0000576 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
DRCafc06922012-03-23 19:47:57 +0000577 #ifndef JCS_EXTENSIONS
578 unsigned char *rgbBuf=NULL;
579 #endif
DRC9b28def2011-05-21 14:37:15 +0000580
581 getinstance(handle)
582 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000583 _throw("tjCompress2(): Instance has not been initialized for compression");
DRC9b28def2011-05-21 14:37:15 +0000584
585 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
586 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
587 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
DRC007a42c2011-05-22 13:55:56 +0000588 _throw("tjCompress2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000589
590 if(setjmp(this->jerr.setjmp_buffer))
591 {
592 /* If we get here, the JPEG code has signaled an error. */
593 retval=-1;
594 goto bailout;
595 }
596
597 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
598
DRCafc06922012-03-23 19:47:57 +0000599 #ifndef JCS_EXTENSIONS
600 if(pixelFormat!=TJPF_GRAY)
601 {
602 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
603 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
604 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
605 pitch=width*RGB_PIXELSIZE;
606 }
607 #endif
608
DRC9b28def2011-05-21 14:37:15 +0000609 cinfo->image_width=width;
610 cinfo->image_height=height;
611
DRC25b995a2011-05-21 15:34:54 +0000612 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
613 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
614 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000615
DRCff78e372011-05-24 10:17:32 +0000616 if(flags&TJFLAG_NOREALLOC)
617 {
DRC9b49f0e2011-07-12 03:17:23 +0000618 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +0000619 }
620 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
DRCf12bb302011-09-07 05:03:18 +0000621 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1)
622 return -1;
DRC9b28def2011-05-21 14:37:15 +0000623
624 jpeg_start_compress(cinfo, TRUE);
625 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000626 _throw("tjCompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000627 for(i=0; i<height; i++)
628 {
DRC25b995a2011-05-21 15:34:54 +0000629 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000630 else row_pointer[i]=&srcBuf[i*pitch];
631 }
632 while(cinfo->next_scanline<cinfo->image_height)
633 {
634 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
635 cinfo->image_height-cinfo->next_scanline);
636 }
637 jpeg_finish_compress(cinfo);
638
639 bailout:
640 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000641 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000642 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000643 #endif
DRC9b28def2011-05-21 14:37:15 +0000644 if(row_pointer) free(row_pointer);
645 return retval;
646}
647
648DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
649 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
650 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
651{
652 int retval=0; unsigned long size;
653 if(flags&TJ_YUV)
654 {
DRC9b49f0e2011-07-12 03:17:23 +0000655 size=tjBufSizeYUV(width, height, jpegSubsamp);
DRC9b28def2011-05-21 14:37:15 +0000656 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
657 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
658 }
659 else
660 {
DRC9b28def2011-05-21 14:37:15 +0000661 retval=tjCompress2(handle, srcBuf, width, pitch, height,
662 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
DRC25b995a2011-05-21 15:34:54 +0000663 flags|TJFLAG_NOREALLOC);
DRC9b28def2011-05-21 14:37:15 +0000664 }
665 *jpegSize=size;
666 return retval;
667}
668
669
670DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
671 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
672 int subsamp, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000673{
DRC91e86ba2011-02-15 05:24:08 +0000674 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000675 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
676 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
677 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC9b28def2011-05-21 14:37:15 +0000678 int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
679 JSAMPLE *ptr=dstBuf;
DRCafc06922012-03-23 19:47:57 +0000680 unsigned long yuvsize=0;
DRC9b28def2011-05-21 14:37:15 +0000681 jpeg_component_info *compptr;
DRCafc06922012-03-23 19:47:57 +0000682 #ifndef JCS_EXTENSIONS
683 unsigned char *rgbBuf=NULL;
684 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000685
DRC9b28def2011-05-21 14:37:15 +0000686 getinstance(handle);
687 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000688 _throw("tjEncodeYUV2(): Instance has not been initialized for compression");
DRC2e7b76b2009-04-03 12:04:24 +0000689
DRCfbb67472010-11-24 04:02:37 +0000690 for(i=0; i<MAX_COMPONENTS; i++)
691 {
692 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
693 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
694 }
695
DRC9b28def2011-05-21 14:37:15 +0000696 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
697 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
698 || subsamp>=NUMSUBOPT)
699 _throw("tjEncodeYUV2(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000700
DRC9b28def2011-05-21 14:37:15 +0000701 if(setjmp(this->jerr.setjmp_buffer))
702 {
703 /* If we get here, the JPEG code has signaled an error. */
704 retval=-1;
705 goto bailout;
706 }
DRC2e7b76b2009-04-03 12:04:24 +0000707
DRC9b28def2011-05-21 14:37:15 +0000708 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC2e7b76b2009-04-03 12:04:24 +0000709
DRCafc06922012-03-23 19:47:57 +0000710 #ifndef JCS_EXTENSIONS
711 if(pixelFormat!=TJPF_GRAY)
712 {
713 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
714 if(!rgbBuf) _throw("tjEncodeYUV2(): Memory allocation failure");
715 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
716 pitch=width*RGB_PIXELSIZE;
717 }
718 #endif
719
DRC9b28def2011-05-21 14:37:15 +0000720 cinfo->image_width=width;
721 cinfo->image_height=height;
DRC2e7b76b2009-04-03 12:04:24 +0000722
DRC25b995a2011-05-21 15:34:54 +0000723 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
724 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
725 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000726
DRC9b49f0e2011-07-12 03:17:23 +0000727 yuvsize=tjBufSizeYUV(width, height, subsamp);
DRC9b28def2011-05-21 14:37:15 +0000728 jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0);
DRCf12bb302011-09-07 05:03:18 +0000729 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1)==-1) return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000730
DRC9b28def2011-05-21 14:37:15 +0000731 jpeg_start_compress(cinfo, TRUE);
732 pw=PAD(width, cinfo->max_h_samp_factor);
733 ph=PAD(height, cinfo->max_v_samp_factor);
DRC2e7b76b2009-04-03 12:04:24 +0000734
DRC9b28def2011-05-21 14:37:15 +0000735 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000736 _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000737 for(i=0; i<height; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000738 {
DRC25b995a2011-05-21 15:34:54 +0000739 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000740 else row_pointer[i]=&srcBuf[i*pitch];
741 }
742 if(height<ph)
743 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
DRCfbb67472010-11-24 04:02:37 +0000744
DRC9b28def2011-05-21 14:37:15 +0000745 for(i=0; i<cinfo->num_components; i++)
746 {
747 compptr=&cinfo->comp_info[i];
748 _tmpbuf[i]=(JSAMPLE *)malloc(
749 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
750 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRC007a42c2011-05-22 13:55:56 +0000751 if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000752 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRC007a42c2011-05-22 13:55:56 +0000753 if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000754 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRCfbb67472010-11-24 04:02:37 +0000755 {
DRC9b28def2011-05-21 14:37:15 +0000756 unsigned char *_tmpbuf_aligned=
757 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
758 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000759 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC9b28def2011-05-21 14:37:15 +0000760 /compptr->h_samp_factor, 16) * row];
DRCfbb67472010-11-24 04:02:37 +0000761 }
DRC9b28def2011-05-21 14:37:15 +0000762 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
763 * compptr->v_samp_factor + 16);
DRC007a42c2011-05-22 13:55:56 +0000764 if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000765 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRC007a42c2011-05-22 13:55:56 +0000766 if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000767 for(row=0; row<compptr->v_samp_factor; row++)
768 {
769 unsigned char *_tmpbuf2_aligned=
770 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
771 tmpbuf2[i][row]=&_tmpbuf2_aligned[
772 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
773 }
774 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
775 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
776 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
DRC007a42c2011-05-22 13:55:56 +0000777 if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000778 for(row=0; row<ch[i]; row++)
779 {
780 outbuf[i][row]=ptr;
781 ptr+=PAD(cw[i], 4);
782 }
783 }
784 if(yuvsize!=(unsigned long)(ptr-dstBuf))
785 _throw("tjEncodeYUV2(): Generated image is not the correct size");
DRCfbb67472010-11-24 04:02:37 +0000786
DRC9b28def2011-05-21 14:37:15 +0000787 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
DRCfbb67472010-11-24 04:02:37 +0000788 {
DRC9b28def2011-05-21 14:37:15 +0000789 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
790 cinfo->max_v_samp_factor);
791 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
792 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
793 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
794 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
795 compptr->v_samp_factor, cw[i]);
DRC6ee54592011-03-01 08:18:30 +0000796 }
DRC9b28def2011-05-21 14:37:15 +0000797 cinfo->next_scanline+=height;
798 jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000799
DRC91e86ba2011-02-15 05:24:08 +0000800 bailout:
DRC9b28def2011-05-21 14:37:15 +0000801 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000802 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000803 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000804 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000805 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000806 for(i=0; i<MAX_COMPONENTS; i++)
807 {
808 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000809 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000810 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000811 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000812 if(outbuf[i]!=NULL) free(outbuf[i]);
813 }
DRC91e86ba2011-02-15 05:24:08 +0000814 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000815}
816
DRC9b28def2011-05-21 14:37:15 +0000817DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
818 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
819 int subsamp, int flags)
DRC84241602011-02-25 02:08:23 +0000820{
DRC9b28def2011-05-21 14:37:15 +0000821 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
822 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
DRC84241602011-02-25 02:08:23 +0000823}
824
825
DRC9b28def2011-05-21 14:37:15 +0000826/* Decompressor */
DRC2e7b76b2009-04-03 12:04:24 +0000827
DRC9b28def2011-05-21 14:37:15 +0000828static tjhandle _tjInitDecompress(tjinstance *this)
DRC2e7b76b2009-04-03 12:04:24 +0000829{
DRC9b28def2011-05-21 14:37:15 +0000830 unsigned char buffer[1];
DRC2e7b76b2009-04-03 12:04:24 +0000831
DRC9b28def2011-05-21 14:37:15 +0000832 /* This is also straight out of example.c */
833 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
834 this->jerr.pub.error_exit=my_error_exit;
835 this->jerr.pub.output_message=my_output_message;
DRC2e7b76b2009-04-03 12:04:24 +0000836
DRC9b28def2011-05-21 14:37:15 +0000837 if(setjmp(this->jerr.setjmp_buffer))
838 {
839 /* If we get here, the JPEG code has signaled an error. */
840 if(this) free(this); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +0000841 }
DRC2e7b76b2009-04-03 12:04:24 +0000842
DRC9b28def2011-05-21 14:37:15 +0000843 jpeg_create_decompress(&this->dinfo);
844 /* Make an initial call so it will create the source manager */
845 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +0000846
DRC007a42c2011-05-22 13:55:56 +0000847 this->init|=DECOMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000848 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000849}
850
DRC890f1e02011-02-26 22:02:37 +0000851DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
852{
DRC9b28def2011-05-21 14:37:15 +0000853 tjinstance *this;
854 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000855 {
DRC007a42c2011-05-22 13:55:56 +0000856 snprintf(errStr, JMSG_LENGTH_MAX,
857 "tjInitDecompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000858 return NULL;
859 }
DRC007a42c2011-05-22 13:55:56 +0000860 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000861 return _tjInitDecompress(this);
DRC890f1e02011-02-26 22:02:37 +0000862}
863
DRC2e7b76b2009-04-03 12:04:24 +0000864
DRC9b28def2011-05-21 14:37:15 +0000865DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
866 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
867 int *jpegSubsamp)
DRC1fe80f82010-12-14 01:21:29 +0000868{
DRC9b49f0e2011-07-12 03:17:23 +0000869 int retval=0;
DRC1fe80f82010-12-14 01:21:29 +0000870
DRC9b28def2011-05-21 14:37:15 +0000871 getinstance(handle);
872 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000873 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
DRC1fe80f82010-12-14 01:21:29 +0000874
DRC9b28def2011-05-21 14:37:15 +0000875 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
876 || jpegSubsamp==NULL)
877 _throw("tjDecompressHeader2(): Invalid argument");
DRC1fe80f82010-12-14 01:21:29 +0000878
DRC9b28def2011-05-21 14:37:15 +0000879 if(setjmp(this->jerr.setjmp_buffer))
880 {
881 /* If we get here, the JPEG code has signaled an error. */
DRC1fe80f82010-12-14 01:21:29 +0000882 return -1;
883 }
884
DRC9b28def2011-05-21 14:37:15 +0000885 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
886 jpeg_read_header(dinfo, TRUE);
DRC1fe80f82010-12-14 01:21:29 +0000887
DRC9b28def2011-05-21 14:37:15 +0000888 *width=dinfo->image_width;
889 *height=dinfo->image_height;
DRC9b49f0e2011-07-12 03:17:23 +0000890 *jpegSubsamp=getSubsamp(dinfo);
DRC1fe80f82010-12-14 01:21:29 +0000891
DRC9b28def2011-05-21 14:37:15 +0000892 jpeg_abort_decompress(dinfo);
DRC1fe80f82010-12-14 01:21:29 +0000893
DRC9b28def2011-05-21 14:37:15 +0000894 if(*jpegSubsamp<0)
DRC007a42c2011-05-22 13:55:56 +0000895 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
896 if(*width<1 || *height<1)
897 _throw("tjDecompressHeader2(): Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +0000898
899 bailout:
900 return retval;
901}
902
DRC9b28def2011-05-21 14:37:15 +0000903DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
904 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
DRC91e86ba2011-02-15 05:24:08 +0000905{
DRC9b28def2011-05-21 14:37:15 +0000906 int jpegSubsamp;
907 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
908 &jpegSubsamp);
DRC1fe80f82010-12-14 01:21:29 +0000909}
910
911
DRC109a5782011-03-01 09:53:07 +0000912DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +0000913{
DRC109a5782011-03-01 09:53:07 +0000914 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +0000915 {
DRC9b28def2011-05-21 14:37:15 +0000916 snprintf(errStr, JMSG_LENGTH_MAX,
DRC007a42c2011-05-22 13:55:56 +0000917 "tjGetScalingFactors(): Invalid argument");
DRC109a5782011-03-01 09:53:07 +0000918 return NULL;
DRCb28fc572011-02-22 06:41:29 +0000919 }
920
DRC109a5782011-03-01 09:53:07 +0000921 *numscalingfactors=NUMSF;
922 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +0000923}
924
925
DRC9b28def2011-05-21 14:37:15 +0000926DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
927 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
928 int height, int pixelFormat, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000929{
DRC9b28def2011-05-21 14:37:15 +0000930 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRC109a5782011-03-01 09:53:07 +0000931 int jpegwidth, jpegheight, scaledw, scaledh;
DRCafc06922012-03-23 19:47:57 +0000932 #ifndef JCS_EXTENSIONS
933 unsigned char *rgbBuf=NULL;
934 unsigned char *_dstBuf=NULL; int _pitch=0;
935 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000936
DRC9b28def2011-05-21 14:37:15 +0000937 getinstance(handle);
938 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000939 _throw("tjDecompress2(): Instance has not been initialized for decompression");
DRC9b28def2011-05-21 14:37:15 +0000940
941 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
942 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
943 _throw("tjDecompress2(): Invalid argument");
944
DRC25b995a2011-05-21 15:34:54 +0000945 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
946 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
947 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000948
949 if(setjmp(this->jerr.setjmp_buffer))
950 {
951 /* If we get here, the JPEG code has signaled an error. */
952 retval=-1;
953 goto bailout;
954 }
955
956 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
957 jpeg_read_header(dinfo, TRUE);
DRC2eda8212012-03-23 19:32:38 +0000958 if(setDecompDefaults(dinfo, pixelFormat)==-1)
959 {
960 retval=-1; goto bailout;
961 }
DRC9b28def2011-05-21 14:37:15 +0000962
DRC25b995a2011-05-21 15:34:54 +0000963 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +0000964
965 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
966 if(width==0) width=jpegwidth;
967 if(height==0) height=jpegheight;
968 for(i=0; i<NUMSF; i++)
969 {
970 scaledw=TJSCALED(jpegwidth, sf[i]);
971 scaledh=TJSCALED(jpegheight, sf[i]);
972 if(scaledw<=width && scaledh<=height)
973 break;
974 }
975 if(scaledw>width || scaledh>height)
DRC007a42c2011-05-22 13:55:56 +0000976 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
DRC9b28def2011-05-21 14:37:15 +0000977 width=scaledw; height=scaledh;
978 dinfo->scale_num=sf[i].num;
979 dinfo->scale_denom=sf[i].denom;
980
981 jpeg_start_decompress(dinfo);
982 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
DRCafc06922012-03-23 19:47:57 +0000983
984 #ifndef JCS_EXTENSIONS
985 if(pixelFormat!=TJPF_GRAY &&
986 (RGB_RED!=tjRedOffset[pixelFormat] ||
987 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
988 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
989 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
990 {
991 rgbBuf=(unsigned char *)malloc(width*height*3);
992 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
993 _pitch=pitch; pitch=width*3;
994 _dstBuf=dstBuf; dstBuf=rgbBuf;
995 }
996 #endif
997
DRC9b28def2011-05-21 14:37:15 +0000998 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
999 *dinfo->output_height))==NULL)
DRC007a42c2011-05-22 13:55:56 +00001000 _throw("tjDecompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001001 for(i=0; i<(int)dinfo->output_height; i++)
1002 {
DRC25b995a2011-05-21 15:34:54 +00001003 if(flags&TJFLAG_BOTTOMUP)
DRC9b28def2011-05-21 14:37:15 +00001004 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1005 else row_pointer[i]=&dstBuf[i*pitch];
1006 }
1007 while(dinfo->output_scanline<dinfo->output_height)
1008 {
1009 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1010 dinfo->output_height-dinfo->output_scanline);
1011 }
1012 jpeg_finish_decompress(dinfo);
1013
DRCafc06922012-03-23 19:47:57 +00001014 #ifndef JCS_EXTENSIONS
1015 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1016 #endif
1017
DRC9b28def2011-05-21 14:37:15 +00001018 bailout:
1019 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRCafc06922012-03-23 19:47:57 +00001020 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +00001021 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +00001022 #endif
DRC9b28def2011-05-21 14:37:15 +00001023 if(row_pointer) free(row_pointer);
1024 return retval;
1025}
1026
1027DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1028 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1029 int height, int pixelSize, int flags)
1030{
1031 if(flags&TJ_YUV)
1032 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1033 else
1034 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1035 height, getPixelFormat(pixelSize, flags), flags);
1036}
1037
1038
1039DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1040 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1041 int flags)
1042{
1043 int i, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
1044 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1045 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1046 JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS];
1047
1048 getinstance(handle);
1049 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001050 _throw("tjDecompressToYUV(): Instance has not been initialized for decompression");
DRC2e7b76b2009-04-03 12:04:24 +00001051
DRCf9cf5c72010-12-10 10:58:49 +00001052 for(i=0; i<MAX_COMPONENTS; i++)
1053 {
1054 tmpbuf[i]=NULL; outbuf[i]=NULL;
1055 }
DRC9e17f7d2010-12-10 04:59:13 +00001056
DRC9b28def2011-05-21 14:37:15 +00001057 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
1058 _throw("tjDecompressToYUV(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001059
DRC25b995a2011-05-21 15:34:54 +00001060 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1061 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1062 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +00001063
DRC9b28def2011-05-21 14:37:15 +00001064 if(setjmp(this->jerr.setjmp_buffer))
1065 {
1066 /* If we get here, the JPEG code has signaled an error. */
DRC91e86ba2011-02-15 05:24:08 +00001067 retval=-1;
1068 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +00001069 }
DRC2e7b76b2009-04-03 12:04:24 +00001070
DRC9b28def2011-05-21 14:37:15 +00001071 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1072 jpeg_read_header(dinfo, TRUE);
DRC2e7b76b2009-04-03 12:04:24 +00001073
DRC9b28def2011-05-21 14:37:15 +00001074 for(i=0; i<dinfo->num_components; i++)
DRC2e7b76b2009-04-03 12:04:24 +00001075 {
DRC9b28def2011-05-21 14:37:15 +00001076 jpeg_component_info *compptr=&dinfo->comp_info[i];
1077 int ih;
1078 iw[i]=compptr->width_in_blocks*DCTSIZE;
1079 ih=compptr->height_in_blocks*DCTSIZE;
1080 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
1081 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
1082 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
1083 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
1084 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
1085 th[i]=compptr->v_samp_factor*DCTSIZE;
1086 tmpbufsize+=iw[i]*th[i];
1087 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
DRC007a42c2011-05-22 13:55:56 +00001088 _throw("tjDecompressToYUV(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001089 for(row=0; row<ch[i]; row++)
1090 {
1091 outbuf[i][row]=ptr;
1092 ptr+=PAD(cw[i], 4);
1093 }
1094 }
1095 if(usetmpbuf)
1096 {
1097 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRC007a42c2011-05-22 13:55:56 +00001098 _throw("tjDecompressToYUV(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001099 ptr=_tmpbuf;
1100 for(i=0; i<dinfo->num_components; i++)
1101 {
1102 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRC007a42c2011-05-22 13:55:56 +00001103 _throw("tjDecompressToYUV(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001104 for(row=0; row<th[i]; row++)
1105 {
1106 tmpbuf[i][row]=ptr;
1107 ptr+=iw[i];
1108 }
1109 }
1110 }
DRC9e17f7d2010-12-10 04:59:13 +00001111
DRC25b995a2011-05-21 15:34:54 +00001112 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +00001113 dinfo->raw_data_out=TRUE;
1114
1115 jpeg_start_decompress(dinfo);
1116 for(row=0; row<(int)dinfo->output_height;
1117 row+=dinfo->max_v_samp_factor*DCTSIZE)
1118 {
1119 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1120 int crow[MAX_COMPONENTS];
DRC9e17f7d2010-12-10 04:59:13 +00001121 for(i=0; i<dinfo->num_components; i++)
1122 {
1123 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRC9b28def2011-05-21 14:37:15 +00001124 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1125 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1126 else yuvptr[i]=&outbuf[i][crow[i]];
DRCf9cf5c72010-12-10 10:58:49 +00001127 }
DRC9b28def2011-05-21 14:37:15 +00001128 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
DRCf9cf5c72010-12-10 10:58:49 +00001129 if(usetmpbuf)
1130 {
DRC9b28def2011-05-21 14:37:15 +00001131 int j;
DRCf9cf5c72010-12-10 10:58:49 +00001132 for(i=0; i<dinfo->num_components; i++)
1133 {
DRC9b28def2011-05-21 14:37:15 +00001134 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +00001135 {
DRC9b28def2011-05-21 14:37:15 +00001136 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001137 }
DRC9e17f7d2010-12-10 04:59:13 +00001138 }
1139 }
1140 }
DRC9b28def2011-05-21 14:37:15 +00001141 jpeg_finish_decompress(dinfo);
DRC2e7b76b2009-04-03 12:04:24 +00001142
DRC91e86ba2011-02-15 05:24:08 +00001143 bailout:
DRC9b28def2011-05-21 14:37:15 +00001144 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC9e17f7d2010-12-10 04:59:13 +00001145 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +00001146 {
1147 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +00001148 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001149 }
1150 if(_tmpbuf) free(_tmpbuf);
DRC91e86ba2011-02-15 05:24:08 +00001151 return retval;
DRC2e7b76b2009-04-03 12:04:24 +00001152}
1153
1154
DRC9b28def2011-05-21 14:37:15 +00001155/* Transformer */
DRC890f1e02011-02-26 22:02:37 +00001156
1157DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1158{
DRC9b28def2011-05-21 14:37:15 +00001159 tjinstance *this=NULL; tjhandle handle=NULL;
1160 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00001161 {
DRC007a42c2011-05-22 13:55:56 +00001162 snprintf(errStr, JMSG_LENGTH_MAX,
1163 "tjInitTransform(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00001164 return NULL;
1165 }
DRC007a42c2011-05-22 13:55:56 +00001166 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +00001167 handle=_tjInitCompress(this);
1168 if(!handle) return NULL;
1169 handle=_tjInitDecompress(this);
1170 return handle;
DRC890f1e02011-02-26 22:02:37 +00001171}
1172
1173
DRC9b28def2011-05-21 14:37:15 +00001174DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1175 unsigned long jpegSize, int n, unsigned char **dstBufs,
1176 unsigned long *dstSizes, tjtransform *t, int flags)
DRC890f1e02011-02-26 22:02:37 +00001177{
DRC0a325192011-03-02 09:22:41 +00001178 jpeg_transform_info *xinfo=NULL;
DRC890f1e02011-02-26 22:02:37 +00001179 jvirt_barray_ptr *srccoefs, *dstcoefs;
DRC9b49f0e2011-07-12 03:17:23 +00001180 int retval=0, i, jpegSubsamp;
DRC890f1e02011-02-26 22:02:37 +00001181
DRC9b28def2011-05-21 14:37:15 +00001182 getinstance(handle);
1183 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001184 _throw("tjTransform(): Instance has not been initialized for transformation");
DRC890f1e02011-02-26 22:02:37 +00001185
DRC9b28def2011-05-21 14:37:15 +00001186 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1187 || t==NULL || flags<0)
1188 _throw("tjTransform(): Invalid argument");
1189
DRC25b995a2011-05-21 15:34:54 +00001190 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1191 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1192 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC890f1e02011-02-26 22:02:37 +00001193
DRC9b28def2011-05-21 14:37:15 +00001194 if(setjmp(this->jerr.setjmp_buffer))
1195 {
1196 /* If we get here, the JPEG code has signaled an error. */
DRC890f1e02011-02-26 22:02:37 +00001197 retval=-1;
1198 goto bailout;
1199 }
1200
DRC9b28def2011-05-21 14:37:15 +00001201 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
DRC890f1e02011-02-26 22:02:37 +00001202
DRC0a325192011-03-02 09:22:41 +00001203 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1204 ==NULL)
DRC007a42c2011-05-22 13:55:56 +00001205 _throw("tjTransform(): Memory allocation failure");
1206 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
DRC890f1e02011-02-26 22:02:37 +00001207
DRC0a325192011-03-02 09:22:41 +00001208 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001209 {
DRC0a325192011-03-02 09:22:41 +00001210 xinfo[i].transform=xformtypes[t[i].op];
DRC25b995a2011-05-21 15:34:54 +00001211 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1212 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1213 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1214 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1215 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
DRCba5ea512011-03-04 03:20:34 +00001216 else xinfo[i].slow_hflip=0;
DRC0a325192011-03-02 09:22:41 +00001217
1218 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001219 {
DRC0a325192011-03-02 09:22:41 +00001220 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
1221 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
1222 if(t[i].r.w!=0)
1223 {
1224 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
1225 }
DRCd932e582011-03-15 20:09:47 +00001226 else xinfo[i].crop_width=JCROP_UNSET;
DRC0a325192011-03-02 09:22:41 +00001227 if(t[i].r.h!=0)
1228 {
1229 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
1230 }
DRCd932e582011-03-15 20:09:47 +00001231 else xinfo[i].crop_height=JCROP_UNSET;
DRC890f1e02011-02-26 22:02:37 +00001232 }
1233 }
1234
DRC9b28def2011-05-21 14:37:15 +00001235 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1236 jpeg_read_header(dinfo, TRUE);
DRC9b49f0e2011-07-12 03:17:23 +00001237 jpegSubsamp=getSubsamp(dinfo);
1238 if(jpegSubsamp<0)
1239 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC890f1e02011-02-26 22:02:37 +00001240
DRC0a325192011-03-02 09:22:41 +00001241 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001242 {
DRC9b28def2011-05-21 14:37:15 +00001243 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
DRC007a42c2011-05-22 13:55:56 +00001244 _throw("tjTransform(): Transform is not perfect");
DRC890f1e02011-02-26 22:02:37 +00001245
DRC0a325192011-03-02 09:22:41 +00001246 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001247 {
DRC0a325192011-03-02 09:22:41 +00001248 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1249 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1250 {
DRC9b28def2011-05-21 14:37:15 +00001251 snprintf(errStr, JMSG_LENGTH_MAX,
DRC0a325192011-03-02 09:22:41 +00001252 "To crop this JPEG image, x must be a multiple of %d\n"
1253 "and y must be a multiple of %d.\n",
1254 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1255 retval=-1; goto bailout;
1256 }
DRC890f1e02011-02-26 22:02:37 +00001257 }
1258 }
1259
DRC9b28def2011-05-21 14:37:15 +00001260 srccoefs=jpeg_read_coefficients(dinfo);
DRC890f1e02011-02-26 22:02:37 +00001261
DRC0a325192011-03-02 09:22:41 +00001262 for(i=0; i<n; i++)
1263 {
DRCff78e372011-05-24 10:17:32 +00001264 int w, h, alloc=1;
DRC0a325192011-03-02 09:22:41 +00001265 if(!xinfo[i].crop)
1266 {
DRC9b28def2011-05-21 14:37:15 +00001267 w=dinfo->image_width; h=dinfo->image_height;
DRC0a325192011-03-02 09:22:41 +00001268 }
1269 else
1270 {
1271 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
1272 }
DRCff78e372011-05-24 10:17:32 +00001273 if(flags&TJFLAG_NOREALLOC)
1274 {
DRC9b49f0e2011-07-12 03:17:23 +00001275 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +00001276 }
DRC7bf04d32011-09-17 00:18:31 +00001277 if(!(t[i].options&TJXOPT_NOOUTPUT))
1278 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
DRC9b28def2011-05-21 14:37:15 +00001279 jpeg_copy_critical_parameters(dinfo, cinfo);
1280 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00001281 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00001282 if(!(t[i].options&TJXOPT_NOOUTPUT))
1283 {
1284 jpeg_write_coefficients(cinfo, dstcoefs);
1285 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1286 }
1287 else jinit_c_master_control(cinfo, TRUE);
DRC9b28def2011-05-21 14:37:15 +00001288 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00001289 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00001290 if(t[i].customFilter)
1291 {
DRCefe28ce2012-01-17 11:48:38 +00001292 int ci, y; JDIMENSION by;
DRC7bf04d32011-09-17 00:18:31 +00001293 for(ci=0; ci<cinfo->num_components; ci++)
1294 {
1295 jpeg_component_info *compptr=&cinfo->comp_info[ci];
1296 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1297 DCTSIZE};
1298 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1299 compptr->height_in_blocks*DCTSIZE};
1300 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1301 {
1302 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1303 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1304 TRUE);
1305 for(y=0; y<compptr->v_samp_factor; y++)
1306 {
1307 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
DRCf5467112011-09-20 05:02:19 +00001308 ci, i, &t[i])==-1)
DRC7bf04d32011-09-17 00:18:31 +00001309 _throw("tjTransform(): Error in custom filter");
1310 arrayRegion.y+=DCTSIZE;
1311 }
1312 }
1313 }
1314 }
1315 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
DRC0a325192011-03-02 09:22:41 +00001316 }
1317
DRC9b28def2011-05-21 14:37:15 +00001318 jpeg_finish_decompress(dinfo);
DRC890f1e02011-02-26 22:02:37 +00001319
DRC890f1e02011-02-26 22:02:37 +00001320 bailout:
DRC9b28def2011-05-21 14:37:15 +00001321 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1322 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC0a325192011-03-02 09:22:41 +00001323 if(xinfo) free(xinfo);
DRC890f1e02011-02-26 22:02:37 +00001324 return retval;
1325}