blob: 94918c99174007bc655d45b0da88311588562556 [file] [log] [blame]
DRC9b28def2011-05-21 14:37:15 +00001/*
DRCf610d612013-04-26 10:33:29 +00002 * Copyright (C)2009-2013 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
DRCbdfcb742013-01-22 13:56:34 +000029/* TurboJPEG/LJT: this implements the TurboJPEG API using libjpeg or
30 libjpeg-turbo */
DRC2e7b76b2009-04-03 12:04:24 +000031
32#include <stdio.h>
33#include <stdlib.h>
DRC296c71b2011-05-25 04:12:52 +000034#include <jinclude.h>
DRCfbb67472010-11-24 04:02:37 +000035#define JPEG_INTERNALS
DRC2e7b76b2009-04-03 12:04:24 +000036#include <jpeglib.h>
37#include <jerror.h>
38#include <setjmp.h>
39#include "./turbojpeg.h"
DRCa29294a2011-05-24 09:17:57 +000040#include "./tjutil.h"
DRC890f1e02011-02-26 22:02:37 +000041#include "transupp.h"
DRC418fe282013-05-07 21:17:35 +000042#include "./jpegcomp.h"
DRC2a2e4512011-01-05 22:33:24 +000043
DRC9b28def2011-05-21 14:37:15 +000044extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
45 unsigned long *, boolean);
46extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
47
DRCfbb67472010-11-24 04:02:37 +000048#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
DRCf610d612013-04-26 10:33:29 +000049#define isPow2(x) (((x)&(x-1))==0)
DRC2e7b76b2009-04-03 12:04:24 +000050
51
DRC9b28def2011-05-21 14:37:15 +000052/* Error handling (based on example in example.c) */
DRC2e7b76b2009-04-03 12:04:24 +000053
DRC9b28def2011-05-21 14:37:15 +000054static char errStr[JMSG_LENGTH_MAX]="No error";
DRC2e7b76b2009-04-03 12:04:24 +000055
DRC9b28def2011-05-21 14:37:15 +000056struct my_error_mgr
DRC2e7b76b2009-04-03 12:04:24 +000057{
58 struct jpeg_error_mgr pub;
DRC9b28def2011-05-21 14:37:15 +000059 jmp_buf setjmp_buffer;
60};
61typedef struct my_error_mgr *my_error_ptr;
DRC2e7b76b2009-04-03 12:04:24 +000062
63static void my_error_exit(j_common_ptr cinfo)
64{
DRC9b28def2011-05-21 14:37:15 +000065 my_error_ptr myerr=(my_error_ptr)cinfo->err;
DRC2e7b76b2009-04-03 12:04:24 +000066 (*cinfo->err->output_message)(cinfo);
DRC9b28def2011-05-21 14:37:15 +000067 longjmp(myerr->setjmp_buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +000068}
69
DRC9b28def2011-05-21 14:37:15 +000070/* Based on output_message() in jerror.c */
71
DRC2e7b76b2009-04-03 12:04:24 +000072static void my_output_message(j_common_ptr cinfo)
73{
DRC9b28def2011-05-21 14:37:15 +000074 (*cinfo->err->format_message)(cinfo, errStr);
DRC2e7b76b2009-04-03 12:04:24 +000075}
76
77
DRC9b28def2011-05-21 14:37:15 +000078/* Global structures, macros, etc. */
DRC2e7b76b2009-04-03 12:04:24 +000079
DRC9b28def2011-05-21 14:37:15 +000080enum {COMPRESS=1, DECOMPRESS=2};
81
82typedef struct _tjinstance
DRC2e7b76b2009-04-03 12:04:24 +000083{
84 struct jpeg_compress_struct cinfo;
85 struct jpeg_decompress_struct dinfo;
DRC9b28def2011-05-21 14:37:15 +000086 struct my_error_mgr jerr;
87 int init;
88} tjinstance;
DRC2e7b76b2009-04-03 12:04:24 +000089
DRC1f3635c2013-08-18 10:19:00 +000090static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};
DRC9b28def2011-05-21 14:37:15 +000091
DRC007a42c2011-05-22 13:55:56 +000092static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
93{
DRC890f1e02011-02-26 22:02:37 +000094 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
95 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
96};
DRC9b28def2011-05-21 14:37:15 +000097
DRCab2df6e2012-01-28 06:49:56 +000098#define NUMSF 16
DRC109a5782011-03-01 09:53:07 +000099static const tjscalingfactor sf[NUMSF]={
DRCab2df6e2012-01-28 06:49:56 +0000100 {2, 1},
101 {15, 8},
102 {7, 4},
103 {13, 8},
104 {3, 2},
105 {11, 8},
106 {5, 4},
107 {9, 8},
DRC109a5782011-03-01 09:53:07 +0000108 {1, 1},
DRCab2df6e2012-01-28 06:49:56 +0000109 {7, 8},
110 {3, 4},
111 {5, 8},
DRC109a5782011-03-01 09:53:07 +0000112 {1, 2},
DRCab2df6e2012-01-28 06:49:56 +0000113 {3, 8},
DRC109a5782011-03-01 09:53:07 +0000114 {1, 4},
115 {1, 8}
116};
DRC2e7b76b2009-04-03 12:04:24 +0000117
DRCa29294a2011-05-24 09:17:57 +0000118#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
DRCda5220a2011-03-02 02:17:30 +0000119 retval=-1; goto bailout;}
DRC9b28def2011-05-21 14:37:15 +0000120#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
121 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
122 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
123 return -1;} \
124 cinfo=&this->cinfo; dinfo=&this->dinfo;
DRC2e7b76b2009-04-03 12:04:24 +0000125
DRC9b28def2011-05-21 14:37:15 +0000126static int getPixelFormat(int pixelSize, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000127{
DRC25b995a2011-05-21 15:34:54 +0000128 if(pixelSize==1) return TJPF_GRAY;
DRC9b28def2011-05-21 14:37:15 +0000129 if(pixelSize==3)
130 {
DRC25b995a2011-05-21 15:34:54 +0000131 if(flags&TJ_BGR) return TJPF_BGR;
132 else return TJPF_RGB;
DRC9b28def2011-05-21 14:37:15 +0000133 }
134 if(pixelSize==4)
135 {
136 if(flags&TJ_ALPHAFIRST)
137 {
DRC25b995a2011-05-21 15:34:54 +0000138 if(flags&TJ_BGR) return TJPF_XBGR;
139 else return TJPF_XRGB;
DRC9b28def2011-05-21 14:37:15 +0000140 }
141 else
142 {
DRC25b995a2011-05-21 15:34:54 +0000143 if(flags&TJ_BGR) return TJPF_BGRX;
144 else return TJPF_RGBX;
DRC9b28def2011-05-21 14:37:15 +0000145 }
146 }
147 return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000148}
149
DRCf12bb302011-09-07 05:03:18 +0000150static int setCompDefaults(struct jpeg_compress_struct *cinfo,
DRC73d74c12012-06-29 23:46:38 +0000151 int pixelFormat, int subsamp, int jpegQual, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000152{
DRCf12bb302011-09-07 05:03:18 +0000153 int retval=0;
154
DRC9b28def2011-05-21 14:37:15 +0000155 switch(pixelFormat)
156 {
DRC25b995a2011-05-21 15:34:54 +0000157 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000158 cinfo->in_color_space=JCS_GRAYSCALE; break;
159 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000160 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000161 cinfo->in_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000162 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000163 cinfo->in_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000164 case TJPF_RGBX:
DRC67ce3b22011-12-19 02:21:03 +0000165 case TJPF_RGBA:
DRC9b28def2011-05-21 14:37:15 +0000166 cinfo->in_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000167 case TJPF_BGRX:
DRC67ce3b22011-12-19 02:21:03 +0000168 case TJPF_BGRA:
DRC9b28def2011-05-21 14:37:15 +0000169 cinfo->in_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000170 case TJPF_XRGB:
DRC67ce3b22011-12-19 02:21:03 +0000171 case TJPF_ARGB:
DRC9b28def2011-05-21 14:37:15 +0000172 cinfo->in_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000173 case TJPF_XBGR:
DRC67ce3b22011-12-19 02:21:03 +0000174 case TJPF_ABGR:
DRC9b28def2011-05-21 14:37:15 +0000175 cinfo->in_color_space=JCS_EXT_XBGR; break;
176 #else
DRC25b995a2011-05-21 15:34:54 +0000177 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000178 case TJPF_BGR:
179 case TJPF_RGBX:
180 case TJPF_BGRX:
181 case TJPF_XRGB:
182 case TJPF_XBGR:
183 case TJPF_RGBA:
184 case TJPF_BGRA:
185 case TJPF_ARGB:
186 case TJPF_ABGR:
187 cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
188 break;
DRC9b28def2011-05-21 14:37:15 +0000189 #endif
DRCefa4ddc2010-10-13 19:22:50 +0000190 }
DRC2e7b76b2009-04-03 12:04:24 +0000191
DRC9b28def2011-05-21 14:37:15 +0000192 cinfo->input_components=tjPixelSize[pixelFormat];
193 jpeg_set_defaults(cinfo);
194 if(jpegQual>=0)
195 {
196 jpeg_set_quality(cinfo, jpegQual, TRUE);
DRC73d74c12012-06-29 23:46:38 +0000197 if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
DRC9b28def2011-05-21 14:37:15 +0000198 else cinfo->dct_method=JDCT_FASTEST;
199 }
DRC25b995a2011-05-21 15:34:54 +0000200 if(subsamp==TJSAMP_GRAY)
DRC9b28def2011-05-21 14:37:15 +0000201 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
202 else
203 jpeg_set_colorspace(cinfo, JCS_YCbCr);
DRC2e7b76b2009-04-03 12:04:24 +0000204
DRC9b28def2011-05-21 14:37:15 +0000205 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
206 cinfo->comp_info[1].h_samp_factor=1;
207 cinfo->comp_info[2].h_samp_factor=1;
208 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
209 cinfo->comp_info[1].v_samp_factor=1;
210 cinfo->comp_info[2].v_samp_factor=1;
DRCf12bb302011-09-07 05:03:18 +0000211
DRCf12bb302011-09-07 05:03:18 +0000212 return retval;
DRC9b28def2011-05-21 14:37:15 +0000213}
214
DRCf12bb302011-09-07 05:03:18 +0000215static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
DRC73d74c12012-06-29 23:46:38 +0000216 int pixelFormat, int flags)
DRC9b28def2011-05-21 14:37:15 +0000217{
DRCf12bb302011-09-07 05:03:18 +0000218 int retval=0;
219
DRC9b28def2011-05-21 14:37:15 +0000220 switch(pixelFormat)
221 {
DRC25b995a2011-05-21 15:34:54 +0000222 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000223 dinfo->out_color_space=JCS_GRAYSCALE; break;
224 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000225 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000226 dinfo->out_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000227 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000228 dinfo->out_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000229 case TJPF_RGBX:
DRC9b28def2011-05-21 14:37:15 +0000230 dinfo->out_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000231 case TJPF_BGRX:
DRC9b28def2011-05-21 14:37:15 +0000232 dinfo->out_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000233 case TJPF_XRGB:
DRC9b28def2011-05-21 14:37:15 +0000234 dinfo->out_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000235 case TJPF_XBGR:
DRC9b28def2011-05-21 14:37:15 +0000236 dinfo->out_color_space=JCS_EXT_XBGR; break;
DRC67ce3b22011-12-19 02:21:03 +0000237 #if JCS_ALPHA_EXTENSIONS==1
238 case TJPF_RGBA:
239 dinfo->out_color_space=JCS_EXT_RGBA; break;
240 case TJPF_BGRA:
241 dinfo->out_color_space=JCS_EXT_BGRA; break;
242 case TJPF_ARGB:
243 dinfo->out_color_space=JCS_EXT_ARGB; break;
244 case TJPF_ABGR:
245 dinfo->out_color_space=JCS_EXT_ABGR; break;
246 #endif
DRC9b28def2011-05-21 14:37:15 +0000247 #else
DRC25b995a2011-05-21 15:34:54 +0000248 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000249 case TJPF_BGR:
250 case TJPF_RGBX:
251 case TJPF_BGRX:
252 case TJPF_XRGB:
253 case TJPF_XBGR:
254 case TJPF_RGBA:
255 case TJPF_BGRA:
256 case TJPF_ARGB:
257 case TJPF_ABGR:
258 dinfo->out_color_space=JCS_RGB; break;
DRC67ce3b22011-12-19 02:21:03 +0000259 #endif
DRC9b28def2011-05-21 14:37:15 +0000260 default:
261 _throw("Unsupported pixel format");
DRC9b28def2011-05-21 14:37:15 +0000262 }
DRCf12bb302011-09-07 05:03:18 +0000263
DRC73d74c12012-06-29 23:46:38 +0000264 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
265
DRCf12bb302011-09-07 05:03:18 +0000266 bailout:
DRCf12bb302011-09-07 05:03:18 +0000267 return retval;
DRC9b28def2011-05-21 14:37:15 +0000268}
269
270
DRC9b49f0e2011-07-12 03:17:23 +0000271static int getSubsamp(j_decompress_ptr dinfo)
272{
273 int retval=-1, i, k;
274 for(i=0; i<NUMSUBOPT; i++)
275 {
276 if(dinfo->num_components==pixelsize[i])
277 {
278 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
279 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
280 {
281 int match=0;
282 for(k=1; k<dinfo->num_components; k++)
283 {
284 if(dinfo->comp_info[k].h_samp_factor==1
285 && dinfo->comp_info[k].v_samp_factor==1)
286 match++;
287 }
288 if(match==dinfo->num_components-1)
289 {
290 retval=i; break;
291 }
292 }
293 }
294 }
295 return retval;
296}
297
298
DRCafc06922012-03-23 19:47:57 +0000299#ifndef JCS_EXTENSIONS
300
301/* Conversion functions to emulate the colorspace extensions. This allows the
302 TurboJPEG wrapper to be used with libjpeg */
303
304#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
305 int rowPad=pitch-width*PS; \
306 while(height--) \
307 { \
308 unsigned char *endOfRow=src+width*PS; \
309 while(src<endOfRow) \
310 { \
311 dst[RGB_RED]=src[ROFFSET]; \
312 dst[RGB_GREEN]=src[GOFFSET]; \
313 dst[RGB_BLUE]=src[BOFFSET]; \
314 dst+=RGB_PIXELSIZE; src+=PS; \
315 } \
316 src+=rowPad; \
317 } \
318}
319
320static unsigned char *toRGB(unsigned char *src, int width, int pitch,
321 int height, int pixelFormat, unsigned char *dst)
322{
323 unsigned char *retval=src;
324 switch(pixelFormat)
325 {
326 case TJPF_RGB:
327 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
328 retval=dst; TORGB(3, 0, 1, 2);
329 #endif
330 break;
331 case TJPF_BGR:
332 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
333 retval=dst; TORGB(3, 2, 1, 0);
334 #endif
335 break;
336 case TJPF_RGBX:
337 case TJPF_RGBA:
338 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
339 retval=dst; TORGB(4, 0, 1, 2);
340 #endif
341 break;
342 case TJPF_BGRX:
343 case TJPF_BGRA:
344 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
345 retval=dst; TORGB(4, 2, 1, 0);
346 #endif
347 break;
348 case TJPF_XRGB:
349 case TJPF_ARGB:
350 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
351 retval=dst; TORGB(4, 1, 2, 3);
352 #endif
353 break;
354 case TJPF_XBGR:
355 case TJPF_ABGR:
356 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
357 retval=dst; TORGB(4, 3, 2, 1);
358 #endif
359 break;
360 }
361 return retval;
362}
363
364#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
365 int rowPad=pitch-width*PS; \
366 while(height--) \
367 { \
368 unsigned char *endOfRow=dst+width*PS; \
369 while(dst<endOfRow) \
370 { \
371 dst[ROFFSET]=src[RGB_RED]; \
372 dst[GOFFSET]=src[RGB_GREEN]; \
373 dst[BOFFSET]=src[RGB_BLUE]; \
374 SETALPHA \
375 dst+=PS; src+=RGB_PIXELSIZE; \
376 } \
377 dst+=rowPad; \
378 } \
379}
380
381static void fromRGB(unsigned char *src, unsigned char *dst, int width,
382 int pitch, int height, int pixelFormat)
383{
384 switch(pixelFormat)
385 {
386 case TJPF_RGB:
387 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
388 FROMRGB(3, 0, 1, 2,);
389 #endif
390 break;
391 case TJPF_BGR:
392 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
393 FROMRGB(3, 2, 1, 0,);
394 #endif
395 break;
396 case TJPF_RGBX:
397 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
398 FROMRGB(4, 0, 1, 2,);
399 #endif
400 break;
401 case TJPF_RGBA:
402 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
403 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
404 #endif
405 break;
406 case TJPF_BGRX:
407 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
408 FROMRGB(4, 2, 1, 0,);
409 #endif
410 break;
411 case TJPF_BGRA:
412 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
413 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
414 #endif
415 break;
416 case TJPF_XRGB:
417 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
418 FROMRGB(4, 1, 2, 3,); return;
419 #endif
420 break;
421 case TJPF_ARGB:
422 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
423 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
424 #endif
425 break;
426 case TJPF_XBGR:
427 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
428 FROMRGB(4, 3, 2, 1,); return;
429 #endif
430 break;
431 case TJPF_ABGR:
432 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
433 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
434 #endif
435 break;
436 }
437}
438
439#endif
440
441
DRC9b28def2011-05-21 14:37:15 +0000442/* General API functions */
443
444DLLEXPORT char* DLLCALL tjGetErrorStr(void)
445{
446 return errStr;
447}
448
449
450DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
451{
452 getinstance(handle);
453 if(setjmp(this->jerr.setjmp_buffer)) return -1;
454 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
455 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
456 free(this);
457 return 0;
458}
459
460
DRC6b76f752011-05-24 16:52:47 +0000461/* These are exposed mainly because Windows can't malloc() and free() across
462 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
463 with turbojpeg.dll for compatibility reasons. However, these functions
464 can potentially be used for other purposes by different implementations. */
465
466DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
467{
468 if(buf) free(buf);
469}
470
471
472DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
473{
474 return (unsigned char *)malloc(bytes);
475}
476
477
DRC9b28def2011-05-21 14:37:15 +0000478/* Compressor */
479
480static tjhandle _tjInitCompress(tjinstance *this)
481{
482 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
483
484 /* This is also straight out of example.c */
485 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
486 this->jerr.pub.error_exit=my_error_exit;
487 this->jerr.pub.output_message=my_output_message;
488
489 if(setjmp(this->jerr.setjmp_buffer))
490 {
491 /* If we get here, the JPEG code has signaled an error. */
492 if(this) free(this); return NULL;
493 }
494
495 jpeg_create_compress(&this->cinfo);
496 /* Make an initial call so it will create the destination manager */
497 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
498
DRC007a42c2011-05-22 13:55:56 +0000499 this->init|=COMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000500 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000501}
502
DRC890f1e02011-02-26 22:02:37 +0000503DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
504{
DRC9b28def2011-05-21 14:37:15 +0000505 tjinstance *this=NULL;
506 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000507 {
DRC007a42c2011-05-22 13:55:56 +0000508 snprintf(errStr, JMSG_LENGTH_MAX,
509 "tjInitCompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000510 return NULL;
511 }
DRC007a42c2011-05-22 13:55:56 +0000512 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000513 return _tjInitCompress(this);
DRC890f1e02011-02-26 22:02:37 +0000514}
515
DRC84241602011-02-25 02:08:23 +0000516
DRC9b49f0e2011-07-12 03:17:23 +0000517DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
518 int jpegSubsamp)
519{
520 unsigned long retval=0; int mcuw, mcuh, chromasf;
521 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
522 _throw("tjBufSize(): Invalid argument");
523
524 // This allows for rare corner cases in which a JPEG image can actually be
525 // larger than the uncompressed input (we wouldn't mention it if it hadn't
526 // happened before.)
527 mcuw=tjMCUWidth[jpegSubsamp];
528 mcuh=tjMCUHeight[jpegSubsamp];
529 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
530 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
531
532 bailout:
533 return retval;
534}
535
DRC2e7b76b2009-04-03 12:04:24 +0000536DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
537{
DRCf3cf9732011-02-22 00:16:14 +0000538 unsigned long retval=0;
539 if(width<1 || height<1)
DRC007a42c2011-05-22 13:55:56 +0000540 _throw("TJBUFSIZE(): Invalid argument");
DRCf3cf9732011-02-22 00:16:14 +0000541
542 // This allows for rare corner cases in which a JPEG image can actually be
543 // larger than the uncompressed input (we wouldn't mention it if it hadn't
DRCb28fc572011-02-22 06:41:29 +0000544 // happened before.)
DRC007a42c2011-05-22 13:55:56 +0000545 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
DRCf3cf9732011-02-22 00:16:14 +0000546
547 bailout:
548 return retval;
549}
550
DRC84241602011-02-25 02:08:23 +0000551
DRCf610d612013-04-26 10:33:29 +0000552DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
DRCf3cf9732011-02-22 00:16:14 +0000553 int subsamp)
554{
555 unsigned long retval=0;
556 int pw, ph, cw, ch;
DRCf610d612013-04-26 10:33:29 +0000557 if(width<1 || height<1 || pad<1 || !isPow2(pad) || subsamp<0
558 || subsamp>=NUMSUBOPT)
559 _throw("tjBufSizeYUV2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000560 pw=PAD(width, tjMCUWidth[subsamp]/8);
561 ph=PAD(height, tjMCUHeight[subsamp]/8);
562 cw=pw*8/tjMCUWidth[subsamp]; ch=ph*8/tjMCUHeight[subsamp];
DRCf610d612013-04-26 10:33:29 +0000563 retval=PAD(pw, pad)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, pad)*ch*2);
DRCf3cf9732011-02-22 00:16:14 +0000564
565 bailout:
566 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000567}
568
DRCf610d612013-04-26 10:33:29 +0000569DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
570 int subsamp)
571{
572 return tjBufSizeYUV2(width, 4, height, subsamp);
573}
DRC84241602011-02-25 02:08:23 +0000574
DRC9b49f0e2011-07-12 03:17:23 +0000575DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
576 int subsamp)
577{
578 return tjBufSizeYUV(width, height, subsamp);
579}
580
581
DRC9b28def2011-05-21 14:37:15 +0000582DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
583 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
584 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
585{
DRCff78e372011-05-24 10:17:32 +0000586 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
DRCafc06922012-03-23 19:47:57 +0000587 #ifndef JCS_EXTENSIONS
588 unsigned char *rgbBuf=NULL;
589 #endif
DRC9b28def2011-05-21 14:37:15 +0000590
591 getinstance(handle)
592 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000593 _throw("tjCompress2(): Instance has not been initialized for compression");
DRC9b28def2011-05-21 14:37:15 +0000594
595 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
596 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
597 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
DRC007a42c2011-05-22 13:55:56 +0000598 _throw("tjCompress2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000599
600 if(setjmp(this->jerr.setjmp_buffer))
601 {
602 /* If we get here, the JPEG code has signaled an error. */
603 retval=-1;
604 goto bailout;
605 }
606
607 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
608
DRCafc06922012-03-23 19:47:57 +0000609 #ifndef JCS_EXTENSIONS
610 if(pixelFormat!=TJPF_GRAY)
611 {
612 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
613 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
614 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
615 pitch=width*RGB_PIXELSIZE;
616 }
617 #endif
618
DRC9b28def2011-05-21 14:37:15 +0000619 cinfo->image_width=width;
620 cinfo->image_height=height;
621
DRC25b995a2011-05-21 15:34:54 +0000622 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
623 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
624 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000625
DRCff78e372011-05-24 10:17:32 +0000626 if(flags&TJFLAG_NOREALLOC)
627 {
DRC9b49f0e2011-07-12 03:17:23 +0000628 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +0000629 }
630 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
DRC73d74c12012-06-29 23:46:38 +0000631 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
DRCf12bb302011-09-07 05:03:18 +0000632 return -1;
DRC9b28def2011-05-21 14:37:15 +0000633
634 jpeg_start_compress(cinfo, TRUE);
635 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000636 _throw("tjCompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000637 for(i=0; i<height; i++)
638 {
DRC25b995a2011-05-21 15:34:54 +0000639 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000640 else row_pointer[i]=&srcBuf[i*pitch];
641 }
642 while(cinfo->next_scanline<cinfo->image_height)
643 {
644 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
645 cinfo->image_height-cinfo->next_scanline);
646 }
647 jpeg_finish_compress(cinfo);
648
649 bailout:
650 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000651 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000652 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000653 #endif
DRC9b28def2011-05-21 14:37:15 +0000654 if(row_pointer) free(row_pointer);
655 return retval;
656}
657
658DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
659 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
660 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
661{
662 int retval=0; unsigned long size;
663 if(flags&TJ_YUV)
664 {
DRC9b49f0e2011-07-12 03:17:23 +0000665 size=tjBufSizeYUV(width, height, jpegSubsamp);
DRC9b28def2011-05-21 14:37:15 +0000666 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
667 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
668 }
669 else
670 {
DRC9b28def2011-05-21 14:37:15 +0000671 retval=tjCompress2(handle, srcBuf, width, pitch, height,
672 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
DRC25b995a2011-05-21 15:34:54 +0000673 flags|TJFLAG_NOREALLOC);
DRC9b28def2011-05-21 14:37:15 +0000674 }
675 *jpegSize=size;
676 return retval;
677}
678
679
DRCf610d612013-04-26 10:33:29 +0000680DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle, unsigned char *srcBuf,
DRC9b28def2011-05-21 14:37:15 +0000681 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
DRCf610d612013-04-26 10:33:29 +0000682 int pad, int subsamp, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000683{
DRC91e86ba2011-02-15 05:24:08 +0000684 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000685 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
686 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
687 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC9b28def2011-05-21 14:37:15 +0000688 int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
689 JSAMPLE *ptr=dstBuf;
DRCafc06922012-03-23 19:47:57 +0000690 unsigned long yuvsize=0;
DRC9b28def2011-05-21 14:37:15 +0000691 jpeg_component_info *compptr;
DRCafc06922012-03-23 19:47:57 +0000692 #ifndef JCS_EXTENSIONS
693 unsigned char *rgbBuf=NULL;
694 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000695
DRC9b28def2011-05-21 14:37:15 +0000696 getinstance(handle);
697 if((this->init&COMPRESS)==0)
DRCf610d612013-04-26 10:33:29 +0000698 _throw("tjEncodeYUV3(): Instance has not been initialized for compression");
DRC2e7b76b2009-04-03 12:04:24 +0000699
DRCfbb67472010-11-24 04:02:37 +0000700 for(i=0; i<MAX_COMPONENTS; i++)
701 {
702 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
703 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
704 }
705
DRC9b28def2011-05-21 14:37:15 +0000706 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
DRCf610d612013-04-26 10:33:29 +0000707 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || pad<0 || !isPow2(pad)
708 || subsamp<0 || subsamp>=NUMSUBOPT)
709 _throw("tjEncodeYUV3(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000710
DRC9b28def2011-05-21 14:37:15 +0000711 if(setjmp(this->jerr.setjmp_buffer))
712 {
713 /* If we get here, the JPEG code has signaled an error. */
714 retval=-1;
715 goto bailout;
716 }
DRC2e7b76b2009-04-03 12:04:24 +0000717
DRC9b28def2011-05-21 14:37:15 +0000718 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC2e7b76b2009-04-03 12:04:24 +0000719
DRCafc06922012-03-23 19:47:57 +0000720 #ifndef JCS_EXTENSIONS
721 if(pixelFormat!=TJPF_GRAY)
722 {
723 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
DRCf610d612013-04-26 10:33:29 +0000724 if(!rgbBuf) _throw("tjEncodeYUV3(): Memory allocation failure");
DRCafc06922012-03-23 19:47:57 +0000725 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
726 pitch=width*RGB_PIXELSIZE;
727 }
728 #endif
729
DRC9b28def2011-05-21 14:37:15 +0000730 cinfo->image_width=width;
731 cinfo->image_height=height;
DRC2e7b76b2009-04-03 12:04:24 +0000732
DRC25b995a2011-05-21 15:34:54 +0000733 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
734 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
735 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000736
DRCf610d612013-04-26 10:33:29 +0000737 yuvsize=tjBufSizeYUV2(width, pad, height, subsamp);
DRC9b28def2011-05-21 14:37:15 +0000738 jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0);
DRC73d74c12012-06-29 23:46:38 +0000739 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000740
DRC9b28def2011-05-21 14:37:15 +0000741 jpeg_start_compress(cinfo, TRUE);
742 pw=PAD(width, cinfo->max_h_samp_factor);
743 ph=PAD(height, cinfo->max_v_samp_factor);
DRC2e7b76b2009-04-03 12:04:24 +0000744
DRC9b28def2011-05-21 14:37:15 +0000745 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
DRCf610d612013-04-26 10:33:29 +0000746 _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000747 for(i=0; i<height; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000748 {
DRC25b995a2011-05-21 15:34:54 +0000749 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000750 else row_pointer[i]=&srcBuf[i*pitch];
751 }
752 if(height<ph)
753 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
DRCfbb67472010-11-24 04:02:37 +0000754
DRC9b28def2011-05-21 14:37:15 +0000755 for(i=0; i<cinfo->num_components; i++)
756 {
757 compptr=&cinfo->comp_info[i];
758 _tmpbuf[i]=(JSAMPLE *)malloc(
759 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
760 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRCf610d612013-04-26 10:33:29 +0000761 if(!_tmpbuf[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000762 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRCf610d612013-04-26 10:33:29 +0000763 if(!tmpbuf[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000764 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRCfbb67472010-11-24 04:02:37 +0000765 {
DRC9b28def2011-05-21 14:37:15 +0000766 unsigned char *_tmpbuf_aligned=
767 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
768 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000769 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC9b28def2011-05-21 14:37:15 +0000770 /compptr->h_samp_factor, 16) * row];
DRCfbb67472010-11-24 04:02:37 +0000771 }
DRC9b28def2011-05-21 14:37:15 +0000772 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
773 * compptr->v_samp_factor + 16);
DRCf610d612013-04-26 10:33:29 +0000774 if(!_tmpbuf2[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000775 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCf610d612013-04-26 10:33:29 +0000776 if(!tmpbuf2[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000777 for(row=0; row<compptr->v_samp_factor; row++)
778 {
779 unsigned char *_tmpbuf2_aligned=
780 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
781 tmpbuf2[i][row]=&_tmpbuf2_aligned[
782 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
783 }
784 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
785 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
786 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
DRCf610d612013-04-26 10:33:29 +0000787 if(!outbuf[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000788 for(row=0; row<ch[i]; row++)
789 {
790 outbuf[i][row]=ptr;
DRCf610d612013-04-26 10:33:29 +0000791 ptr+=PAD(cw[i], pad);
DRC9b28def2011-05-21 14:37:15 +0000792 }
793 }
794 if(yuvsize!=(unsigned long)(ptr-dstBuf))
DRCf610d612013-04-26 10:33:29 +0000795 _throw("tjEncodeYUV3(): Generated image is not the correct size");
DRCfbb67472010-11-24 04:02:37 +0000796
DRC9b28def2011-05-21 14:37:15 +0000797 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
DRCfbb67472010-11-24 04:02:37 +0000798 {
DRC9b28def2011-05-21 14:37:15 +0000799 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
800 cinfo->max_v_samp_factor);
801 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
802 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
803 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
804 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
805 compptr->v_samp_factor, cw[i]);
DRC6ee54592011-03-01 08:18:30 +0000806 }
DRC9b28def2011-05-21 14:37:15 +0000807 cinfo->next_scanline+=height;
808 jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000809
DRC91e86ba2011-02-15 05:24:08 +0000810 bailout:
DRC9b28def2011-05-21 14:37:15 +0000811 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000812 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000813 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000814 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000815 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000816 for(i=0; i<MAX_COMPONENTS; i++)
817 {
818 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000819 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000820 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000821 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000822 if(outbuf[i]!=NULL) free(outbuf[i]);
823 }
DRC91e86ba2011-02-15 05:24:08 +0000824 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000825}
826
DRCf610d612013-04-26 10:33:29 +0000827DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
828 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
829 int subsamp, int flags)
830{
831 return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
832 dstBuf, 4, subsamp, flags);
833}
834
DRC9b28def2011-05-21 14:37:15 +0000835DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
836 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
837 int subsamp, int flags)
DRC84241602011-02-25 02:08:23 +0000838{
DRC9b28def2011-05-21 14:37:15 +0000839 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
840 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
DRC84241602011-02-25 02:08:23 +0000841}
842
843
DRC9b28def2011-05-21 14:37:15 +0000844/* Decompressor */
DRC2e7b76b2009-04-03 12:04:24 +0000845
DRC9b28def2011-05-21 14:37:15 +0000846static tjhandle _tjInitDecompress(tjinstance *this)
DRC2e7b76b2009-04-03 12:04:24 +0000847{
DRC9b28def2011-05-21 14:37:15 +0000848 unsigned char buffer[1];
DRC2e7b76b2009-04-03 12:04:24 +0000849
DRC9b28def2011-05-21 14:37:15 +0000850 /* This is also straight out of example.c */
851 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
852 this->jerr.pub.error_exit=my_error_exit;
853 this->jerr.pub.output_message=my_output_message;
DRC2e7b76b2009-04-03 12:04:24 +0000854
DRC9b28def2011-05-21 14:37:15 +0000855 if(setjmp(this->jerr.setjmp_buffer))
856 {
857 /* If we get here, the JPEG code has signaled an error. */
858 if(this) free(this); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +0000859 }
DRC2e7b76b2009-04-03 12:04:24 +0000860
DRC9b28def2011-05-21 14:37:15 +0000861 jpeg_create_decompress(&this->dinfo);
862 /* Make an initial call so it will create the source manager */
863 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +0000864
DRC007a42c2011-05-22 13:55:56 +0000865 this->init|=DECOMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000866 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000867}
868
DRC890f1e02011-02-26 22:02:37 +0000869DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
870{
DRC9b28def2011-05-21 14:37:15 +0000871 tjinstance *this;
872 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000873 {
DRC007a42c2011-05-22 13:55:56 +0000874 snprintf(errStr, JMSG_LENGTH_MAX,
875 "tjInitDecompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000876 return NULL;
877 }
DRC007a42c2011-05-22 13:55:56 +0000878 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000879 return _tjInitDecompress(this);
DRC890f1e02011-02-26 22:02:37 +0000880}
881
DRC2e7b76b2009-04-03 12:04:24 +0000882
DRC9b28def2011-05-21 14:37:15 +0000883DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
884 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
885 int *jpegSubsamp)
DRC1fe80f82010-12-14 01:21:29 +0000886{
DRC9b49f0e2011-07-12 03:17:23 +0000887 int retval=0;
DRC1fe80f82010-12-14 01:21:29 +0000888
DRC9b28def2011-05-21 14:37:15 +0000889 getinstance(handle);
890 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000891 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
DRC1fe80f82010-12-14 01:21:29 +0000892
DRC9b28def2011-05-21 14:37:15 +0000893 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
894 || jpegSubsamp==NULL)
895 _throw("tjDecompressHeader2(): Invalid argument");
DRC1fe80f82010-12-14 01:21:29 +0000896
DRC9b28def2011-05-21 14:37:15 +0000897 if(setjmp(this->jerr.setjmp_buffer))
898 {
899 /* If we get here, the JPEG code has signaled an error. */
DRC1fe80f82010-12-14 01:21:29 +0000900 return -1;
901 }
902
DRC9b28def2011-05-21 14:37:15 +0000903 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
904 jpeg_read_header(dinfo, TRUE);
DRC1fe80f82010-12-14 01:21:29 +0000905
DRC9b28def2011-05-21 14:37:15 +0000906 *width=dinfo->image_width;
907 *height=dinfo->image_height;
DRC9b49f0e2011-07-12 03:17:23 +0000908 *jpegSubsamp=getSubsamp(dinfo);
DRC1fe80f82010-12-14 01:21:29 +0000909
DRC9b28def2011-05-21 14:37:15 +0000910 jpeg_abort_decompress(dinfo);
DRC1fe80f82010-12-14 01:21:29 +0000911
DRC9b28def2011-05-21 14:37:15 +0000912 if(*jpegSubsamp<0)
DRC007a42c2011-05-22 13:55:56 +0000913 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
914 if(*width<1 || *height<1)
915 _throw("tjDecompressHeader2(): Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +0000916
917 bailout:
918 return retval;
919}
920
DRC9b28def2011-05-21 14:37:15 +0000921DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
922 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
DRC91e86ba2011-02-15 05:24:08 +0000923{
DRC9b28def2011-05-21 14:37:15 +0000924 int jpegSubsamp;
925 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
926 &jpegSubsamp);
DRC1fe80f82010-12-14 01:21:29 +0000927}
928
929
DRC109a5782011-03-01 09:53:07 +0000930DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +0000931{
DRC109a5782011-03-01 09:53:07 +0000932 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +0000933 {
DRC9b28def2011-05-21 14:37:15 +0000934 snprintf(errStr, JMSG_LENGTH_MAX,
DRC007a42c2011-05-22 13:55:56 +0000935 "tjGetScalingFactors(): Invalid argument");
DRC109a5782011-03-01 09:53:07 +0000936 return NULL;
DRCb28fc572011-02-22 06:41:29 +0000937 }
938
DRC109a5782011-03-01 09:53:07 +0000939 *numscalingfactors=NUMSF;
940 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +0000941}
942
943
DRC9b28def2011-05-21 14:37:15 +0000944DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
945 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
946 int height, int pixelFormat, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000947{
DRC9b28def2011-05-21 14:37:15 +0000948 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRC109a5782011-03-01 09:53:07 +0000949 int jpegwidth, jpegheight, scaledw, scaledh;
DRCafc06922012-03-23 19:47:57 +0000950 #ifndef JCS_EXTENSIONS
951 unsigned char *rgbBuf=NULL;
952 unsigned char *_dstBuf=NULL; int _pitch=0;
953 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000954
DRC9b28def2011-05-21 14:37:15 +0000955 getinstance(handle);
956 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000957 _throw("tjDecompress2(): Instance has not been initialized for decompression");
DRC9b28def2011-05-21 14:37:15 +0000958
959 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
960 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
961 _throw("tjDecompress2(): Invalid argument");
962
DRC25b995a2011-05-21 15:34:54 +0000963 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
964 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
965 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000966
967 if(setjmp(this->jerr.setjmp_buffer))
968 {
969 /* If we get here, the JPEG code has signaled an error. */
970 retval=-1;
971 goto bailout;
972 }
973
974 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
975 jpeg_read_header(dinfo, TRUE);
DRC73d74c12012-06-29 23:46:38 +0000976 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
DRC2eda8212012-03-23 19:32:38 +0000977 {
978 retval=-1; goto bailout;
979 }
DRC9b28def2011-05-21 14:37:15 +0000980
DRC25b995a2011-05-21 15:34:54 +0000981 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +0000982
983 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
984 if(width==0) width=jpegwidth;
985 if(height==0) height=jpegheight;
986 for(i=0; i<NUMSF; i++)
987 {
988 scaledw=TJSCALED(jpegwidth, sf[i]);
989 scaledh=TJSCALED(jpegheight, sf[i]);
990 if(scaledw<=width && scaledh<=height)
DRCf610d612013-04-26 10:33:29 +0000991 break;
DRC9b28def2011-05-21 14:37:15 +0000992 }
993 if(scaledw>width || scaledh>height)
DRC007a42c2011-05-22 13:55:56 +0000994 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
DRC9b28def2011-05-21 14:37:15 +0000995 width=scaledw; height=scaledh;
996 dinfo->scale_num=sf[i].num;
997 dinfo->scale_denom=sf[i].denom;
998
999 jpeg_start_decompress(dinfo);
1000 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
DRCafc06922012-03-23 19:47:57 +00001001
1002 #ifndef JCS_EXTENSIONS
1003 if(pixelFormat!=TJPF_GRAY &&
1004 (RGB_RED!=tjRedOffset[pixelFormat] ||
1005 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1006 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1007 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1008 {
1009 rgbBuf=(unsigned char *)malloc(width*height*3);
1010 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1011 _pitch=pitch; pitch=width*3;
1012 _dstBuf=dstBuf; dstBuf=rgbBuf;
1013 }
1014 #endif
1015
DRC9b28def2011-05-21 14:37:15 +00001016 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1017 *dinfo->output_height))==NULL)
DRC007a42c2011-05-22 13:55:56 +00001018 _throw("tjDecompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001019 for(i=0; i<(int)dinfo->output_height; i++)
1020 {
DRC25b995a2011-05-21 15:34:54 +00001021 if(flags&TJFLAG_BOTTOMUP)
DRC9b28def2011-05-21 14:37:15 +00001022 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1023 else row_pointer[i]=&dstBuf[i*pitch];
1024 }
1025 while(dinfo->output_scanline<dinfo->output_height)
1026 {
1027 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1028 dinfo->output_height-dinfo->output_scanline);
1029 }
1030 jpeg_finish_decompress(dinfo);
1031
DRCafc06922012-03-23 19:47:57 +00001032 #ifndef JCS_EXTENSIONS
1033 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1034 #endif
1035
DRC9b28def2011-05-21 14:37:15 +00001036 bailout:
1037 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRCafc06922012-03-23 19:47:57 +00001038 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +00001039 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +00001040 #endif
DRC9b28def2011-05-21 14:37:15 +00001041 if(row_pointer) free(row_pointer);
1042 return retval;
1043}
1044
1045DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1046 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1047 int height, int pixelSize, int flags)
1048{
1049 if(flags&TJ_YUV)
1050 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1051 else
1052 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1053 height, getPixelFormat(pixelSize, flags), flags);
1054}
1055
1056
DRCf610d612013-04-26 10:33:29 +00001057DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
DRC9b28def2011-05-21 14:37:15 +00001058 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
DRCf610d612013-04-26 10:33:29 +00001059 int width, int pad, int height, int flags)
DRC9b28def2011-05-21 14:37:15 +00001060{
DRCf610d612013-04-26 10:33:29 +00001061 int i, sfi, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001062 int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
DRC9b28def2011-05-21 14:37:15 +00001063 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1064 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1065 JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001066 int dctsize;
DRC9b28def2011-05-21 14:37:15 +00001067
1068 getinstance(handle);
1069 if((this->init&DECOMPRESS)==0)
DRCf610d612013-04-26 10:33:29 +00001070 _throw("tjDecompressToYUV2(): Instance has not been initialized for decompression");
DRC2e7b76b2009-04-03 12:04:24 +00001071
DRCf9cf5c72010-12-10 10:58:49 +00001072 for(i=0; i<MAX_COMPONENTS; i++)
1073 {
1074 tmpbuf[i]=NULL; outbuf[i]=NULL;
1075 }
DRC9e17f7d2010-12-10 04:59:13 +00001076
DRCf610d612013-04-26 10:33:29 +00001077 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
1078 || !isPow2(pad) || height<0)
1079 _throw("tjDecompressToYUV2(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001080
DRC25b995a2011-05-21 15:34:54 +00001081 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1082 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1083 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +00001084
DRC9b28def2011-05-21 14:37:15 +00001085 if(setjmp(this->jerr.setjmp_buffer))
1086 {
1087 /* If we get here, the JPEG code has signaled an error. */
DRC91e86ba2011-02-15 05:24:08 +00001088 retval=-1;
1089 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +00001090 }
DRC2e7b76b2009-04-03 12:04:24 +00001091
DRC9b28def2011-05-21 14:37:15 +00001092 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1093 jpeg_read_header(dinfo, TRUE);
DRC418fe282013-05-07 21:17:35 +00001094 jpegSubsamp=getSubsamp(dinfo);
1095 if(jpegSubsamp<0)
1096 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC2e7b76b2009-04-03 12:04:24 +00001097
DRCf610d612013-04-26 10:33:29 +00001098 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1099 if(width==0) width=jpegwidth;
1100 if(height==0) height=jpegheight;
1101 for(i=0; i<NUMSF; i++)
1102 {
1103 scaledw=TJSCALED(jpegwidth, sf[i]);
1104 scaledh=TJSCALED(jpegheight, sf[i]);
1105 if(scaledw<=width && scaledh<=height)
1106 break;
1107 }
1108 if(scaledw>width || scaledh>height)
1109 _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1110 width=scaledw; height=scaledh;
1111 dinfo->scale_num=sf[i].num;
1112 dinfo->scale_denom=sf[i].denom;
1113 sfi=i;
1114 jpeg_calc_output_dimensions(dinfo);
1115
DRC418fe282013-05-07 21:17:35 +00001116 dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
1117
DRC9b28def2011-05-21 14:37:15 +00001118 for(i=0; i<dinfo->num_components; i++)
DRC2e7b76b2009-04-03 12:04:24 +00001119 {
DRC9b28def2011-05-21 14:37:15 +00001120 jpeg_component_info *compptr=&dinfo->comp_info[i];
1121 int ih;
DRC418fe282013-05-07 21:17:35 +00001122 iw[i]=compptr->width_in_blocks*dctsize;
1123 ih=compptr->height_in_blocks*dctsize;
DRCf610d612013-04-26 10:33:29 +00001124 cw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001125 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
DRCf610d612013-04-26 10:33:29 +00001126 ch[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001127 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
1128 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
DRC418fe282013-05-07 21:17:35 +00001129 th[i]=compptr->v_samp_factor*dctsize;
DRC9b28def2011-05-21 14:37:15 +00001130 tmpbufsize+=iw[i]*th[i];
1131 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
DRCf610d612013-04-26 10:33:29 +00001132 _throw("tjDecompressToYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001133 for(row=0; row<ch[i]; row++)
1134 {
1135 outbuf[i][row]=ptr;
DRCf610d612013-04-26 10:33:29 +00001136 ptr+=PAD(cw[i], pad);
DRC9b28def2011-05-21 14:37:15 +00001137 }
1138 }
1139 if(usetmpbuf)
1140 {
1141 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRCf610d612013-04-26 10:33:29 +00001142 _throw("tjDecompressToYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001143 ptr=_tmpbuf;
1144 for(i=0; i<dinfo->num_components; i++)
1145 {
1146 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRCf610d612013-04-26 10:33:29 +00001147 _throw("tjDecompressToYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001148 for(row=0; row<th[i]; row++)
1149 {
1150 tmpbuf[i][row]=ptr;
1151 ptr+=iw[i];
1152 }
1153 }
1154 }
DRC9e17f7d2010-12-10 04:59:13 +00001155
DRC25b995a2011-05-21 15:34:54 +00001156 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRCe0419b52012-07-03 20:01:31 +00001157 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
DRC9b28def2011-05-21 14:37:15 +00001158 dinfo->raw_data_out=TRUE;
1159
1160 jpeg_start_decompress(dinfo);
1161 for(row=0; row<(int)dinfo->output_height;
DRC418fe282013-05-07 21:17:35 +00001162 row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
DRC9b28def2011-05-21 14:37:15 +00001163 {
1164 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1165 int crow[MAX_COMPONENTS];
DRC9e17f7d2010-12-10 04:59:13 +00001166 for(i=0; i<dinfo->num_components; i++)
1167 {
1168 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRC418fe282013-05-07 21:17:35 +00001169 if(jpegSubsamp==TJ_420)
1170 {
1171 /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1172 to be clever and use the IDCT to perform upsampling on the U and V
1173 planes. For instance, if the output image is to be scaled by 1/2
1174 relative to the JPEG image, then the scaling factor and upsampling
1175 effectively cancel each other, so a normal 8x8 IDCT can be used.
1176 However, this is not desirable when using the decompress-to-YUV
1177 functionality in TurboJPEG, since we want to output the U and V
1178 planes in their subsampled form. Thus, we have to override some
1179 internal libjpeg parameters to force it to use the "scaled" IDCT
1180 functions on the U and V planes. */
1181 compptr->_DCT_scaled_size=dctsize;
1182 compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
1183 sf[sfi].num/sf[sfi].denom*
1184 compptr->v_samp_factor/dinfo->max_v_samp_factor;
1185 dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1186 }
DRC9b28def2011-05-21 14:37:15 +00001187 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1188 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1189 else yuvptr[i]=&outbuf[i][crow[i]];
DRCf9cf5c72010-12-10 10:58:49 +00001190 }
DRCf610d612013-04-26 10:33:29 +00001191 jpeg_read_raw_data(dinfo, yuvptr,
DRC418fe282013-05-07 21:17:35 +00001192 dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
DRCf9cf5c72010-12-10 10:58:49 +00001193 if(usetmpbuf)
1194 {
DRC9b28def2011-05-21 14:37:15 +00001195 int j;
DRCf9cf5c72010-12-10 10:58:49 +00001196 for(i=0; i<dinfo->num_components; i++)
1197 {
DRC9b28def2011-05-21 14:37:15 +00001198 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +00001199 {
DRC9b28def2011-05-21 14:37:15 +00001200 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001201 }
DRC9e17f7d2010-12-10 04:59:13 +00001202 }
1203 }
1204 }
DRC9b28def2011-05-21 14:37:15 +00001205 jpeg_finish_decompress(dinfo);
DRC2e7b76b2009-04-03 12:04:24 +00001206
DRC91e86ba2011-02-15 05:24:08 +00001207 bailout:
DRC9b28def2011-05-21 14:37:15 +00001208 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC9e17f7d2010-12-10 04:59:13 +00001209 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +00001210 {
1211 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +00001212 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001213 }
1214 if(_tmpbuf) free(_tmpbuf);
DRC91e86ba2011-02-15 05:24:08 +00001215 return retval;
DRC2e7b76b2009-04-03 12:04:24 +00001216}
1217
DRCf610d612013-04-26 10:33:29 +00001218DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1219 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1220 int flags)
1221{
1222 return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1223}
1224
DRC2e7b76b2009-04-03 12:04:24 +00001225
DRC9b28def2011-05-21 14:37:15 +00001226/* Transformer */
DRC890f1e02011-02-26 22:02:37 +00001227
1228DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1229{
DRC9b28def2011-05-21 14:37:15 +00001230 tjinstance *this=NULL; tjhandle handle=NULL;
1231 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00001232 {
DRC007a42c2011-05-22 13:55:56 +00001233 snprintf(errStr, JMSG_LENGTH_MAX,
1234 "tjInitTransform(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00001235 return NULL;
1236 }
DRC007a42c2011-05-22 13:55:56 +00001237 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +00001238 handle=_tjInitCompress(this);
1239 if(!handle) return NULL;
1240 handle=_tjInitDecompress(this);
1241 return handle;
DRC890f1e02011-02-26 22:02:37 +00001242}
1243
1244
DRC9b28def2011-05-21 14:37:15 +00001245DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1246 unsigned long jpegSize, int n, unsigned char **dstBufs,
1247 unsigned long *dstSizes, tjtransform *t, int flags)
DRC890f1e02011-02-26 22:02:37 +00001248{
DRC0a325192011-03-02 09:22:41 +00001249 jpeg_transform_info *xinfo=NULL;
DRC890f1e02011-02-26 22:02:37 +00001250 jvirt_barray_ptr *srccoefs, *dstcoefs;
DRC9b49f0e2011-07-12 03:17:23 +00001251 int retval=0, i, jpegSubsamp;
DRC890f1e02011-02-26 22:02:37 +00001252
DRC9b28def2011-05-21 14:37:15 +00001253 getinstance(handle);
1254 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001255 _throw("tjTransform(): Instance has not been initialized for transformation");
DRC890f1e02011-02-26 22:02:37 +00001256
DRC9b28def2011-05-21 14:37:15 +00001257 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1258 || t==NULL || flags<0)
1259 _throw("tjTransform(): Invalid argument");
1260
DRC25b995a2011-05-21 15:34:54 +00001261 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1262 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1263 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC890f1e02011-02-26 22:02:37 +00001264
DRC9b28def2011-05-21 14:37:15 +00001265 if(setjmp(this->jerr.setjmp_buffer))
1266 {
1267 /* If we get here, the JPEG code has signaled an error. */
DRC890f1e02011-02-26 22:02:37 +00001268 retval=-1;
1269 goto bailout;
1270 }
1271
DRC9b28def2011-05-21 14:37:15 +00001272 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
DRC890f1e02011-02-26 22:02:37 +00001273
DRC0a325192011-03-02 09:22:41 +00001274 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1275 ==NULL)
DRC007a42c2011-05-22 13:55:56 +00001276 _throw("tjTransform(): Memory allocation failure");
1277 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
DRC890f1e02011-02-26 22:02:37 +00001278
DRC0a325192011-03-02 09:22:41 +00001279 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001280 {
DRC0a325192011-03-02 09:22:41 +00001281 xinfo[i].transform=xformtypes[t[i].op];
DRC25b995a2011-05-21 15:34:54 +00001282 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1283 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1284 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1285 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1286 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
DRCba5ea512011-03-04 03:20:34 +00001287 else xinfo[i].slow_hflip=0;
DRC0a325192011-03-02 09:22:41 +00001288
1289 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001290 {
DRC0a325192011-03-02 09:22:41 +00001291 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
1292 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
1293 if(t[i].r.w!=0)
1294 {
1295 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
1296 }
DRCd932e582011-03-15 20:09:47 +00001297 else xinfo[i].crop_width=JCROP_UNSET;
DRC0a325192011-03-02 09:22:41 +00001298 if(t[i].r.h!=0)
1299 {
1300 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
1301 }
DRCd932e582011-03-15 20:09:47 +00001302 else xinfo[i].crop_height=JCROP_UNSET;
DRC890f1e02011-02-26 22:02:37 +00001303 }
1304 }
1305
DRC9b28def2011-05-21 14:37:15 +00001306 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1307 jpeg_read_header(dinfo, TRUE);
DRC9b49f0e2011-07-12 03:17:23 +00001308 jpegSubsamp=getSubsamp(dinfo);
1309 if(jpegSubsamp<0)
1310 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC890f1e02011-02-26 22:02:37 +00001311
DRC0a325192011-03-02 09:22:41 +00001312 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001313 {
DRC9b28def2011-05-21 14:37:15 +00001314 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
DRC007a42c2011-05-22 13:55:56 +00001315 _throw("tjTransform(): Transform is not perfect");
DRC890f1e02011-02-26 22:02:37 +00001316
DRC0a325192011-03-02 09:22:41 +00001317 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001318 {
DRC0a325192011-03-02 09:22:41 +00001319 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1320 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1321 {
DRC9b28def2011-05-21 14:37:15 +00001322 snprintf(errStr, JMSG_LENGTH_MAX,
DRC0a325192011-03-02 09:22:41 +00001323 "To crop this JPEG image, x must be a multiple of %d\n"
1324 "and y must be a multiple of %d.\n",
1325 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1326 retval=-1; goto bailout;
1327 }
DRC890f1e02011-02-26 22:02:37 +00001328 }
1329 }
1330
DRC9b28def2011-05-21 14:37:15 +00001331 srccoefs=jpeg_read_coefficients(dinfo);
DRC890f1e02011-02-26 22:02:37 +00001332
DRC0a325192011-03-02 09:22:41 +00001333 for(i=0; i<n; i++)
1334 {
DRCff78e372011-05-24 10:17:32 +00001335 int w, h, alloc=1;
DRC0a325192011-03-02 09:22:41 +00001336 if(!xinfo[i].crop)
1337 {
DRC9b28def2011-05-21 14:37:15 +00001338 w=dinfo->image_width; h=dinfo->image_height;
DRC0a325192011-03-02 09:22:41 +00001339 }
1340 else
1341 {
1342 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
1343 }
DRCff78e372011-05-24 10:17:32 +00001344 if(flags&TJFLAG_NOREALLOC)
1345 {
DRC9b49f0e2011-07-12 03:17:23 +00001346 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +00001347 }
DRC7bf04d32011-09-17 00:18:31 +00001348 if(!(t[i].options&TJXOPT_NOOUTPUT))
1349 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
DRC9b28def2011-05-21 14:37:15 +00001350 jpeg_copy_critical_parameters(dinfo, cinfo);
1351 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00001352 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00001353 if(!(t[i].options&TJXOPT_NOOUTPUT))
1354 {
1355 jpeg_write_coefficients(cinfo, dstcoefs);
1356 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1357 }
1358 else jinit_c_master_control(cinfo, TRUE);
DRC9b28def2011-05-21 14:37:15 +00001359 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00001360 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00001361 if(t[i].customFilter)
1362 {
DRCefe28ce2012-01-17 11:48:38 +00001363 int ci, y; JDIMENSION by;
DRC7bf04d32011-09-17 00:18:31 +00001364 for(ci=0; ci<cinfo->num_components; ci++)
1365 {
1366 jpeg_component_info *compptr=&cinfo->comp_info[ci];
1367 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1368 DCTSIZE};
1369 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1370 compptr->height_in_blocks*DCTSIZE};
1371 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1372 {
1373 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1374 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1375 TRUE);
1376 for(y=0; y<compptr->v_samp_factor; y++)
1377 {
1378 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
DRCf5467112011-09-20 05:02:19 +00001379 ci, i, &t[i])==-1)
DRC7bf04d32011-09-17 00:18:31 +00001380 _throw("tjTransform(): Error in custom filter");
1381 arrayRegion.y+=DCTSIZE;
1382 }
1383 }
1384 }
1385 }
1386 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
DRC0a325192011-03-02 09:22:41 +00001387 }
1388
DRC9b28def2011-05-21 14:37:15 +00001389 jpeg_finish_decompress(dinfo);
DRC890f1e02011-02-26 22:02:37 +00001390
DRC890f1e02011-02-26 22:02:37 +00001391 bailout:
DRC9b28def2011-05-21 14:37:15 +00001392 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1393 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC0a325192011-03-02 09:22:41 +00001394 if(xinfo) free(xinfo);
DRC890f1e02011-02-26 22:02:37 +00001395 return retval;
1396}