blob: 8dcc3b7269ae9092ea2856bdb62de98d1e234219 [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
DRCcd7c3e62013-08-23 02:49:25 +0000190 case TJPF_CMYK:
191 cinfo->in_color_space=JCS_CMYK; break;
DRCefa4ddc2010-10-13 19:22:50 +0000192 }
DRC2e7b76b2009-04-03 12:04:24 +0000193
DRC9b28def2011-05-21 14:37:15 +0000194 cinfo->input_components=tjPixelSize[pixelFormat];
195 jpeg_set_defaults(cinfo);
196 if(jpegQual>=0)
197 {
198 jpeg_set_quality(cinfo, jpegQual, TRUE);
DRC73d74c12012-06-29 23:46:38 +0000199 if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
DRC9b28def2011-05-21 14:37:15 +0000200 else cinfo->dct_method=JDCT_FASTEST;
201 }
DRC25b995a2011-05-21 15:34:54 +0000202 if(subsamp==TJSAMP_GRAY)
DRC9b28def2011-05-21 14:37:15 +0000203 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
DRCcd7c3e62013-08-23 02:49:25 +0000204 else if(pixelFormat==TJPF_CMYK)
205 jpeg_set_colorspace(cinfo, JCS_YCCK);
206 else jpeg_set_colorspace(cinfo, JCS_YCbCr);
DRC2e7b76b2009-04-03 12:04:24 +0000207
DRC9b28def2011-05-21 14:37:15 +0000208 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
209 cinfo->comp_info[1].h_samp_factor=1;
210 cinfo->comp_info[2].h_samp_factor=1;
DRCcd7c3e62013-08-23 02:49:25 +0000211 if(cinfo->num_components>3)
212 cinfo->comp_info[3].h_samp_factor=tjMCUWidth[subsamp]/8;
DRC9b28def2011-05-21 14:37:15 +0000213 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
214 cinfo->comp_info[1].v_samp_factor=1;
215 cinfo->comp_info[2].v_samp_factor=1;
DRCcd7c3e62013-08-23 02:49:25 +0000216 if(cinfo->num_components>3)
217 cinfo->comp_info[3].v_samp_factor=tjMCUHeight[subsamp]/8;
DRCf12bb302011-09-07 05:03:18 +0000218
DRCf12bb302011-09-07 05:03:18 +0000219 return retval;
DRC9b28def2011-05-21 14:37:15 +0000220}
221
DRCf12bb302011-09-07 05:03:18 +0000222static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
DRC73d74c12012-06-29 23:46:38 +0000223 int pixelFormat, int flags)
DRC9b28def2011-05-21 14:37:15 +0000224{
DRCf12bb302011-09-07 05:03:18 +0000225 int retval=0;
226
DRC9b28def2011-05-21 14:37:15 +0000227 switch(pixelFormat)
228 {
DRC25b995a2011-05-21 15:34:54 +0000229 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000230 dinfo->out_color_space=JCS_GRAYSCALE; break;
231 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000232 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000233 dinfo->out_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000234 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000235 dinfo->out_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000236 case TJPF_RGBX:
DRC9b28def2011-05-21 14:37:15 +0000237 dinfo->out_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000238 case TJPF_BGRX:
DRC9b28def2011-05-21 14:37:15 +0000239 dinfo->out_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000240 case TJPF_XRGB:
DRC9b28def2011-05-21 14:37:15 +0000241 dinfo->out_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000242 case TJPF_XBGR:
DRC9b28def2011-05-21 14:37:15 +0000243 dinfo->out_color_space=JCS_EXT_XBGR; break;
DRC67ce3b22011-12-19 02:21:03 +0000244 #if JCS_ALPHA_EXTENSIONS==1
245 case TJPF_RGBA:
246 dinfo->out_color_space=JCS_EXT_RGBA; break;
247 case TJPF_BGRA:
248 dinfo->out_color_space=JCS_EXT_BGRA; break;
249 case TJPF_ARGB:
250 dinfo->out_color_space=JCS_EXT_ARGB; break;
251 case TJPF_ABGR:
252 dinfo->out_color_space=JCS_EXT_ABGR; break;
253 #endif
DRC9b28def2011-05-21 14:37:15 +0000254 #else
DRC25b995a2011-05-21 15:34:54 +0000255 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000256 case TJPF_BGR:
257 case TJPF_RGBX:
258 case TJPF_BGRX:
259 case TJPF_XRGB:
260 case TJPF_XBGR:
261 case TJPF_RGBA:
262 case TJPF_BGRA:
263 case TJPF_ARGB:
264 case TJPF_ABGR:
265 dinfo->out_color_space=JCS_RGB; break;
DRC67ce3b22011-12-19 02:21:03 +0000266 #endif
DRCcd7c3e62013-08-23 02:49:25 +0000267 case TJPF_CMYK:
268 dinfo->out_color_space=JCS_CMYK; break;
DRC9b28def2011-05-21 14:37:15 +0000269 default:
270 _throw("Unsupported pixel format");
DRC9b28def2011-05-21 14:37:15 +0000271 }
DRCf12bb302011-09-07 05:03:18 +0000272
DRC73d74c12012-06-29 23:46:38 +0000273 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
274
DRCf12bb302011-09-07 05:03:18 +0000275 bailout:
DRCf12bb302011-09-07 05:03:18 +0000276 return retval;
DRC9b28def2011-05-21 14:37:15 +0000277}
278
279
DRC9b49f0e2011-07-12 03:17:23 +0000280static int getSubsamp(j_decompress_ptr dinfo)
281{
282 int retval=-1, i, k;
283 for(i=0; i<NUMSUBOPT; i++)
284 {
DRCcd7c3e62013-08-23 02:49:25 +0000285 if(dinfo->num_components==pixelsize[i]
286 || ((dinfo->jpeg_color_space==JCS_YCCK
287 || dinfo->jpeg_color_space==JCS_CMYK)
288 && pixelsize[i]==3 && dinfo->num_components==4))
DRC9b49f0e2011-07-12 03:17:23 +0000289 {
290 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
291 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
292 {
293 int match=0;
294 for(k=1; k<dinfo->num_components; k++)
295 {
DRCcd7c3e62013-08-23 02:49:25 +0000296 int href=1, vref=1;
297 if(dinfo->jpeg_color_space==JCS_YCCK && k==3)
298 {
299 href=tjMCUWidth[i]/8; vref=tjMCUHeight[i]/8;
300 }
301 if(dinfo->comp_info[k].h_samp_factor==href
302 && dinfo->comp_info[k].v_samp_factor==vref)
DRC9b49f0e2011-07-12 03:17:23 +0000303 match++;
304 }
305 if(match==dinfo->num_components-1)
306 {
307 retval=i; break;
308 }
309 }
310 }
311 }
312 return retval;
313}
314
315
DRCafc06922012-03-23 19:47:57 +0000316#ifndef JCS_EXTENSIONS
317
318/* Conversion functions to emulate the colorspace extensions. This allows the
319 TurboJPEG wrapper to be used with libjpeg */
320
321#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
322 int rowPad=pitch-width*PS; \
323 while(height--) \
324 { \
325 unsigned char *endOfRow=src+width*PS; \
326 while(src<endOfRow) \
327 { \
328 dst[RGB_RED]=src[ROFFSET]; \
329 dst[RGB_GREEN]=src[GOFFSET]; \
330 dst[RGB_BLUE]=src[BOFFSET]; \
331 dst+=RGB_PIXELSIZE; src+=PS; \
332 } \
333 src+=rowPad; \
334 } \
335}
336
337static unsigned char *toRGB(unsigned char *src, int width, int pitch,
338 int height, int pixelFormat, unsigned char *dst)
339{
340 unsigned char *retval=src;
341 switch(pixelFormat)
342 {
343 case TJPF_RGB:
344 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
345 retval=dst; TORGB(3, 0, 1, 2);
346 #endif
347 break;
348 case TJPF_BGR:
349 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
350 retval=dst; TORGB(3, 2, 1, 0);
351 #endif
352 break;
353 case TJPF_RGBX:
354 case TJPF_RGBA:
355 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
356 retval=dst; TORGB(4, 0, 1, 2);
357 #endif
358 break;
359 case TJPF_BGRX:
360 case TJPF_BGRA:
361 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
362 retval=dst; TORGB(4, 2, 1, 0);
363 #endif
364 break;
365 case TJPF_XRGB:
366 case TJPF_ARGB:
367 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
368 retval=dst; TORGB(4, 1, 2, 3);
369 #endif
370 break;
371 case TJPF_XBGR:
372 case TJPF_ABGR:
373 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
374 retval=dst; TORGB(4, 3, 2, 1);
375 #endif
376 break;
377 }
378 return retval;
379}
380
381#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
382 int rowPad=pitch-width*PS; \
383 while(height--) \
384 { \
385 unsigned char *endOfRow=dst+width*PS; \
386 while(dst<endOfRow) \
387 { \
388 dst[ROFFSET]=src[RGB_RED]; \
389 dst[GOFFSET]=src[RGB_GREEN]; \
390 dst[BOFFSET]=src[RGB_BLUE]; \
391 SETALPHA \
392 dst+=PS; src+=RGB_PIXELSIZE; \
393 } \
394 dst+=rowPad; \
395 } \
396}
397
398static void fromRGB(unsigned char *src, unsigned char *dst, int width,
399 int pitch, int height, int pixelFormat)
400{
401 switch(pixelFormat)
402 {
403 case TJPF_RGB:
404 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
405 FROMRGB(3, 0, 1, 2,);
406 #endif
407 break;
408 case TJPF_BGR:
409 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
410 FROMRGB(3, 2, 1, 0,);
411 #endif
412 break;
413 case TJPF_RGBX:
414 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
415 FROMRGB(4, 0, 1, 2,);
416 #endif
417 break;
418 case TJPF_RGBA:
419 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
420 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
421 #endif
422 break;
423 case TJPF_BGRX:
424 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
425 FROMRGB(4, 2, 1, 0,);
426 #endif
427 break;
428 case TJPF_BGRA:
429 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
430 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
431 #endif
432 break;
433 case TJPF_XRGB:
434 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
435 FROMRGB(4, 1, 2, 3,); return;
436 #endif
437 break;
438 case TJPF_ARGB:
439 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
440 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
441 #endif
442 break;
443 case TJPF_XBGR:
444 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
445 FROMRGB(4, 3, 2, 1,); return;
446 #endif
447 break;
448 case TJPF_ABGR:
449 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
450 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
451 #endif
452 break;
453 }
454}
455
456#endif
457
458
DRC9b28def2011-05-21 14:37:15 +0000459/* General API functions */
460
461DLLEXPORT char* DLLCALL tjGetErrorStr(void)
462{
463 return errStr;
464}
465
466
467DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
468{
469 getinstance(handle);
470 if(setjmp(this->jerr.setjmp_buffer)) return -1;
471 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
472 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
473 free(this);
474 return 0;
475}
476
477
DRC6b76f752011-05-24 16:52:47 +0000478/* These are exposed mainly because Windows can't malloc() and free() across
479 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
480 with turbojpeg.dll for compatibility reasons. However, these functions
481 can potentially be used for other purposes by different implementations. */
482
483DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
484{
485 if(buf) free(buf);
486}
487
488
489DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
490{
491 return (unsigned char *)malloc(bytes);
492}
493
494
DRC9b28def2011-05-21 14:37:15 +0000495/* Compressor */
496
497static tjhandle _tjInitCompress(tjinstance *this)
498{
499 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
500
501 /* This is also straight out of example.c */
502 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
503 this->jerr.pub.error_exit=my_error_exit;
504 this->jerr.pub.output_message=my_output_message;
505
506 if(setjmp(this->jerr.setjmp_buffer))
507 {
508 /* If we get here, the JPEG code has signaled an error. */
509 if(this) free(this); return NULL;
510 }
511
512 jpeg_create_compress(&this->cinfo);
513 /* Make an initial call so it will create the destination manager */
514 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
515
DRC007a42c2011-05-22 13:55:56 +0000516 this->init|=COMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000517 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000518}
519
DRC890f1e02011-02-26 22:02:37 +0000520DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
521{
DRC9b28def2011-05-21 14:37:15 +0000522 tjinstance *this=NULL;
523 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000524 {
DRC007a42c2011-05-22 13:55:56 +0000525 snprintf(errStr, JMSG_LENGTH_MAX,
526 "tjInitCompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000527 return NULL;
528 }
DRC007a42c2011-05-22 13:55:56 +0000529 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000530 return _tjInitCompress(this);
DRC890f1e02011-02-26 22:02:37 +0000531}
532
DRC84241602011-02-25 02:08:23 +0000533
DRC9b49f0e2011-07-12 03:17:23 +0000534DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
535 int jpegSubsamp)
536{
537 unsigned long retval=0; int mcuw, mcuh, chromasf;
538 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
539 _throw("tjBufSize(): Invalid argument");
540
541 // This allows for rare corner cases in which a JPEG image can actually be
542 // larger than the uncompressed input (we wouldn't mention it if it hadn't
543 // happened before.)
544 mcuw=tjMCUWidth[jpegSubsamp];
545 mcuh=tjMCUHeight[jpegSubsamp];
546 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
547 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
548
549 bailout:
550 return retval;
551}
552
DRC2e7b76b2009-04-03 12:04:24 +0000553DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
554{
DRCf3cf9732011-02-22 00:16:14 +0000555 unsigned long retval=0;
556 if(width<1 || height<1)
DRC007a42c2011-05-22 13:55:56 +0000557 _throw("TJBUFSIZE(): Invalid argument");
DRCf3cf9732011-02-22 00:16:14 +0000558
559 // This allows for rare corner cases in which a JPEG image can actually be
560 // larger than the uncompressed input (we wouldn't mention it if it hadn't
DRCb28fc572011-02-22 06:41:29 +0000561 // happened before.)
DRC007a42c2011-05-22 13:55:56 +0000562 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
DRCf3cf9732011-02-22 00:16:14 +0000563
564 bailout:
565 return retval;
566}
567
DRC84241602011-02-25 02:08:23 +0000568
DRCf610d612013-04-26 10:33:29 +0000569DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
DRCf3cf9732011-02-22 00:16:14 +0000570 int subsamp)
571{
572 unsigned long retval=0;
573 int pw, ph, cw, ch;
DRCf610d612013-04-26 10:33:29 +0000574 if(width<1 || height<1 || pad<1 || !isPow2(pad) || subsamp<0
575 || subsamp>=NUMSUBOPT)
576 _throw("tjBufSizeYUV2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000577 pw=PAD(width, tjMCUWidth[subsamp]/8);
578 ph=PAD(height, tjMCUHeight[subsamp]/8);
579 cw=pw*8/tjMCUWidth[subsamp]; ch=ph*8/tjMCUHeight[subsamp];
DRCf610d612013-04-26 10:33:29 +0000580 retval=PAD(pw, pad)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, pad)*ch*2);
DRCf3cf9732011-02-22 00:16:14 +0000581
582 bailout:
583 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000584}
585
DRCf610d612013-04-26 10:33:29 +0000586DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
587 int subsamp)
588{
589 return tjBufSizeYUV2(width, 4, height, subsamp);
590}
DRC84241602011-02-25 02:08:23 +0000591
DRC9b49f0e2011-07-12 03:17:23 +0000592DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
593 int subsamp)
594{
595 return tjBufSizeYUV(width, height, subsamp);
596}
597
598
DRC9b28def2011-05-21 14:37:15 +0000599DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
600 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
601 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
602{
DRCff78e372011-05-24 10:17:32 +0000603 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
DRCafc06922012-03-23 19:47:57 +0000604 #ifndef JCS_EXTENSIONS
605 unsigned char *rgbBuf=NULL;
606 #endif
DRC9b28def2011-05-21 14:37:15 +0000607
608 getinstance(handle)
609 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000610 _throw("tjCompress2(): Instance has not been initialized for compression");
DRC9b28def2011-05-21 14:37:15 +0000611
612 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
613 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
614 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
DRC007a42c2011-05-22 13:55:56 +0000615 _throw("tjCompress2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000616
617 if(setjmp(this->jerr.setjmp_buffer))
618 {
619 /* If we get here, the JPEG code has signaled an error. */
620 retval=-1;
621 goto bailout;
622 }
623
624 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
625
DRCafc06922012-03-23 19:47:57 +0000626 #ifndef JCS_EXTENSIONS
627 if(pixelFormat!=TJPF_GRAY)
628 {
629 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
630 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
631 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
632 pitch=width*RGB_PIXELSIZE;
633 }
634 #endif
635
DRC9b28def2011-05-21 14:37:15 +0000636 cinfo->image_width=width;
637 cinfo->image_height=height;
638
DRC25b995a2011-05-21 15:34:54 +0000639 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
640 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
641 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000642
DRCff78e372011-05-24 10:17:32 +0000643 if(flags&TJFLAG_NOREALLOC)
644 {
DRC9b49f0e2011-07-12 03:17:23 +0000645 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +0000646 }
647 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
DRC73d74c12012-06-29 23:46:38 +0000648 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
DRCf12bb302011-09-07 05:03:18 +0000649 return -1;
DRC9b28def2011-05-21 14:37:15 +0000650
651 jpeg_start_compress(cinfo, TRUE);
652 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000653 _throw("tjCompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000654 for(i=0; i<height; i++)
655 {
DRC25b995a2011-05-21 15:34:54 +0000656 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000657 else row_pointer[i]=&srcBuf[i*pitch];
658 }
659 while(cinfo->next_scanline<cinfo->image_height)
660 {
661 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
662 cinfo->image_height-cinfo->next_scanline);
663 }
664 jpeg_finish_compress(cinfo);
665
666 bailout:
667 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000668 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000669 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000670 #endif
DRC9b28def2011-05-21 14:37:15 +0000671 if(row_pointer) free(row_pointer);
672 return retval;
673}
674
675DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
676 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
677 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
678{
679 int retval=0; unsigned long size;
680 if(flags&TJ_YUV)
681 {
DRC9b49f0e2011-07-12 03:17:23 +0000682 size=tjBufSizeYUV(width, height, jpegSubsamp);
DRC9b28def2011-05-21 14:37:15 +0000683 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
684 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
685 }
686 else
687 {
DRC9b28def2011-05-21 14:37:15 +0000688 retval=tjCompress2(handle, srcBuf, width, pitch, height,
689 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
DRC25b995a2011-05-21 15:34:54 +0000690 flags|TJFLAG_NOREALLOC);
DRC9b28def2011-05-21 14:37:15 +0000691 }
692 *jpegSize=size;
693 return retval;
694}
695
696
DRCf610d612013-04-26 10:33:29 +0000697DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle, unsigned char *srcBuf,
DRC9b28def2011-05-21 14:37:15 +0000698 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
DRCf610d612013-04-26 10:33:29 +0000699 int pad, int subsamp, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000700{
DRC91e86ba2011-02-15 05:24:08 +0000701 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000702 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
703 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
704 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC9b28def2011-05-21 14:37:15 +0000705 int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
706 JSAMPLE *ptr=dstBuf;
DRCafc06922012-03-23 19:47:57 +0000707 unsigned long yuvsize=0;
DRC9b28def2011-05-21 14:37:15 +0000708 jpeg_component_info *compptr;
DRCafc06922012-03-23 19:47:57 +0000709 #ifndef JCS_EXTENSIONS
710 unsigned char *rgbBuf=NULL;
711 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000712
DRCfbb67472010-11-24 04:02:37 +0000713 for(i=0; i<MAX_COMPONENTS; i++)
714 {
715 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
716 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
717 }
718
DRCe2f8e692013-10-30 22:21:06 +0000719 getinstance(handle);
720 if((this->init&COMPRESS)==0)
721 _throw("tjEncodeYUV3(): Instance has not been initialized for compression");
722
DRC9b28def2011-05-21 14:37:15 +0000723 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
DRCf610d612013-04-26 10:33:29 +0000724 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || pad<0 || !isPow2(pad)
725 || subsamp<0 || subsamp>=NUMSUBOPT)
726 _throw("tjEncodeYUV3(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000727
DRC9b28def2011-05-21 14:37:15 +0000728 if(setjmp(this->jerr.setjmp_buffer))
729 {
730 /* If we get here, the JPEG code has signaled an error. */
731 retval=-1;
732 goto bailout;
733 }
DRC2e7b76b2009-04-03 12:04:24 +0000734
DRCcd7c3e62013-08-23 02:49:25 +0000735 if(pixelFormat==TJPF_CMYK)
736 _throw("tjEncodeYUV3(): Cannot generate YUV images from CMYK pixels");
737
DRC9b28def2011-05-21 14:37:15 +0000738 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC2e7b76b2009-04-03 12:04:24 +0000739
DRCafc06922012-03-23 19:47:57 +0000740 #ifndef JCS_EXTENSIONS
741 if(pixelFormat!=TJPF_GRAY)
742 {
743 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
DRCf610d612013-04-26 10:33:29 +0000744 if(!rgbBuf) _throw("tjEncodeYUV3(): Memory allocation failure");
DRCafc06922012-03-23 19:47:57 +0000745 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
746 pitch=width*RGB_PIXELSIZE;
747 }
748 #endif
749
DRC9b28def2011-05-21 14:37:15 +0000750 cinfo->image_width=width;
751 cinfo->image_height=height;
DRC2e7b76b2009-04-03 12:04:24 +0000752
DRC25b995a2011-05-21 15:34:54 +0000753 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
754 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
755 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000756
DRCf610d612013-04-26 10:33:29 +0000757 yuvsize=tjBufSizeYUV2(width, pad, height, subsamp);
DRC9b28def2011-05-21 14:37:15 +0000758 jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0);
DRC73d74c12012-06-29 23:46:38 +0000759 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000760
DRC9b28def2011-05-21 14:37:15 +0000761 jpeg_start_compress(cinfo, TRUE);
762 pw=PAD(width, cinfo->max_h_samp_factor);
763 ph=PAD(height, cinfo->max_v_samp_factor);
DRC2e7b76b2009-04-03 12:04:24 +0000764
DRC9b28def2011-05-21 14:37:15 +0000765 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
DRCf610d612013-04-26 10:33:29 +0000766 _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000767 for(i=0; i<height; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000768 {
DRC25b995a2011-05-21 15:34:54 +0000769 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000770 else row_pointer[i]=&srcBuf[i*pitch];
771 }
772 if(height<ph)
773 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
DRCfbb67472010-11-24 04:02:37 +0000774
DRC9b28def2011-05-21 14:37:15 +0000775 for(i=0; i<cinfo->num_components; i++)
776 {
777 compptr=&cinfo->comp_info[i];
778 _tmpbuf[i]=(JSAMPLE *)malloc(
779 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
780 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRCf610d612013-04-26 10:33:29 +0000781 if(!_tmpbuf[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000782 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRCf610d612013-04-26 10:33:29 +0000783 if(!tmpbuf[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000784 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRCfbb67472010-11-24 04:02:37 +0000785 {
DRC9b28def2011-05-21 14:37:15 +0000786 unsigned char *_tmpbuf_aligned=
787 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
788 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000789 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC9b28def2011-05-21 14:37:15 +0000790 /compptr->h_samp_factor, 16) * row];
DRCfbb67472010-11-24 04:02:37 +0000791 }
DRC9b28def2011-05-21 14:37:15 +0000792 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
793 * compptr->v_samp_factor + 16);
DRCf610d612013-04-26 10:33:29 +0000794 if(!_tmpbuf2[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000795 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCf610d612013-04-26 10:33:29 +0000796 if(!tmpbuf2[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000797 for(row=0; row<compptr->v_samp_factor; row++)
798 {
799 unsigned char *_tmpbuf2_aligned=
800 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
801 tmpbuf2[i][row]=&_tmpbuf2_aligned[
802 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
803 }
804 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
805 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
806 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
DRCf610d612013-04-26 10:33:29 +0000807 if(!outbuf[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000808 for(row=0; row<ch[i]; row++)
809 {
810 outbuf[i][row]=ptr;
DRCf610d612013-04-26 10:33:29 +0000811 ptr+=PAD(cw[i], pad);
DRC9b28def2011-05-21 14:37:15 +0000812 }
813 }
814 if(yuvsize!=(unsigned long)(ptr-dstBuf))
DRCf610d612013-04-26 10:33:29 +0000815 _throw("tjEncodeYUV3(): Generated image is not the correct size");
DRCfbb67472010-11-24 04:02:37 +0000816
DRC9b28def2011-05-21 14:37:15 +0000817 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
DRCfbb67472010-11-24 04:02:37 +0000818 {
DRC9b28def2011-05-21 14:37:15 +0000819 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
820 cinfo->max_v_samp_factor);
821 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
822 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
823 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
824 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
825 compptr->v_samp_factor, cw[i]);
DRC6ee54592011-03-01 08:18:30 +0000826 }
DRC9b28def2011-05-21 14:37:15 +0000827 cinfo->next_scanline+=height;
828 jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000829
DRC91e86ba2011-02-15 05:24:08 +0000830 bailout:
DRC9b28def2011-05-21 14:37:15 +0000831 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000832 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000833 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000834 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000835 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000836 for(i=0; i<MAX_COMPONENTS; i++)
837 {
838 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000839 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000840 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000841 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000842 if(outbuf[i]!=NULL) free(outbuf[i]);
843 }
DRC91e86ba2011-02-15 05:24:08 +0000844 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000845}
846
DRCf610d612013-04-26 10:33:29 +0000847DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
848 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
849 int subsamp, int flags)
850{
851 return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
852 dstBuf, 4, subsamp, flags);
853}
854
DRC9b28def2011-05-21 14:37:15 +0000855DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
856 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
857 int subsamp, int flags)
DRC84241602011-02-25 02:08:23 +0000858{
DRC9b28def2011-05-21 14:37:15 +0000859 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
860 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
DRC84241602011-02-25 02:08:23 +0000861}
862
863
DRC9b28def2011-05-21 14:37:15 +0000864/* Decompressor */
DRC2e7b76b2009-04-03 12:04:24 +0000865
DRC9b28def2011-05-21 14:37:15 +0000866static tjhandle _tjInitDecompress(tjinstance *this)
DRC2e7b76b2009-04-03 12:04:24 +0000867{
DRC9b28def2011-05-21 14:37:15 +0000868 unsigned char buffer[1];
DRC2e7b76b2009-04-03 12:04:24 +0000869
DRC9b28def2011-05-21 14:37:15 +0000870 /* This is also straight out of example.c */
871 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
872 this->jerr.pub.error_exit=my_error_exit;
873 this->jerr.pub.output_message=my_output_message;
DRC2e7b76b2009-04-03 12:04:24 +0000874
DRC9b28def2011-05-21 14:37:15 +0000875 if(setjmp(this->jerr.setjmp_buffer))
876 {
877 /* If we get here, the JPEG code has signaled an error. */
878 if(this) free(this); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +0000879 }
DRC2e7b76b2009-04-03 12:04:24 +0000880
DRC9b28def2011-05-21 14:37:15 +0000881 jpeg_create_decompress(&this->dinfo);
882 /* Make an initial call so it will create the source manager */
883 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +0000884
DRC007a42c2011-05-22 13:55:56 +0000885 this->init|=DECOMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000886 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000887}
888
DRC890f1e02011-02-26 22:02:37 +0000889DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
890{
DRC9b28def2011-05-21 14:37:15 +0000891 tjinstance *this;
892 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000893 {
DRC007a42c2011-05-22 13:55:56 +0000894 snprintf(errStr, JMSG_LENGTH_MAX,
895 "tjInitDecompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000896 return NULL;
897 }
DRC007a42c2011-05-22 13:55:56 +0000898 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000899 return _tjInitDecompress(this);
DRC890f1e02011-02-26 22:02:37 +0000900}
901
DRC2e7b76b2009-04-03 12:04:24 +0000902
DRCcd7c3e62013-08-23 02:49:25 +0000903DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
DRC9b28def2011-05-21 14:37:15 +0000904 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
DRCcd7c3e62013-08-23 02:49:25 +0000905 int *jpegSubsamp, int *jpegColorspace)
DRC1fe80f82010-12-14 01:21:29 +0000906{
DRC9b49f0e2011-07-12 03:17:23 +0000907 int retval=0;
DRC1fe80f82010-12-14 01:21:29 +0000908
DRC9b28def2011-05-21 14:37:15 +0000909 getinstance(handle);
910 if((this->init&DECOMPRESS)==0)
DRCcd7c3e62013-08-23 02:49:25 +0000911 _throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
DRC1fe80f82010-12-14 01:21:29 +0000912
DRC9b28def2011-05-21 14:37:15 +0000913 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
DRCcd7c3e62013-08-23 02:49:25 +0000914 || jpegSubsamp==NULL || jpegColorspace==NULL)
915 _throw("tjDecompressHeader3(): Invalid argument");
DRC1fe80f82010-12-14 01:21:29 +0000916
DRC9b28def2011-05-21 14:37:15 +0000917 if(setjmp(this->jerr.setjmp_buffer))
918 {
919 /* If we get here, the JPEG code has signaled an error. */
DRC1fe80f82010-12-14 01:21:29 +0000920 return -1;
921 }
922
DRC9b28def2011-05-21 14:37:15 +0000923 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
924 jpeg_read_header(dinfo, TRUE);
DRC1fe80f82010-12-14 01:21:29 +0000925
DRC9b28def2011-05-21 14:37:15 +0000926 *width=dinfo->image_width;
927 *height=dinfo->image_height;
DRC9b49f0e2011-07-12 03:17:23 +0000928 *jpegSubsamp=getSubsamp(dinfo);
DRCcd7c3e62013-08-23 02:49:25 +0000929 switch(dinfo->jpeg_color_space)
930 {
931 case JCS_GRAYSCALE: *jpegColorspace=TJCS_GRAY; break;
932 case JCS_RGB: *jpegColorspace=TJCS_RGB; break;
933 case JCS_YCbCr: *jpegColorspace=TJCS_YCbCr; break;
934 case JCS_CMYK: *jpegColorspace=TJCS_CMYK; break;
935 case JCS_YCCK: *jpegColorspace=TJCS_YCCK; break;
936 default: *jpegColorspace=-1; break;
937 }
DRC1fe80f82010-12-14 01:21:29 +0000938
DRC9b28def2011-05-21 14:37:15 +0000939 jpeg_abort_decompress(dinfo);
DRC1fe80f82010-12-14 01:21:29 +0000940
DRC9b28def2011-05-21 14:37:15 +0000941 if(*jpegSubsamp<0)
DRCcd7c3e62013-08-23 02:49:25 +0000942 _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
943 if(*jpegColorspace<0)
944 _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
DRC007a42c2011-05-22 13:55:56 +0000945 if(*width<1 || *height<1)
DRCcd7c3e62013-08-23 02:49:25 +0000946 _throw("tjDecompressHeader3(): Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +0000947
948 bailout:
949 return retval;
950}
951
DRCcd7c3e62013-08-23 02:49:25 +0000952DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
953 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
954 int *jpegSubsamp)
955{
956 int jpegColorspace;
957 return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
958 jpegSubsamp, &jpegColorspace);
959}
960
DRC9b28def2011-05-21 14:37:15 +0000961DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
962 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
DRC91e86ba2011-02-15 05:24:08 +0000963{
DRC9b28def2011-05-21 14:37:15 +0000964 int jpegSubsamp;
965 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
966 &jpegSubsamp);
DRC1fe80f82010-12-14 01:21:29 +0000967}
968
969
DRC109a5782011-03-01 09:53:07 +0000970DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +0000971{
DRC109a5782011-03-01 09:53:07 +0000972 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +0000973 {
DRC9b28def2011-05-21 14:37:15 +0000974 snprintf(errStr, JMSG_LENGTH_MAX,
DRC007a42c2011-05-22 13:55:56 +0000975 "tjGetScalingFactors(): Invalid argument");
DRC109a5782011-03-01 09:53:07 +0000976 return NULL;
DRCb28fc572011-02-22 06:41:29 +0000977 }
978
DRC109a5782011-03-01 09:53:07 +0000979 *numscalingfactors=NUMSF;
980 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +0000981}
982
983
DRC9b28def2011-05-21 14:37:15 +0000984DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
985 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
986 int height, int pixelFormat, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000987{
DRC9b28def2011-05-21 14:37:15 +0000988 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRC109a5782011-03-01 09:53:07 +0000989 int jpegwidth, jpegheight, scaledw, scaledh;
DRCafc06922012-03-23 19:47:57 +0000990 #ifndef JCS_EXTENSIONS
991 unsigned char *rgbBuf=NULL;
992 unsigned char *_dstBuf=NULL; int _pitch=0;
993 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000994
DRC9b28def2011-05-21 14:37:15 +0000995 getinstance(handle);
996 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000997 _throw("tjDecompress2(): Instance has not been initialized for decompression");
DRC9b28def2011-05-21 14:37:15 +0000998
999 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
1000 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
1001 _throw("tjDecompress2(): Invalid argument");
1002
DRC25b995a2011-05-21 15:34:54 +00001003 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1004 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1005 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +00001006
1007 if(setjmp(this->jerr.setjmp_buffer))
1008 {
1009 /* If we get here, the JPEG code has signaled an error. */
1010 retval=-1;
1011 goto bailout;
1012 }
1013
1014 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1015 jpeg_read_header(dinfo, TRUE);
DRC73d74c12012-06-29 23:46:38 +00001016 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
DRC2eda8212012-03-23 19:32:38 +00001017 {
1018 retval=-1; goto bailout;
1019 }
DRC9b28def2011-05-21 14:37:15 +00001020
DRC25b995a2011-05-21 15:34:54 +00001021 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +00001022
1023 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1024 if(width==0) width=jpegwidth;
1025 if(height==0) height=jpegheight;
1026 for(i=0; i<NUMSF; i++)
1027 {
1028 scaledw=TJSCALED(jpegwidth, sf[i]);
1029 scaledh=TJSCALED(jpegheight, sf[i]);
1030 if(scaledw<=width && scaledh<=height)
DRCf610d612013-04-26 10:33:29 +00001031 break;
DRC9b28def2011-05-21 14:37:15 +00001032 }
1033 if(scaledw>width || scaledh>height)
DRC007a42c2011-05-22 13:55:56 +00001034 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
DRC9b28def2011-05-21 14:37:15 +00001035 width=scaledw; height=scaledh;
1036 dinfo->scale_num=sf[i].num;
1037 dinfo->scale_denom=sf[i].denom;
1038
1039 jpeg_start_decompress(dinfo);
1040 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
DRCafc06922012-03-23 19:47:57 +00001041
1042 #ifndef JCS_EXTENSIONS
1043 if(pixelFormat!=TJPF_GRAY &&
1044 (RGB_RED!=tjRedOffset[pixelFormat] ||
1045 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1046 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1047 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1048 {
1049 rgbBuf=(unsigned char *)malloc(width*height*3);
1050 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1051 _pitch=pitch; pitch=width*3;
1052 _dstBuf=dstBuf; dstBuf=rgbBuf;
1053 }
1054 #endif
1055
DRC9b28def2011-05-21 14:37:15 +00001056 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1057 *dinfo->output_height))==NULL)
DRC007a42c2011-05-22 13:55:56 +00001058 _throw("tjDecompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001059 for(i=0; i<(int)dinfo->output_height; i++)
1060 {
DRC25b995a2011-05-21 15:34:54 +00001061 if(flags&TJFLAG_BOTTOMUP)
DRC9b28def2011-05-21 14:37:15 +00001062 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1063 else row_pointer[i]=&dstBuf[i*pitch];
1064 }
1065 while(dinfo->output_scanline<dinfo->output_height)
1066 {
1067 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1068 dinfo->output_height-dinfo->output_scanline);
1069 }
1070 jpeg_finish_decompress(dinfo);
1071
DRCafc06922012-03-23 19:47:57 +00001072 #ifndef JCS_EXTENSIONS
1073 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1074 #endif
1075
DRC9b28def2011-05-21 14:37:15 +00001076 bailout:
1077 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRCafc06922012-03-23 19:47:57 +00001078 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +00001079 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +00001080 #endif
DRC9b28def2011-05-21 14:37:15 +00001081 if(row_pointer) free(row_pointer);
1082 return retval;
1083}
1084
1085DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1086 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1087 int height, int pixelSize, int flags)
1088{
1089 if(flags&TJ_YUV)
1090 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1091 else
1092 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1093 height, getPixelFormat(pixelSize, flags), flags);
1094}
1095
1096
DRCf610d612013-04-26 10:33:29 +00001097DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
DRC9b28def2011-05-21 14:37:15 +00001098 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
DRCf610d612013-04-26 10:33:29 +00001099 int width, int pad, int height, int flags)
DRC9b28def2011-05-21 14:37:15 +00001100{
DRCf610d612013-04-26 10:33:29 +00001101 int i, sfi, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001102 int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
DRC9b28def2011-05-21 14:37:15 +00001103 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1104 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1105 JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001106 int dctsize;
DRC9b28def2011-05-21 14:37:15 +00001107
DRCf9cf5c72010-12-10 10:58:49 +00001108 for(i=0; i<MAX_COMPONENTS; i++)
1109 {
1110 tmpbuf[i]=NULL; outbuf[i]=NULL;
1111 }
DRC9e17f7d2010-12-10 04:59:13 +00001112
DRCe2f8e692013-10-30 22:21:06 +00001113 getinstance(handle);
1114 if((this->init&DECOMPRESS)==0)
1115 _throw("tjDecompressToYUV2(): Instance has not been initialized for decompression");
1116
DRCf610d612013-04-26 10:33:29 +00001117 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
1118 || !isPow2(pad) || height<0)
1119 _throw("tjDecompressToYUV2(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001120
DRC25b995a2011-05-21 15:34:54 +00001121 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1122 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1123 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +00001124
DRC9b28def2011-05-21 14:37:15 +00001125 if(setjmp(this->jerr.setjmp_buffer))
1126 {
1127 /* If we get here, the JPEG code has signaled an error. */
DRC91e86ba2011-02-15 05:24:08 +00001128 retval=-1;
1129 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +00001130 }
DRC2e7b76b2009-04-03 12:04:24 +00001131
DRC9b28def2011-05-21 14:37:15 +00001132 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1133 jpeg_read_header(dinfo, TRUE);
DRC418fe282013-05-07 21:17:35 +00001134 jpegSubsamp=getSubsamp(dinfo);
1135 if(jpegSubsamp<0)
1136 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC2e7b76b2009-04-03 12:04:24 +00001137
DRCf610d612013-04-26 10:33:29 +00001138 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1139 if(width==0) width=jpegwidth;
1140 if(height==0) height=jpegheight;
1141 for(i=0; i<NUMSF; i++)
1142 {
1143 scaledw=TJSCALED(jpegwidth, sf[i]);
1144 scaledh=TJSCALED(jpegheight, sf[i]);
1145 if(scaledw<=width && scaledh<=height)
1146 break;
1147 }
1148 if(scaledw>width || scaledh>height)
1149 _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
DRCcd7c3e62013-08-23 02:49:25 +00001150 if(dinfo->num_components>3)
1151 _throw("tjDecompressToYUV2(): JPEG image must have 3 or fewer components");
1152
DRCf610d612013-04-26 10:33:29 +00001153 width=scaledw; height=scaledh;
1154 dinfo->scale_num=sf[i].num;
1155 dinfo->scale_denom=sf[i].denom;
1156 sfi=i;
1157 jpeg_calc_output_dimensions(dinfo);
1158
DRC418fe282013-05-07 21:17:35 +00001159 dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
1160
DRC9b28def2011-05-21 14:37:15 +00001161 for(i=0; i<dinfo->num_components; i++)
DRC2e7b76b2009-04-03 12:04:24 +00001162 {
DRC9b28def2011-05-21 14:37:15 +00001163 jpeg_component_info *compptr=&dinfo->comp_info[i];
1164 int ih;
DRC418fe282013-05-07 21:17:35 +00001165 iw[i]=compptr->width_in_blocks*dctsize;
1166 ih=compptr->height_in_blocks*dctsize;
DRCf610d612013-04-26 10:33:29 +00001167 cw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001168 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
DRCf610d612013-04-26 10:33:29 +00001169 ch[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001170 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
1171 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
DRC418fe282013-05-07 21:17:35 +00001172 th[i]=compptr->v_samp_factor*dctsize;
DRC9b28def2011-05-21 14:37:15 +00001173 tmpbufsize+=iw[i]*th[i];
1174 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
DRCf610d612013-04-26 10:33:29 +00001175 _throw("tjDecompressToYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001176 for(row=0; row<ch[i]; row++)
1177 {
1178 outbuf[i][row]=ptr;
DRCf610d612013-04-26 10:33:29 +00001179 ptr+=PAD(cw[i], pad);
DRC9b28def2011-05-21 14:37:15 +00001180 }
1181 }
1182 if(usetmpbuf)
1183 {
1184 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRCf610d612013-04-26 10:33:29 +00001185 _throw("tjDecompressToYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001186 ptr=_tmpbuf;
1187 for(i=0; i<dinfo->num_components; i++)
1188 {
1189 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRCf610d612013-04-26 10:33:29 +00001190 _throw("tjDecompressToYUV2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001191 for(row=0; row<th[i]; row++)
1192 {
1193 tmpbuf[i][row]=ptr;
1194 ptr+=iw[i];
1195 }
1196 }
1197 }
DRC9e17f7d2010-12-10 04:59:13 +00001198
DRC25b995a2011-05-21 15:34:54 +00001199 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRCe0419b52012-07-03 20:01:31 +00001200 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
DRC9b28def2011-05-21 14:37:15 +00001201 dinfo->raw_data_out=TRUE;
1202
1203 jpeg_start_decompress(dinfo);
1204 for(row=0; row<(int)dinfo->output_height;
DRC418fe282013-05-07 21:17:35 +00001205 row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
DRC9b28def2011-05-21 14:37:15 +00001206 {
1207 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1208 int crow[MAX_COMPONENTS];
DRC9e17f7d2010-12-10 04:59:13 +00001209 for(i=0; i<dinfo->num_components; i++)
1210 {
1211 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRC418fe282013-05-07 21:17:35 +00001212 if(jpegSubsamp==TJ_420)
1213 {
1214 /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1215 to be clever and use the IDCT to perform upsampling on the U and V
1216 planes. For instance, if the output image is to be scaled by 1/2
1217 relative to the JPEG image, then the scaling factor and upsampling
1218 effectively cancel each other, so a normal 8x8 IDCT can be used.
1219 However, this is not desirable when using the decompress-to-YUV
1220 functionality in TurboJPEG, since we want to output the U and V
1221 planes in their subsampled form. Thus, we have to override some
1222 internal libjpeg parameters to force it to use the "scaled" IDCT
1223 functions on the U and V planes. */
1224 compptr->_DCT_scaled_size=dctsize;
1225 compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
1226 sf[sfi].num/sf[sfi].denom*
1227 compptr->v_samp_factor/dinfo->max_v_samp_factor;
1228 dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1229 }
DRC9b28def2011-05-21 14:37:15 +00001230 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1231 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1232 else yuvptr[i]=&outbuf[i][crow[i]];
DRCf9cf5c72010-12-10 10:58:49 +00001233 }
DRCf610d612013-04-26 10:33:29 +00001234 jpeg_read_raw_data(dinfo, yuvptr,
DRC418fe282013-05-07 21:17:35 +00001235 dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
DRCf9cf5c72010-12-10 10:58:49 +00001236 if(usetmpbuf)
1237 {
DRC9b28def2011-05-21 14:37:15 +00001238 int j;
DRCf9cf5c72010-12-10 10:58:49 +00001239 for(i=0; i<dinfo->num_components; i++)
1240 {
DRC9b28def2011-05-21 14:37:15 +00001241 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +00001242 {
DRC9b28def2011-05-21 14:37:15 +00001243 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001244 }
DRC9e17f7d2010-12-10 04:59:13 +00001245 }
1246 }
1247 }
DRC9b28def2011-05-21 14:37:15 +00001248 jpeg_finish_decompress(dinfo);
DRC2e7b76b2009-04-03 12:04:24 +00001249
DRC91e86ba2011-02-15 05:24:08 +00001250 bailout:
DRC9b28def2011-05-21 14:37:15 +00001251 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC9e17f7d2010-12-10 04:59:13 +00001252 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +00001253 {
1254 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +00001255 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001256 }
1257 if(_tmpbuf) free(_tmpbuf);
DRC91e86ba2011-02-15 05:24:08 +00001258 return retval;
DRC2e7b76b2009-04-03 12:04:24 +00001259}
1260
DRCf610d612013-04-26 10:33:29 +00001261DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1262 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1263 int flags)
1264{
1265 return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1266}
1267
DRC2e7b76b2009-04-03 12:04:24 +00001268
DRC9b28def2011-05-21 14:37:15 +00001269/* Transformer */
DRC890f1e02011-02-26 22:02:37 +00001270
1271DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1272{
DRC9b28def2011-05-21 14:37:15 +00001273 tjinstance *this=NULL; tjhandle handle=NULL;
1274 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00001275 {
DRC007a42c2011-05-22 13:55:56 +00001276 snprintf(errStr, JMSG_LENGTH_MAX,
1277 "tjInitTransform(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00001278 return NULL;
1279 }
DRC007a42c2011-05-22 13:55:56 +00001280 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +00001281 handle=_tjInitCompress(this);
1282 if(!handle) return NULL;
1283 handle=_tjInitDecompress(this);
1284 return handle;
DRC890f1e02011-02-26 22:02:37 +00001285}
1286
1287
DRC9b28def2011-05-21 14:37:15 +00001288DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1289 unsigned long jpegSize, int n, unsigned char **dstBufs,
1290 unsigned long *dstSizes, tjtransform *t, int flags)
DRC890f1e02011-02-26 22:02:37 +00001291{
DRC0a325192011-03-02 09:22:41 +00001292 jpeg_transform_info *xinfo=NULL;
DRC890f1e02011-02-26 22:02:37 +00001293 jvirt_barray_ptr *srccoefs, *dstcoefs;
DRC9b49f0e2011-07-12 03:17:23 +00001294 int retval=0, i, jpegSubsamp;
DRC890f1e02011-02-26 22:02:37 +00001295
DRC9b28def2011-05-21 14:37:15 +00001296 getinstance(handle);
1297 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001298 _throw("tjTransform(): Instance has not been initialized for transformation");
DRC890f1e02011-02-26 22:02:37 +00001299
DRC9b28def2011-05-21 14:37:15 +00001300 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1301 || t==NULL || flags<0)
1302 _throw("tjTransform(): Invalid argument");
1303
DRC25b995a2011-05-21 15:34:54 +00001304 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1305 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1306 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC890f1e02011-02-26 22:02:37 +00001307
DRC9b28def2011-05-21 14:37:15 +00001308 if(setjmp(this->jerr.setjmp_buffer))
1309 {
1310 /* If we get here, the JPEG code has signaled an error. */
DRC890f1e02011-02-26 22:02:37 +00001311 retval=-1;
1312 goto bailout;
1313 }
1314
DRC9b28def2011-05-21 14:37:15 +00001315 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
DRC890f1e02011-02-26 22:02:37 +00001316
DRC0a325192011-03-02 09:22:41 +00001317 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1318 ==NULL)
DRC007a42c2011-05-22 13:55:56 +00001319 _throw("tjTransform(): Memory allocation failure");
1320 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
DRC890f1e02011-02-26 22:02:37 +00001321
DRC0a325192011-03-02 09:22:41 +00001322 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001323 {
DRC0a325192011-03-02 09:22:41 +00001324 xinfo[i].transform=xformtypes[t[i].op];
DRC25b995a2011-05-21 15:34:54 +00001325 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1326 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1327 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1328 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1329 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
DRCba5ea512011-03-04 03:20:34 +00001330 else xinfo[i].slow_hflip=0;
DRC0a325192011-03-02 09:22:41 +00001331
1332 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001333 {
DRC0a325192011-03-02 09:22:41 +00001334 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
1335 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
1336 if(t[i].r.w!=0)
1337 {
1338 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
1339 }
DRCd932e582011-03-15 20:09:47 +00001340 else xinfo[i].crop_width=JCROP_UNSET;
DRC0a325192011-03-02 09:22:41 +00001341 if(t[i].r.h!=0)
1342 {
1343 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
1344 }
DRCd932e582011-03-15 20:09:47 +00001345 else xinfo[i].crop_height=JCROP_UNSET;
DRC890f1e02011-02-26 22:02:37 +00001346 }
1347 }
1348
DRC9b28def2011-05-21 14:37:15 +00001349 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1350 jpeg_read_header(dinfo, TRUE);
DRC9b49f0e2011-07-12 03:17:23 +00001351 jpegSubsamp=getSubsamp(dinfo);
1352 if(jpegSubsamp<0)
1353 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC890f1e02011-02-26 22:02:37 +00001354
DRC0a325192011-03-02 09:22:41 +00001355 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001356 {
DRC9b28def2011-05-21 14:37:15 +00001357 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
DRC007a42c2011-05-22 13:55:56 +00001358 _throw("tjTransform(): Transform is not perfect");
DRC890f1e02011-02-26 22:02:37 +00001359
DRC0a325192011-03-02 09:22:41 +00001360 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001361 {
DRC0a325192011-03-02 09:22:41 +00001362 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1363 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1364 {
DRC9b28def2011-05-21 14:37:15 +00001365 snprintf(errStr, JMSG_LENGTH_MAX,
DRC0a325192011-03-02 09:22:41 +00001366 "To crop this JPEG image, x must be a multiple of %d\n"
1367 "and y must be a multiple of %d.\n",
1368 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1369 retval=-1; goto bailout;
1370 }
DRC890f1e02011-02-26 22:02:37 +00001371 }
1372 }
1373
DRC9b28def2011-05-21 14:37:15 +00001374 srccoefs=jpeg_read_coefficients(dinfo);
DRC890f1e02011-02-26 22:02:37 +00001375
DRC0a325192011-03-02 09:22:41 +00001376 for(i=0; i<n; i++)
1377 {
DRCff78e372011-05-24 10:17:32 +00001378 int w, h, alloc=1;
DRC0a325192011-03-02 09:22:41 +00001379 if(!xinfo[i].crop)
1380 {
DRC9b28def2011-05-21 14:37:15 +00001381 w=dinfo->image_width; h=dinfo->image_height;
DRC0a325192011-03-02 09:22:41 +00001382 }
1383 else
1384 {
1385 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
1386 }
DRCff78e372011-05-24 10:17:32 +00001387 if(flags&TJFLAG_NOREALLOC)
1388 {
DRC9b49f0e2011-07-12 03:17:23 +00001389 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +00001390 }
DRC7bf04d32011-09-17 00:18:31 +00001391 if(!(t[i].options&TJXOPT_NOOUTPUT))
1392 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
DRC9b28def2011-05-21 14:37:15 +00001393 jpeg_copy_critical_parameters(dinfo, cinfo);
1394 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00001395 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00001396 if(!(t[i].options&TJXOPT_NOOUTPUT))
1397 {
1398 jpeg_write_coefficients(cinfo, dstcoefs);
1399 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1400 }
1401 else jinit_c_master_control(cinfo, TRUE);
DRC9b28def2011-05-21 14:37:15 +00001402 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00001403 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00001404 if(t[i].customFilter)
1405 {
DRCefe28ce2012-01-17 11:48:38 +00001406 int ci, y; JDIMENSION by;
DRC7bf04d32011-09-17 00:18:31 +00001407 for(ci=0; ci<cinfo->num_components; ci++)
1408 {
1409 jpeg_component_info *compptr=&cinfo->comp_info[ci];
1410 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1411 DCTSIZE};
1412 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1413 compptr->height_in_blocks*DCTSIZE};
1414 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1415 {
1416 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1417 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1418 TRUE);
1419 for(y=0; y<compptr->v_samp_factor; y++)
1420 {
1421 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
DRCf5467112011-09-20 05:02:19 +00001422 ci, i, &t[i])==-1)
DRC7bf04d32011-09-17 00:18:31 +00001423 _throw("tjTransform(): Error in custom filter");
1424 arrayRegion.y+=DCTSIZE;
1425 }
1426 }
1427 }
1428 }
1429 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
DRC0a325192011-03-02 09:22:41 +00001430 }
1431
DRC9b28def2011-05-21 14:37:15 +00001432 jpeg_finish_decompress(dinfo);
DRC890f1e02011-02-26 22:02:37 +00001433
DRC890f1e02011-02-26 22:02:37 +00001434 bailout:
DRC9b28def2011-05-21 14:37:15 +00001435 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1436 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC0a325192011-03-02 09:22:41 +00001437 if(xinfo) free(xinfo);
DRC890f1e02011-02-26 22:02:37 +00001438 return retval;
1439}