blob: f51df789aec1c8c5378defacce9568b03014b70d [file] [log] [blame]
hbono@chromium.org98626972011-08-03 03:13:08 +00001/*
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002 * Copyright (C)2009-2016 D. R. Commander. All Rights Reserved.
hbono@chromium.org98626972011-08-03 03:13:08 +00003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * - 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.
27 */
28
noel@chromium.org3395bcc2014-04-14 06:56:00 +000029/* TurboJPEG/LJT: this implements the TurboJPEG API using libjpeg or
30 libjpeg-turbo */
hbono@chromium.org98626972011-08-03 03:13:08 +000031
32#include <stdio.h>
33#include <stdlib.h>
Tom Hudson0d47d2d2016-05-04 13:22:56 -040034#include <ctype.h>
hbono@chromium.org98626972011-08-03 03:13:08 +000035#include <jinclude.h>
36#define JPEG_INTERNALS
37#include <jpeglib.h>
38#include <jerror.h>
39#include <setjmp.h>
40#include "./turbojpeg.h"
41#include "./tjutil.h"
42#include "transupp.h"
Tom Hudson0d47d2d2016-05-04 13:22:56 -040043#include "./jpegcomp.h"
hbono@chromium.org98626972011-08-03 03:13:08 +000044
45extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
46 unsigned long *, boolean);
Tom Hudson0d47d2d2016-05-04 13:22:56 -040047extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
48 unsigned long);
hbono@chromium.org98626972011-08-03 03:13:08 +000049
50#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
Tom Hudson0d47d2d2016-05-04 13:22:56 -040051#define isPow2(x) (((x)&(x-1))==0)
hbono@chromium.org98626972011-08-03 03:13:08 +000052
53
54/* Error handling (based on example in example.c) */
55
56static char errStr[JMSG_LENGTH_MAX]="No error";
57
58struct my_error_mgr
59{
60 struct jpeg_error_mgr pub;
61 jmp_buf setjmp_buffer;
Tom Hudson0d47d2d2016-05-04 13:22:56 -040062 void (*emit_message)(j_common_ptr, int);
63 boolean warning;
hbono@chromium.org98626972011-08-03 03:13:08 +000064};
65typedef struct my_error_mgr *my_error_ptr;
66
67static void my_error_exit(j_common_ptr cinfo)
68{
69 my_error_ptr myerr=(my_error_ptr)cinfo->err;
70 (*cinfo->err->output_message)(cinfo);
71 longjmp(myerr->setjmp_buffer, 1);
72}
73
74/* Based on output_message() in jerror.c */
75
76static void my_output_message(j_common_ptr cinfo)
77{
78 (*cinfo->err->format_message)(cinfo, errStr);
79}
80
Tom Hudson0d47d2d2016-05-04 13:22:56 -040081static void my_emit_message(j_common_ptr cinfo, int msg_level)
82{
83 my_error_ptr myerr=(my_error_ptr)cinfo->err;
84 myerr->emit_message(cinfo, msg_level);
85 if(msg_level<0) myerr->warning=TRUE;
86}
87
hbono@chromium.org98626972011-08-03 03:13:08 +000088
89/* Global structures, macros, etc. */
90
91enum {COMPRESS=1, DECOMPRESS=2};
92
93typedef struct _tjinstance
94{
95 struct jpeg_compress_struct cinfo;
96 struct jpeg_decompress_struct dinfo;
97 struct my_error_mgr jerr;
Tom Hudson0d47d2d2016-05-04 13:22:56 -040098 int init, headerRead;
hbono@chromium.org98626972011-08-03 03:13:08 +000099} tjinstance;
100
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400101static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};
hbono@chromium.org98626972011-08-03 03:13:08 +0000102
103static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
104{
105 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
106 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
107};
108
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000109#define NUMSF 16
hbono@chromium.org98626972011-08-03 03:13:08 +0000110static const tjscalingfactor sf[NUMSF]={
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000111 {2, 1},
112 {15, 8},
113 {7, 4},
114 {13, 8},
115 {3, 2},
116 {11, 8},
117 {5, 4},
118 {9, 8},
hbono@chromium.org98626972011-08-03 03:13:08 +0000119 {1, 1},
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000120 {7, 8},
121 {3, 4},
122 {5, 8},
hbono@chromium.org98626972011-08-03 03:13:08 +0000123 {1, 2},
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000124 {3, 8},
hbono@chromium.org98626972011-08-03 03:13:08 +0000125 {1, 4},
126 {1, 8}
127};
128
129#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
130 retval=-1; goto bailout;}
131#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
132 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
133 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
134 return -1;} \
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400135 cinfo=&this->cinfo; dinfo=&this->dinfo; \
136 this->jerr.warning=FALSE;
137#define getcinstance(handle) tjinstance *this=(tjinstance *)handle; \
138 j_compress_ptr cinfo=NULL; \
139 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
140 return -1;} \
141 cinfo=&this->cinfo; \
142 this->jerr.warning=FALSE;
143#define getdinstance(handle) tjinstance *this=(tjinstance *)handle; \
144 j_decompress_ptr dinfo=NULL; \
145 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
146 return -1;} \
147 dinfo=&this->dinfo; \
148 this->jerr.warning=FALSE;
hbono@chromium.org98626972011-08-03 03:13:08 +0000149
150static int getPixelFormat(int pixelSize, int flags)
151{
152 if(pixelSize==1) return TJPF_GRAY;
153 if(pixelSize==3)
154 {
155 if(flags&TJ_BGR) return TJPF_BGR;
156 else return TJPF_RGB;
157 }
158 if(pixelSize==4)
159 {
160 if(flags&TJ_ALPHAFIRST)
161 {
162 if(flags&TJ_BGR) return TJPF_XBGR;
163 else return TJPF_XRGB;
164 }
165 else
166 {
167 if(flags&TJ_BGR) return TJPF_BGRX;
168 else return TJPF_RGBX;
169 }
170 }
171 return -1;
172}
173
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000174static int setCompDefaults(struct jpeg_compress_struct *cinfo,
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000175 int pixelFormat, int subsamp, int jpegQual, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +0000176{
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000177 int retval=0;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400178 char *env=NULL;
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000179
hbono@chromium.org98626972011-08-03 03:13:08 +0000180 switch(pixelFormat)
181 {
182 case TJPF_GRAY:
183 cinfo->in_color_space=JCS_GRAYSCALE; break;
184 #if JCS_EXTENSIONS==1
185 case TJPF_RGB:
186 cinfo->in_color_space=JCS_EXT_RGB; break;
187 case TJPF_BGR:
188 cinfo->in_color_space=JCS_EXT_BGR; break;
189 case TJPF_RGBX:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000190 case TJPF_RGBA:
hbono@chromium.org98626972011-08-03 03:13:08 +0000191 cinfo->in_color_space=JCS_EXT_RGBX; break;
192 case TJPF_BGRX:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000193 case TJPF_BGRA:
hbono@chromium.org98626972011-08-03 03:13:08 +0000194 cinfo->in_color_space=JCS_EXT_BGRX; break;
195 case TJPF_XRGB:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000196 case TJPF_ARGB:
hbono@chromium.org98626972011-08-03 03:13:08 +0000197 cinfo->in_color_space=JCS_EXT_XRGB; break;
198 case TJPF_XBGR:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000199 case TJPF_ABGR:
hbono@chromium.org98626972011-08-03 03:13:08 +0000200 cinfo->in_color_space=JCS_EXT_XBGR; break;
201 #else
202 case TJPF_RGB:
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000203 case TJPF_BGR:
204 case TJPF_RGBX:
205 case TJPF_BGRX:
206 case TJPF_XRGB:
207 case TJPF_XBGR:
208 case TJPF_RGBA:
209 case TJPF_BGRA:
210 case TJPF_ARGB:
211 case TJPF_ABGR:
212 cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
213 break;
hbono@chromium.org98626972011-08-03 03:13:08 +0000214 #endif
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400215 case TJPF_CMYK:
216 cinfo->in_color_space=JCS_CMYK; break;
hbono@chromium.org98626972011-08-03 03:13:08 +0000217 }
218
219 cinfo->input_components=tjPixelSize[pixelFormat];
220 jpeg_set_defaults(cinfo);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400221
222#ifndef NO_GETENV
223 if((env=getenv("TJ_OPTIMIZE"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
224 cinfo->optimize_coding=TRUE;
225 if((env=getenv("TJ_ARITHMETIC"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
226 cinfo->arith_code=TRUE;
227 if((env=getenv("TJ_RESTART"))!=NULL && strlen(env)>0)
228 {
229 int temp=-1; char tempc=0;
230 if(sscanf(env, "%d%c", &temp, &tempc)>=1 && temp>=0 && temp<=65535)
231 {
232 if(toupper(tempc)=='B')
233 {
234 cinfo->restart_interval=temp;
235 cinfo->restart_in_rows=0;
236 }
237 else
238 cinfo->restart_in_rows=temp;
239 }
240 }
241#endif
242
hbono@chromium.org98626972011-08-03 03:13:08 +0000243 if(jpegQual>=0)
244 {
245 jpeg_set_quality(cinfo, jpegQual, TRUE);
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000246 if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
hbono@chromium.org98626972011-08-03 03:13:08 +0000247 else cinfo->dct_method=JDCT_FASTEST;
248 }
249 if(subsamp==TJSAMP_GRAY)
250 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400251 else if(pixelFormat==TJPF_CMYK)
252 jpeg_set_colorspace(cinfo, JCS_YCCK);
253 else jpeg_set_colorspace(cinfo, JCS_YCbCr);
254
255#ifndef NO_GETENV
256 if((env=getenv("TJ_PROGRESSIVE"))!=NULL && strlen(env)>0
257 && !strcmp(env, "1"))
258 jpeg_simple_progression(cinfo);
259#endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000260
261 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
262 cinfo->comp_info[1].h_samp_factor=1;
263 cinfo->comp_info[2].h_samp_factor=1;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400264 if(cinfo->num_components>3)
265 cinfo->comp_info[3].h_samp_factor=tjMCUWidth[subsamp]/8;
hbono@chromium.org98626972011-08-03 03:13:08 +0000266 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
267 cinfo->comp_info[1].v_samp_factor=1;
268 cinfo->comp_info[2].v_samp_factor=1;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400269 if(cinfo->num_components>3)
270 cinfo->comp_info[3].v_samp_factor=tjMCUHeight[subsamp]/8;
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000271
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000272 return retval;
hbono@chromium.org98626972011-08-03 03:13:08 +0000273}
274
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000275static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000276 int pixelFormat, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +0000277{
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000278 int retval=0;
279
hbono@chromium.org98626972011-08-03 03:13:08 +0000280 switch(pixelFormat)
281 {
282 case TJPF_GRAY:
283 dinfo->out_color_space=JCS_GRAYSCALE; break;
284 #if JCS_EXTENSIONS==1
285 case TJPF_RGB:
286 dinfo->out_color_space=JCS_EXT_RGB; break;
287 case TJPF_BGR:
288 dinfo->out_color_space=JCS_EXT_BGR; break;
289 case TJPF_RGBX:
290 dinfo->out_color_space=JCS_EXT_RGBX; break;
291 case TJPF_BGRX:
292 dinfo->out_color_space=JCS_EXT_BGRX; break;
293 case TJPF_XRGB:
294 dinfo->out_color_space=JCS_EXT_XRGB; break;
295 case TJPF_XBGR:
296 dinfo->out_color_space=JCS_EXT_XBGR; break;
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000297 #if JCS_ALPHA_EXTENSIONS==1
298 case TJPF_RGBA:
299 dinfo->out_color_space=JCS_EXT_RGBA; break;
300 case TJPF_BGRA:
301 dinfo->out_color_space=JCS_EXT_BGRA; break;
302 case TJPF_ARGB:
303 dinfo->out_color_space=JCS_EXT_ARGB; break;
304 case TJPF_ABGR:
305 dinfo->out_color_space=JCS_EXT_ABGR; break;
306 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000307 #else
308 case TJPF_RGB:
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000309 case TJPF_BGR:
310 case TJPF_RGBX:
311 case TJPF_BGRX:
312 case TJPF_XRGB:
313 case TJPF_XBGR:
314 case TJPF_RGBA:
315 case TJPF_BGRA:
316 case TJPF_ARGB:
317 case TJPF_ABGR:
318 dinfo->out_color_space=JCS_RGB; break;
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000319 #endif
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400320 case TJPF_CMYK:
321 dinfo->out_color_space=JCS_CMYK; break;
hbono@chromium.org98626972011-08-03 03:13:08 +0000322 default:
323 _throw("Unsupported pixel format");
hbono@chromium.org98626972011-08-03 03:13:08 +0000324 }
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000325
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000326 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
327
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000328 bailout:
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000329 return retval;
hbono@chromium.org98626972011-08-03 03:13:08 +0000330}
331
332
333static int getSubsamp(j_decompress_ptr dinfo)
334{
335 int retval=-1, i, k;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400336
337 /* The sampling factors actually have no meaning with grayscale JPEG files,
338 and in fact it's possible to generate grayscale JPEGs with sampling
339 factors > 1 (even though those sampling factors are ignored by the
340 decompressor.) Thus, we need to treat grayscale as a special case. */
341 if(dinfo->num_components==1 && dinfo->jpeg_color_space==JCS_GRAYSCALE)
342 return TJSAMP_GRAY;
343
hbono@chromium.org98626972011-08-03 03:13:08 +0000344 for(i=0; i<NUMSUBOPT; i++)
345 {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400346 if(dinfo->num_components==pixelsize[i]
347 || ((dinfo->jpeg_color_space==JCS_YCCK
348 || dinfo->jpeg_color_space==JCS_CMYK)
349 && pixelsize[i]==3 && dinfo->num_components==4))
hbono@chromium.org98626972011-08-03 03:13:08 +0000350 {
351 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
352 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
353 {
354 int match=0;
355 for(k=1; k<dinfo->num_components; k++)
356 {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400357 int href=1, vref=1;
358 if(dinfo->jpeg_color_space==JCS_YCCK && k==3)
359 {
360 href=tjMCUWidth[i]/8; vref=tjMCUHeight[i]/8;
361 }
362 if(dinfo->comp_info[k].h_samp_factor==href
363 && dinfo->comp_info[k].v_samp_factor==vref)
hbono@chromium.org98626972011-08-03 03:13:08 +0000364 match++;
365 }
366 if(match==dinfo->num_components-1)
367 {
368 retval=i; break;
369 }
370 }
371 }
372 }
373 return retval;
374}
375
376
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000377#ifndef JCS_EXTENSIONS
378
379/* Conversion functions to emulate the colorspace extensions. This allows the
380 TurboJPEG wrapper to be used with libjpeg */
381
382#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
383 int rowPad=pitch-width*PS; \
384 while(height--) \
385 { \
386 unsigned char *endOfRow=src+width*PS; \
387 while(src<endOfRow) \
388 { \
389 dst[RGB_RED]=src[ROFFSET]; \
390 dst[RGB_GREEN]=src[GOFFSET]; \
391 dst[RGB_BLUE]=src[BOFFSET]; \
392 dst+=RGB_PIXELSIZE; src+=PS; \
393 } \
394 src+=rowPad; \
395 } \
396}
397
398static unsigned char *toRGB(unsigned char *src, int width, int pitch,
399 int height, int pixelFormat, unsigned char *dst)
400{
401 unsigned char *retval=src;
402 switch(pixelFormat)
403 {
404 case TJPF_RGB:
405 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
406 retval=dst; TORGB(3, 0, 1, 2);
407 #endif
408 break;
409 case TJPF_BGR:
410 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
411 retval=dst; TORGB(3, 2, 1, 0);
412 #endif
413 break;
414 case TJPF_RGBX:
415 case TJPF_RGBA:
416 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
417 retval=dst; TORGB(4, 0, 1, 2);
418 #endif
419 break;
420 case TJPF_BGRX:
421 case TJPF_BGRA:
422 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
423 retval=dst; TORGB(4, 2, 1, 0);
424 #endif
425 break;
426 case TJPF_XRGB:
427 case TJPF_ARGB:
428 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
429 retval=dst; TORGB(4, 1, 2, 3);
430 #endif
431 break;
432 case TJPF_XBGR:
433 case TJPF_ABGR:
434 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
435 retval=dst; TORGB(4, 3, 2, 1);
436 #endif
437 break;
438 }
439 return retval;
440}
441
442#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
443 int rowPad=pitch-width*PS; \
444 while(height--) \
445 { \
446 unsigned char *endOfRow=dst+width*PS; \
447 while(dst<endOfRow) \
448 { \
449 dst[ROFFSET]=src[RGB_RED]; \
450 dst[GOFFSET]=src[RGB_GREEN]; \
451 dst[BOFFSET]=src[RGB_BLUE]; \
452 SETALPHA \
453 dst+=PS; src+=RGB_PIXELSIZE; \
454 } \
455 dst+=rowPad; \
456 } \
457}
458
459static void fromRGB(unsigned char *src, unsigned char *dst, int width,
460 int pitch, int height, int pixelFormat)
461{
462 switch(pixelFormat)
463 {
464 case TJPF_RGB:
465 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
466 FROMRGB(3, 0, 1, 2,);
467 #endif
468 break;
469 case TJPF_BGR:
470 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
471 FROMRGB(3, 2, 1, 0,);
472 #endif
473 break;
474 case TJPF_RGBX:
475 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
476 FROMRGB(4, 0, 1, 2,);
477 #endif
478 break;
479 case TJPF_RGBA:
480 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
481 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
482 #endif
483 break;
484 case TJPF_BGRX:
485 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
486 FROMRGB(4, 2, 1, 0,);
487 #endif
488 break;
489 case TJPF_BGRA:
490 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
491 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
492 #endif
493 break;
494 case TJPF_XRGB:
495 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
496 FROMRGB(4, 1, 2, 3,); return;
497 #endif
498 break;
499 case TJPF_ARGB:
500 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
501 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
502 #endif
503 break;
504 case TJPF_XBGR:
505 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
506 FROMRGB(4, 3, 2, 1,); return;
507 #endif
508 break;
509 case TJPF_ABGR:
510 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
511 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
512 #endif
513 break;
514 }
515}
516
517#endif
518
519
hbono@chromium.org98626972011-08-03 03:13:08 +0000520/* General API functions */
521
522DLLEXPORT char* DLLCALL tjGetErrorStr(void)
523{
524 return errStr;
525}
526
527
528DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
529{
530 getinstance(handle);
531 if(setjmp(this->jerr.setjmp_buffer)) return -1;
532 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
533 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
534 free(this);
535 return 0;
536}
537
538
539/* These are exposed mainly because Windows can't malloc() and free() across
540 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
541 with turbojpeg.dll for compatibility reasons. However, these functions
542 can potentially be used for other purposes by different implementations. */
543
544DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
545{
546 if(buf) free(buf);
547}
548
549
550DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
551{
552 return (unsigned char *)malloc(bytes);
553}
554
555
556/* Compressor */
557
558static tjhandle _tjInitCompress(tjinstance *this)
559{
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400560 static unsigned char buffer[1];
561 unsigned char *buf=buffer; unsigned long size=1;
hbono@chromium.org98626972011-08-03 03:13:08 +0000562
563 /* This is also straight out of example.c */
564 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
565 this->jerr.pub.error_exit=my_error_exit;
566 this->jerr.pub.output_message=my_output_message;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400567 this->jerr.emit_message=this->jerr.pub.emit_message;
568 this->jerr.pub.emit_message=my_emit_message;
hbono@chromium.org98626972011-08-03 03:13:08 +0000569
570 if(setjmp(this->jerr.setjmp_buffer))
571 {
572 /* If we get here, the JPEG code has signaled an error. */
573 if(this) free(this); return NULL;
574 }
575
576 jpeg_create_compress(&this->cinfo);
577 /* Make an initial call so it will create the destination manager */
578 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
579
580 this->init|=COMPRESS;
581 return (tjhandle)this;
582}
583
584DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
585{
586 tjinstance *this=NULL;
587 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
588 {
589 snprintf(errStr, JMSG_LENGTH_MAX,
590 "tjInitCompress(): Memory allocation failure");
591 return NULL;
592 }
593 MEMZERO(this, sizeof(tjinstance));
594 return _tjInitCompress(this);
595}
596
597
598DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
599 int jpegSubsamp)
600{
601 unsigned long retval=0; int mcuw, mcuh, chromasf;
602 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
603 _throw("tjBufSize(): Invalid argument");
604
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000605 /* This allows for rare corner cases in which a JPEG image can actually be
606 larger than the uncompressed input (we wouldn't mention it if it hadn't
607 happened before.) */
hbono@chromium.org98626972011-08-03 03:13:08 +0000608 mcuw=tjMCUWidth[jpegSubsamp];
609 mcuh=tjMCUHeight[jpegSubsamp];
610 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
611 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
612
613 bailout:
614 return retval;
615}
616
hbono@chromium.org98626972011-08-03 03:13:08 +0000617DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
618{
619 unsigned long retval=0;
620 if(width<1 || height<1)
621 _throw("TJBUFSIZE(): Invalid argument");
622
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000623 /* This allows for rare corner cases in which a JPEG image can actually be
624 larger than the uncompressed input (we wouldn't mention it if it hadn't
625 happened before.) */
hbono@chromium.org98626972011-08-03 03:13:08 +0000626 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
627
628 bailout:
629 return retval;
630}
631
632
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400633DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
hbono@chromium.org98626972011-08-03 03:13:08 +0000634 int subsamp)
635{
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400636 int retval=0, nc, i;
637
638 if(subsamp<0 || subsamp>=NUMSUBOPT)
639 _throw("tjBufSizeYUV2(): Invalid argument");
640
641 nc=(subsamp==TJSAMP_GRAY? 1:3);
642 for(i=0; i<nc; i++)
643 {
644 int pw=tjPlaneWidth(i, width, subsamp);
645 int stride=PAD(pw, pad);
646 int ph=tjPlaneHeight(i, height, subsamp);
647 if(pw<0 || ph<0) return -1;
648 else retval+=stride*ph;
649 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000650
651 bailout:
652 return retval;
653}
654
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400655DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
656 int subsamp)
657{
658 return tjBufSizeYUV2(width, 4, height, subsamp);
659}
hbono@chromium.org98626972011-08-03 03:13:08 +0000660
661DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
662 int subsamp)
663{
664 return tjBufSizeYUV(width, height, subsamp);
665}
666
667
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400668DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
669{
670 int pw, nc, retval=0;
671
672 if(width<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
673 _throw("tjPlaneWidth(): Invalid argument");
674 nc=(subsamp==TJSAMP_GRAY? 1:3);
675 if(componentID<0 || componentID>=nc)
676 _throw("tjPlaneWidth(): Invalid argument");
677
678 pw=PAD(width, tjMCUWidth[subsamp]/8);
679 if(componentID==0)
680 retval=pw;
681 else
682 retval=pw*8/tjMCUWidth[subsamp];
683
684 bailout:
685 return retval;
686}
687
688
689DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
690{
691 int ph, nc, retval=0;
692
693 if(height<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
694 _throw("tjPlaneHeight(): Invalid argument");
695 nc=(subsamp==TJSAMP_GRAY? 1:3);
696 if(componentID<0 || componentID>=nc)
697 _throw("tjPlaneHeight(): Invalid argument");
698
699 ph=PAD(height, tjMCUHeight[subsamp]/8);
700 if(componentID==0)
701 retval=ph;
702 else
703 retval=ph*8/tjMCUHeight[subsamp];
704
705 bailout:
706 return retval;
707}
708
709
710DLLEXPORT unsigned long DLLCALL tjPlaneSizeYUV(int componentID, int width,
711 int stride, int height, int subsamp)
712{
713 unsigned long retval=0;
714 int pw, ph;
715
716 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
717 _throw("tjPlaneSizeYUV(): Invalid argument");
718
719 pw=tjPlaneWidth(componentID, width, subsamp);
720 ph=tjPlaneHeight(componentID, height, subsamp);
721 if(pw<0 || ph<0) return -1;
722
723 if(stride==0) stride=pw;
724 else stride=abs(stride);
725
726 retval=stride*(ph-1)+pw;
727
728 bailout:
729 return retval;
730}
731
732
733DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, const unsigned char *srcBuf,
hbono@chromium.org98626972011-08-03 03:13:08 +0000734 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
735 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
736{
737 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000738 #ifndef JCS_EXTENSIONS
739 unsigned char *rgbBuf=NULL;
740 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000741
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400742 getcinstance(handle)
hbono@chromium.org98626972011-08-03 03:13:08 +0000743 if((this->init&COMPRESS)==0)
744 _throw("tjCompress2(): Instance has not been initialized for compression");
745
746 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
747 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
748 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
749 _throw("tjCompress2(): Invalid argument");
750
751 if(setjmp(this->jerr.setjmp_buffer))
752 {
753 /* If we get here, the JPEG code has signaled an error. */
754 retval=-1;
755 goto bailout;
756 }
757
758 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
759
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000760 #ifndef JCS_EXTENSIONS
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400761 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000762 {
763 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
764 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
765 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
766 pitch=width*RGB_PIXELSIZE;
767 }
768 #endif
769
hbono@chromium.org98626972011-08-03 03:13:08 +0000770 cinfo->image_width=width;
771 cinfo->image_height=height;
772
773 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
774 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
775 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
776
777 if(flags&TJFLAG_NOREALLOC)
778 {
779 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
780 }
781 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000782 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000783 return -1;
hbono@chromium.org98626972011-08-03 03:13:08 +0000784
785 jpeg_start_compress(cinfo, TRUE);
786 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
787 _throw("tjCompress2(): Memory allocation failure");
788 for(i=0; i<height; i++)
789 {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400790 if(flags&TJFLAG_BOTTOMUP)
791 row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
792 else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
hbono@chromium.org98626972011-08-03 03:13:08 +0000793 }
794 while(cinfo->next_scanline<cinfo->image_height)
795 {
796 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
797 cinfo->image_height-cinfo->next_scanline);
798 }
799 jpeg_finish_compress(cinfo);
800
801 bailout:
802 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000803 #ifndef JCS_EXTENSIONS
804 if(rgbBuf) free(rgbBuf);
805 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000806 if(row_pointer) free(row_pointer);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400807 if(this->jerr.warning) retval=-1;
hbono@chromium.org98626972011-08-03 03:13:08 +0000808 return retval;
809}
810
811DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
812 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
813 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
814{
815 int retval=0; unsigned long size;
816 if(flags&TJ_YUV)
817 {
818 size=tjBufSizeYUV(width, height, jpegSubsamp);
819 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
820 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
821 }
822 else
823 {
824 retval=tjCompress2(handle, srcBuf, width, pitch, height,
825 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
826 flags|TJFLAG_NOREALLOC);
827 }
828 *jpegSize=size;
829 return retval;
830}
831
832
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400833DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle,
834 const unsigned char *srcBuf, int width, int pitch, int height,
835 int pixelFormat, unsigned char **dstPlanes, int *strides, int subsamp,
836 int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +0000837{
838 int i, retval=0; JSAMPROW *row_pointer=NULL;
839 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
840 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
841 JSAMPROW *outbuf[MAX_COMPONENTS];
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400842 int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
843 JSAMPLE *ptr;
hbono@chromium.org98626972011-08-03 03:13:08 +0000844 jpeg_component_info *compptr;
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000845 #ifndef JCS_EXTENSIONS
846 unsigned char *rgbBuf=NULL;
847 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000848
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400849 getcinstance(handle);
hbono@chromium.org98626972011-08-03 03:13:08 +0000850
851 for(i=0; i<MAX_COMPONENTS; i++)
852 {
853 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
854 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
855 }
856
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000857 if((this->init&COMPRESS)==0)
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400858 _throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000859
hbono@chromium.org98626972011-08-03 03:13:08 +0000860 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400861 || pixelFormat>=TJ_NUMPF || !dstPlanes || !dstPlanes[0] || subsamp<0
hbono@chromium.org98626972011-08-03 03:13:08 +0000862 || subsamp>=NUMSUBOPT)
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400863 _throw("tjEncodeYUVPlanes(): Invalid argument");
864 if(subsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
865 _throw("tjEncodeYUVPlanes(): Invalid argument");
hbono@chromium.org98626972011-08-03 03:13:08 +0000866
867 if(setjmp(this->jerr.setjmp_buffer))
868 {
869 /* If we get here, the JPEG code has signaled an error. */
870 retval=-1;
871 goto bailout;
872 }
873
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400874 if(pixelFormat==TJPF_CMYK)
875 _throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
876
hbono@chromium.org98626972011-08-03 03:13:08 +0000877 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
878
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000879 #ifndef JCS_EXTENSIONS
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400880 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000881 {
882 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400883 if(!rgbBuf) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000884 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
885 pitch=width*RGB_PIXELSIZE;
886 }
887 #endif
888
hbono@chromium.org98626972011-08-03 03:13:08 +0000889 cinfo->image_width=width;
890 cinfo->image_height=height;
891
892 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
893 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
894 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
895
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000896 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
hbono@chromium.org98626972011-08-03 03:13:08 +0000897
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000898 /* Execute only the parts of jpeg_start_compress() that we need. If we
899 were to call the whole jpeg_start_compress() function, then it would try
900 to write the file headers, which could overflow the output buffer if the
901 YUV image were very small. */
902 if(cinfo->global_state!=CSTATE_START)
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400903 _throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000904 (*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
905 jinit_c_master_control(cinfo, FALSE);
906 jinit_color_converter(cinfo);
907 jinit_downsampler(cinfo);
908 (*cinfo->cconvert->start_pass)(cinfo);
909
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400910 pw0=PAD(width, cinfo->max_h_samp_factor);
911 ph0=PAD(height, cinfo->max_v_samp_factor);
hbono@chromium.org98626972011-08-03 03:13:08 +0000912
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400913 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
914 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
hbono@chromium.org98626972011-08-03 03:13:08 +0000915 for(i=0; i<height; i++)
916 {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400917 if(flags&TJFLAG_BOTTOMUP)
918 row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
919 else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
hbono@chromium.org98626972011-08-03 03:13:08 +0000920 }
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400921 if(height<ph0)
922 for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
hbono@chromium.org98626972011-08-03 03:13:08 +0000923
924 for(i=0; i<cinfo->num_components; i++)
925 {
926 compptr=&cinfo->comp_info[i];
927 _tmpbuf[i]=(JSAMPLE *)malloc(
928 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
929 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400930 if(!_tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
hbono@chromium.org98626972011-08-03 03:13:08 +0000931 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400932 if(!tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
hbono@chromium.org98626972011-08-03 03:13:08 +0000933 for(row=0; row<cinfo->max_v_samp_factor; row++)
934 {
935 unsigned char *_tmpbuf_aligned=
936 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
937 tmpbuf[i][row]=&_tmpbuf_aligned[
938 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
939 /compptr->h_samp_factor, 16) * row];
940 }
941 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
942 * compptr->v_samp_factor + 16);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400943 if(!_tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
hbono@chromium.org98626972011-08-03 03:13:08 +0000944 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400945 if(!tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
hbono@chromium.org98626972011-08-03 03:13:08 +0000946 for(row=0; row<compptr->v_samp_factor; row++)
947 {
948 unsigned char *_tmpbuf2_aligned=
949 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
950 tmpbuf2[i][row]=&_tmpbuf2_aligned[
951 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
952 }
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400953 pw[i]=pw0*compptr->h_samp_factor/cinfo->max_h_samp_factor;
954 ph[i]=ph0*compptr->v_samp_factor/cinfo->max_v_samp_factor;
955 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
956 if(!outbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
957 ptr=dstPlanes[i];
958 for(row=0; row<ph[i]; row++)
hbono@chromium.org98626972011-08-03 03:13:08 +0000959 {
960 outbuf[i][row]=ptr;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400961 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
hbono@chromium.org98626972011-08-03 03:13:08 +0000962 }
963 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000964
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400965 for(row=0; row<ph0; row+=cinfo->max_v_samp_factor)
hbono@chromium.org98626972011-08-03 03:13:08 +0000966 {
967 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
968 cinfo->max_v_samp_factor);
969 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
970 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
971 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
972 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400973 compptr->v_samp_factor, pw[i]);
hbono@chromium.org98626972011-08-03 03:13:08 +0000974 }
975 cinfo->next_scanline+=height;
976 jpeg_abort_compress(cinfo);
977
978 bailout:
979 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000980 #ifndef JCS_EXTENSIONS
981 if(rgbBuf) free(rgbBuf);
982 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000983 if(row_pointer) free(row_pointer);
984 for(i=0; i<MAX_COMPONENTS; i++)
985 {
986 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
987 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
988 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
989 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
990 if(outbuf[i]!=NULL) free(outbuf[i]);
991 }
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400992 if(this->jerr.warning) retval=-1;
hbono@chromium.org98626972011-08-03 03:13:08 +0000993 return retval;
994}
995
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400996DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle,
997 const unsigned char *srcBuf, int width, int pitch, int height,
998 int pixelFormat, unsigned char *dstBuf, int pad, int subsamp, int flags)
999{
1000 unsigned char *dstPlanes[3];
1001 int pw0, ph0, strides[3], retval=-1;
1002
1003 if(width<=0 || height<=0 || dstBuf==NULL || pad<0 || !isPow2(pad)
1004 || subsamp<0 || subsamp>=NUMSUBOPT)
1005 _throw("tjEncodeYUV3(): Invalid argument");
1006
1007 pw0=tjPlaneWidth(0, width, subsamp);
1008 ph0=tjPlaneHeight(0, height, subsamp);
1009 dstPlanes[0]=dstBuf;
1010 strides[0]=PAD(pw0, pad);
1011 if(subsamp==TJSAMP_GRAY)
1012 {
1013 strides[1]=strides[2]=0;
1014 dstPlanes[1]=dstPlanes[2]=NULL;
1015 }
1016 else
1017 {
1018 int pw1=tjPlaneWidth(1, width, subsamp);
1019 int ph1=tjPlaneHeight(1, height, subsamp);
1020 strides[1]=strides[2]=PAD(pw1, pad);
1021 dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1022 dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1023 }
1024
1025 return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
1026 dstPlanes, strides, subsamp, flags);
1027
1028 bailout:
1029 return retval;
1030}
1031
1032DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
1033 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
1034 int subsamp, int flags)
1035{
1036 return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
1037 dstBuf, 4, subsamp, flags);
1038}
1039
hbono@chromium.org98626972011-08-03 03:13:08 +00001040DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
1041 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
1042 int subsamp, int flags)
1043{
1044 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1045 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
1046}
1047
1048
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001049DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle,
1050 const unsigned char **srcPlanes, int width, const int *strides, int height,
1051 int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual,
1052 int flags)
1053{
1054 int i, row, retval=0, alloc=1; JSAMPROW *inbuf[MAX_COMPONENTS];
1055 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1056 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1057 JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS];
1058
1059 getcinstance(handle)
1060
1061 for(i=0; i<MAX_COMPONENTS; i++)
1062 {
1063 tmpbuf[i]=NULL; inbuf[i]=NULL;
1064 }
1065
1066 if((this->init&COMPRESS)==0)
1067 _throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
1068
1069 if(!srcPlanes || !srcPlanes[0] || width<=0 || height<=0 || subsamp<0
1070 || subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0
1071 || jpegQual>100)
1072 _throw("tjCompressFromYUVPlanes(): Invalid argument");
1073 if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1074 _throw("tjCompressFromYUVPlanes(): Invalid argument");
1075
1076 if(setjmp(this->jerr.setjmp_buffer))
1077 {
1078 /* If we get here, the JPEG code has signaled an error. */
1079 retval=-1;
1080 goto bailout;
1081 }
1082
1083 cinfo->image_width=width;
1084 cinfo->image_height=height;
1085
1086 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1087 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1088 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1089
1090 if(flags&TJFLAG_NOREALLOC)
1091 {
1092 alloc=0; *jpegSize=tjBufSize(width, height, subsamp);
1093 }
1094 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1095 if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1)
1096 return -1;
1097 cinfo->raw_data_in=TRUE;
1098
1099 jpeg_start_compress(cinfo, TRUE);
1100 for(i=0; i<cinfo->num_components; i++)
1101 {
1102 jpeg_component_info *compptr=&cinfo->comp_info[i];
1103 int ih;
1104 iw[i]=compptr->width_in_blocks*DCTSIZE;
1105 ih=compptr->height_in_blocks*DCTSIZE;
1106 pw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor)
1107 *compptr->h_samp_factor/cinfo->max_h_samp_factor;
1108 ph[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor)
1109 *compptr->v_samp_factor/cinfo->max_v_samp_factor;
1110 if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
1111 th[i]=compptr->v_samp_factor*DCTSIZE;
1112 tmpbufsize+=iw[i]*th[i];
1113 if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
1114 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1115 ptr=(JSAMPLE *)srcPlanes[i];
1116 for(row=0; row<ph[i]; row++)
1117 {
1118 inbuf[i][row]=ptr;
1119 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
1120 }
1121 }
1122 if(usetmpbuf)
1123 {
1124 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1125 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1126 ptr=_tmpbuf;
1127 for(i=0; i<cinfo->num_components; i++)
1128 {
1129 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1130 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1131 for(row=0; row<th[i]; row++)
1132 {
1133 tmpbuf[i][row]=ptr;
1134 ptr+=iw[i];
1135 }
1136 }
1137 }
1138
1139 for(row=0; row<(int)cinfo->image_height;
1140 row+=cinfo->max_v_samp_factor*DCTSIZE)
1141 {
1142 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1143 int crow[MAX_COMPONENTS];
1144 for(i=0; i<cinfo->num_components; i++)
1145 {
1146 jpeg_component_info *compptr=&cinfo->comp_info[i];
1147 crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor;
1148 if(usetmpbuf)
1149 {
1150 int j, k;
1151 for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
1152 {
1153 memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], pw[i]);
1154 /* Duplicate last sample in row to fill out MCU */
1155 for(k=pw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][pw[i]-1];
1156 }
1157 /* Duplicate last row to fill out MCU */
1158 for(j=ph[i]-crow[i]; j<th[i]; j++)
1159 memcpy(tmpbuf[i][j], tmpbuf[i][ph[i]-crow[i]-1], iw[i]);
1160 yuvptr[i]=tmpbuf[i];
1161 }
1162 else
1163 yuvptr[i]=&inbuf[i][crow[i]];
1164 }
1165 jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE);
1166 }
1167 jpeg_finish_compress(cinfo);
1168
1169 bailout:
1170 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1171 for(i=0; i<MAX_COMPONENTS; i++)
1172 {
1173 if(tmpbuf[i]) free(tmpbuf[i]);
1174 if(inbuf[i]) free(inbuf[i]);
1175 }
1176 if(_tmpbuf) free(_tmpbuf);
1177 if(this->jerr.warning) retval=-1;
1178 return retval;
1179}
1180
1181DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle,
1182 const unsigned char *srcBuf, int width, int pad, int height, int subsamp,
1183 unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)
1184{
1185 const unsigned char *srcPlanes[3];
1186 int pw0, ph0, strides[3], retval=-1;
1187
1188 if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
1189 || subsamp>=NUMSUBOPT)
1190 _throw("tjCompressFromYUV(): Invalid argument");
1191
1192 pw0=tjPlaneWidth(0, width, subsamp);
1193 ph0=tjPlaneHeight(0, height, subsamp);
1194 srcPlanes[0]=srcBuf;
1195 strides[0]=PAD(pw0, pad);
1196 if(subsamp==TJSAMP_GRAY)
1197 {
1198 strides[1]=strides[2]=0;
1199 srcPlanes[1]=srcPlanes[2]=NULL;
1200 }
1201 else
1202 {
1203 int pw1=tjPlaneWidth(1, width, subsamp);
1204 int ph1=tjPlaneHeight(1, height, subsamp);
1205 strides[1]=strides[2]=PAD(pw1, pad);
1206 srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1207 srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1208 }
1209
1210 return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1211 subsamp, jpegBuf, jpegSize, jpegQual, flags);
1212
1213 bailout:
1214 return retval;
1215}
1216
1217
hbono@chromium.org98626972011-08-03 03:13:08 +00001218/* Decompressor */
1219
1220static tjhandle _tjInitDecompress(tjinstance *this)
1221{
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001222 static unsigned char buffer[1];
hbono@chromium.org98626972011-08-03 03:13:08 +00001223
1224 /* This is also straight out of example.c */
1225 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
1226 this->jerr.pub.error_exit=my_error_exit;
1227 this->jerr.pub.output_message=my_output_message;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001228 this->jerr.emit_message=this->jerr.pub.emit_message;
1229 this->jerr.pub.emit_message=my_emit_message;
hbono@chromium.org98626972011-08-03 03:13:08 +00001230
1231 if(setjmp(this->jerr.setjmp_buffer))
1232 {
1233 /* If we get here, the JPEG code has signaled an error. */
1234 if(this) free(this); return NULL;
1235 }
1236
1237 jpeg_create_decompress(&this->dinfo);
1238 /* Make an initial call so it will create the source manager */
1239 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1240
1241 this->init|=DECOMPRESS;
1242 return (tjhandle)this;
1243}
1244
1245DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
1246{
1247 tjinstance *this;
1248 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1249 {
1250 snprintf(errStr, JMSG_LENGTH_MAX,
1251 "tjInitDecompress(): Memory allocation failure");
1252 return NULL;
1253 }
1254 MEMZERO(this, sizeof(tjinstance));
1255 return _tjInitDecompress(this);
1256}
1257
1258
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001259DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
1260 const unsigned char *jpegBuf, unsigned long jpegSize, int *width,
1261 int *height, int *jpegSubsamp, int *jpegColorspace)
hbono@chromium.org98626972011-08-03 03:13:08 +00001262{
1263 int retval=0;
1264
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001265 getdinstance(handle);
hbono@chromium.org98626972011-08-03 03:13:08 +00001266 if((this->init&DECOMPRESS)==0)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001267 _throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
hbono@chromium.org98626972011-08-03 03:13:08 +00001268
1269 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001270 || jpegSubsamp==NULL || jpegColorspace==NULL)
1271 _throw("tjDecompressHeader3(): Invalid argument");
hbono@chromium.org98626972011-08-03 03:13:08 +00001272
1273 if(setjmp(this->jerr.setjmp_buffer))
1274 {
1275 /* If we get here, the JPEG code has signaled an error. */
1276 return -1;
1277 }
1278
1279 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1280 jpeg_read_header(dinfo, TRUE);
1281
1282 *width=dinfo->image_width;
1283 *height=dinfo->image_height;
1284 *jpegSubsamp=getSubsamp(dinfo);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001285 switch(dinfo->jpeg_color_space)
1286 {
1287 case JCS_GRAYSCALE: *jpegColorspace=TJCS_GRAY; break;
1288 case JCS_RGB: *jpegColorspace=TJCS_RGB; break;
1289 case JCS_YCbCr: *jpegColorspace=TJCS_YCbCr; break;
1290 case JCS_CMYK: *jpegColorspace=TJCS_CMYK; break;
1291 case JCS_YCCK: *jpegColorspace=TJCS_YCCK; break;
1292 default: *jpegColorspace=-1; break;
1293 }
hbono@chromium.org98626972011-08-03 03:13:08 +00001294
1295 jpeg_abort_decompress(dinfo);
1296
1297 if(*jpegSubsamp<0)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001298 _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1299 if(*jpegColorspace<0)
1300 _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
hbono@chromium.org98626972011-08-03 03:13:08 +00001301 if(*width<1 || *height<1)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001302 _throw("tjDecompressHeader3(): Invalid data returned in header");
hbono@chromium.org98626972011-08-03 03:13:08 +00001303
1304 bailout:
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001305 if(this->jerr.warning) retval=-1;
hbono@chromium.org98626972011-08-03 03:13:08 +00001306 return retval;
1307}
1308
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001309DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
1310 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
1311 int *jpegSubsamp)
1312{
1313 int jpegColorspace;
1314 return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1315 jpegSubsamp, &jpegColorspace);
1316}
1317
hbono@chromium.org98626972011-08-03 03:13:08 +00001318DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
1319 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
1320{
1321 int jpegSubsamp;
1322 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1323 &jpegSubsamp);
1324}
1325
1326
1327DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
1328{
1329 if(numscalingfactors==NULL)
1330 {
1331 snprintf(errStr, JMSG_LENGTH_MAX,
1332 "tjGetScalingFactors(): Invalid argument");
1333 return NULL;
1334 }
1335
1336 *numscalingfactors=NUMSF;
1337 return (tjscalingfactor *)sf;
1338}
1339
1340
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001341DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
1342 const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1343 int width, int pitch, int height, int pixelFormat, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +00001344{
1345 int i, retval=0; JSAMPROW *row_pointer=NULL;
1346 int jpegwidth, jpegheight, scaledw, scaledh;
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001347 #ifndef JCS_EXTENSIONS
1348 unsigned char *rgbBuf=NULL;
1349 unsigned char *_dstBuf=NULL; int _pitch=0;
1350 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +00001351
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001352 getdinstance(handle);
hbono@chromium.org98626972011-08-03 03:13:08 +00001353 if((this->init&DECOMPRESS)==0)
1354 _throw("tjDecompress2(): Instance has not been initialized for decompression");
1355
1356 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
1357 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
1358 _throw("tjDecompress2(): Invalid argument");
1359
1360 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1361 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1362 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1363
1364 if(setjmp(this->jerr.setjmp_buffer))
1365 {
1366 /* If we get here, the JPEG code has signaled an error. */
1367 retval=-1;
1368 goto bailout;
1369 }
1370
1371 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1372 jpeg_read_header(dinfo, TRUE);
hbono@chromium.org11e6ee92012-07-19 06:04:44 +00001373 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001374 {
1375 retval=-1; goto bailout;
1376 }
hbono@chromium.org98626972011-08-03 03:13:08 +00001377
1378 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
1379
1380 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1381 if(width==0) width=jpegwidth;
1382 if(height==0) height=jpegheight;
1383 for(i=0; i<NUMSF; i++)
1384 {
1385 scaledw=TJSCALED(jpegwidth, sf[i]);
1386 scaledh=TJSCALED(jpegheight, sf[i]);
1387 if(scaledw<=width && scaledh<=height)
noel@chromium.org3395bcc2014-04-14 06:56:00 +00001388 break;
hbono@chromium.org98626972011-08-03 03:13:08 +00001389 }
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001390 if(i>=NUMSF)
hbono@chromium.org98626972011-08-03 03:13:08 +00001391 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
1392 width=scaledw; height=scaledh;
1393 dinfo->scale_num=sf[i].num;
1394 dinfo->scale_denom=sf[i].denom;
1395
1396 jpeg_start_decompress(dinfo);
1397 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001398
1399 #ifndef JCS_EXTENSIONS
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001400 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001401 (RGB_RED!=tjRedOffset[pixelFormat] ||
1402 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1403 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1404 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1405 {
1406 rgbBuf=(unsigned char *)malloc(width*height*3);
1407 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1408 _pitch=pitch; pitch=width*3;
1409 _dstBuf=dstBuf; dstBuf=rgbBuf;
1410 }
1411 #endif
1412
hbono@chromium.org98626972011-08-03 03:13:08 +00001413 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1414 *dinfo->output_height))==NULL)
1415 _throw("tjDecompress2(): Memory allocation failure");
1416 for(i=0; i<(int)dinfo->output_height; i++)
1417 {
1418 if(flags&TJFLAG_BOTTOMUP)
1419 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1420 else row_pointer[i]=&dstBuf[i*pitch];
1421 }
1422 while(dinfo->output_scanline<dinfo->output_height)
1423 {
1424 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1425 dinfo->output_height-dinfo->output_scanline);
1426 }
1427 jpeg_finish_decompress(dinfo);
1428
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001429 #ifndef JCS_EXTENSIONS
1430 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1431 #endif
1432
hbono@chromium.org98626972011-08-03 03:13:08 +00001433 bailout:
1434 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001435 #ifndef JCS_EXTENSIONS
1436 if(rgbBuf) free(rgbBuf);
1437 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +00001438 if(row_pointer) free(row_pointer);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001439 if(this->jerr.warning) retval=-1;
hbono@chromium.org98626972011-08-03 03:13:08 +00001440 return retval;
1441}
1442
1443DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1444 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1445 int height, int pixelSize, int flags)
1446{
1447 if(flags&TJ_YUV)
1448 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1449 else
1450 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1451 height, getPixelFormat(pixelSize, flags), flags);
1452}
1453
1454
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001455static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
1456 int pixelFormat, int subsamp, int flags)
1457{
1458 int i;
1459
1460 dinfo->scale_num=dinfo->scale_denom=1;
1461
1462 if(subsamp==TJSAMP_GRAY)
1463 {
1464 dinfo->num_components=dinfo->comps_in_scan=1;
1465 dinfo->jpeg_color_space=JCS_GRAYSCALE;
1466 }
1467 else
1468 {
1469 dinfo->num_components=dinfo->comps_in_scan=3;
1470 dinfo->jpeg_color_space=JCS_YCbCr;
1471 }
1472
1473 dinfo->comp_info=(jpeg_component_info *)
1474 (*dinfo->mem->alloc_small)((j_common_ptr)dinfo, JPOOL_IMAGE,
1475 dinfo->num_components*sizeof(jpeg_component_info));
1476
1477 for(i=0; i<dinfo->num_components; i++)
1478 {
1479 jpeg_component_info *compptr=&dinfo->comp_info[i];
1480 compptr->h_samp_factor=(i==0)? tjMCUWidth[subsamp]/8:1;
1481 compptr->v_samp_factor=(i==0)? tjMCUHeight[subsamp]/8:1;
1482 compptr->component_index=i;
1483 compptr->component_id=i+1;
1484 compptr->quant_tbl_no=compptr->dc_tbl_no=compptr->ac_tbl_no=
1485 (i==0)? 0:1;
1486 dinfo->cur_comp_info[i]=compptr;
1487 }
1488 dinfo->data_precision=8;
1489 for(i=0; i<2; i++)
1490 {
1491 if(dinfo->quant_tbl_ptrs[i]==NULL)
1492 dinfo->quant_tbl_ptrs[i]=jpeg_alloc_quant_table((j_common_ptr)dinfo);
1493 }
1494
1495 return 0;
1496}
1497
1498
1499int my_read_markers(j_decompress_ptr dinfo)
1500{
1501 return JPEG_REACHED_SOS;
1502}
1503
1504void my_reset_marker_reader(j_decompress_ptr dinfo)
1505{
1506}
1507
1508DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
1509 const unsigned char **srcPlanes, const int *strides, int subsamp,
1510 unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat,
hbono@chromium.org98626972011-08-03 03:13:08 +00001511 int flags)
1512{
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001513 int i, retval=0; JSAMPROW *row_pointer=NULL;
1514 JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1515 JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
1516 int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1517 JSAMPLE *ptr;
1518 jpeg_component_info *compptr;
1519 #ifndef JCS_EXTENSIONS
1520 unsigned char *rgbBuf=NULL;
1521 unsigned char *_dstBuf=NULL; int _pitch=0;
1522 #endif
1523 int (*old_read_markers)(j_decompress_ptr);
1524 void (*old_reset_marker_reader)(j_decompress_ptr);
hbono@chromium.org98626972011-08-03 03:13:08 +00001525
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001526 getdinstance(handle);
1527
1528 for(i=0; i<MAX_COMPONENTS; i++)
1529 {
1530 tmpbuf[i]=NULL; _tmpbuf[i]=NULL; inbuf[i]=NULL;
1531 }
1532
1533 if((this->init&DECOMPRESS)==0)
1534 _throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
1535
1536 if(!srcPlanes || !srcPlanes[0] || subsamp<0 || subsamp>=NUMSUBOPT
1537 || dstBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
1538 || pixelFormat>=TJ_NUMPF)
1539 _throw("tjDecodeYUVPlanes(): Invalid argument");
1540 if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1541 _throw("tjDecodeYUVPlanes(): Invalid argument");
1542
1543 if(setjmp(this->jerr.setjmp_buffer))
1544 {
1545 /* If we get here, the JPEG code has signaled an error. */
1546 retval=-1;
1547 goto bailout;
1548 }
1549
1550 if(pixelFormat==TJPF_CMYK)
1551 _throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
1552
1553 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
1554 dinfo->image_width=width;
1555 dinfo->image_height=height;
1556
1557 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1558 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1559 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1560
1561 if(setDecodeDefaults(dinfo, pixelFormat, subsamp, flags)==-1)
1562 {
1563 retval=-1; goto bailout;
1564 }
1565 old_read_markers=dinfo->marker->read_markers;
1566 dinfo->marker->read_markers=my_read_markers;
1567 old_reset_marker_reader=dinfo->marker->reset_marker_reader;
1568 dinfo->marker->reset_marker_reader=my_reset_marker_reader;
1569 jpeg_read_header(dinfo, TRUE);
1570 dinfo->marker->read_markers=old_read_markers;
1571 dinfo->marker->reset_marker_reader=old_reset_marker_reader;
1572
1573 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
1574 {
1575 retval=-1; goto bailout;
1576 }
1577 dinfo->do_fancy_upsampling=FALSE;
1578 dinfo->Se=DCTSIZE2-1;
1579 jinit_master_decompress(dinfo);
1580 (*dinfo->upsample->start_pass)(dinfo);
1581
1582 pw0=PAD(width, dinfo->max_h_samp_factor);
1583 ph0=PAD(height, dinfo->max_v_samp_factor);
1584
1585 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
1586
1587 #ifndef JCS_EXTENSIONS
1588 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
1589 (RGB_RED!=tjRedOffset[pixelFormat] ||
1590 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1591 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1592 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1593 {
1594 rgbBuf=(unsigned char *)malloc(width*height*3);
1595 if(!rgbBuf) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1596 _pitch=pitch; pitch=width*3;
1597 _dstBuf=dstBuf; dstBuf=rgbBuf;
1598 }
1599 #endif
1600
1601 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
1602 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1603 for(i=0; i<height; i++)
1604 {
1605 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*pitch];
1606 else row_pointer[i]=&dstBuf[i*pitch];
1607 }
1608 if(height<ph0)
1609 for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
1610
1611 for(i=0; i<dinfo->num_components; i++)
1612 {
1613 compptr=&dinfo->comp_info[i];
1614 _tmpbuf[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
1615 * compptr->v_samp_factor + 16);
1616 if(!_tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1617 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
1618 if(!tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1619 for(row=0; row<compptr->v_samp_factor; row++)
1620 {
1621 unsigned char *_tmpbuf_aligned=
1622 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
1623 tmpbuf[i][row]=&_tmpbuf_aligned[
1624 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
1625 }
1626 pw[i]=pw0*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1627 ph[i]=ph0*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1628 inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
1629 if(!inbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1630 ptr=(JSAMPLE *)srcPlanes[i];
1631 for(row=0; row<ph[i]; row++)
1632 {
1633 inbuf[i][row]=ptr;
1634 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
1635 }
1636 }
1637
1638 for(row=0; row<ph0; row+=dinfo->max_v_samp_factor)
1639 {
1640 JDIMENSION inrow=0, outrow=0;
1641 for(i=0, compptr=dinfo->comp_info; i<dinfo->num_components; i++, compptr++)
1642 jcopy_sample_rows(inbuf[i],
1643 row*compptr->v_samp_factor/dinfo->max_v_samp_factor, tmpbuf[i], 0,
1644 compptr->v_samp_factor, pw[i]);
1645 (dinfo->upsample->upsample)(dinfo, tmpbuf, &inrow,
1646 dinfo->max_v_samp_factor, &row_pointer[row], &outrow,
1647 dinfo->max_v_samp_factor);
1648 }
1649 jpeg_abort_decompress(dinfo);
1650
1651 #ifndef JCS_EXTENSIONS
1652 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1653 #endif
1654
1655 bailout:
1656 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1657 #ifndef JCS_EXTENSIONS
1658 if(rgbBuf) free(rgbBuf);
1659 #endif
1660 if(row_pointer) free(row_pointer);
1661 for(i=0; i<MAX_COMPONENTS; i++)
1662 {
1663 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
1664 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
1665 if(inbuf[i]!=NULL) free(inbuf[i]);
1666 }
1667 if(this->jerr.warning) retval=-1;
1668 return retval;
1669}
1670
1671DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
1672 int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
1673 int height, int pixelFormat, int flags)
1674{
1675 const unsigned char *srcPlanes[3];
1676 int pw0, ph0, strides[3], retval=-1;
1677
1678 if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT
1679 || width<=0 || height<=0)
1680 _throw("tjDecodeYUV(): Invalid argument");
1681
1682 pw0=tjPlaneWidth(0, width, subsamp);
1683 ph0=tjPlaneHeight(0, height, subsamp);
1684 srcPlanes[0]=srcBuf;
1685 strides[0]=PAD(pw0, pad);
1686 if(subsamp==TJSAMP_GRAY)
1687 {
1688 strides[1]=strides[2]=0;
1689 srcPlanes[1]=srcPlanes[2]=NULL;
1690 }
1691 else
1692 {
1693 int pw1=tjPlaneWidth(1, width, subsamp);
1694 int ph1=tjPlaneHeight(1, height, subsamp);
1695 strides[1]=strides[2]=PAD(pw1, pad);
1696 srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1697 srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1698 }
1699
1700 return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1701 pitch, height, pixelFormat, flags);
1702
1703 bailout:
1704 return retval;
1705}
1706
1707DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle,
1708 const unsigned char *jpegBuf, unsigned long jpegSize,
1709 unsigned char **dstPlanes, int width, int *strides, int height, int flags)
1710{
1711 int i, sfi, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
1712 int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
1713 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1714 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1715 JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS];
1716 int dctsize;
1717
1718 getdinstance(handle);
hbono@chromium.org98626972011-08-03 03:13:08 +00001719
1720 for(i=0; i<MAX_COMPONENTS; i++)
1721 {
1722 tmpbuf[i]=NULL; outbuf[i]=NULL;
1723 }
1724
noel@chromium.org3395bcc2014-04-14 06:56:00 +00001725 if((this->init&DECOMPRESS)==0)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001726 _throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
noel@chromium.org3395bcc2014-04-14 06:56:00 +00001727
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001728 if(jpegBuf==NULL || jpegSize<=0 || !dstPlanes || !dstPlanes[0] || width<0
1729 || height<0)
1730 _throw("tjDecompressToYUVPlanes(): Invalid argument");
hbono@chromium.org98626972011-08-03 03:13:08 +00001731
1732 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1733 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1734 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1735
1736 if(setjmp(this->jerr.setjmp_buffer))
1737 {
1738 /* If we get here, the JPEG code has signaled an error. */
1739 retval=-1;
1740 goto bailout;
1741 }
1742
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001743 if(!this->headerRead)
1744 {
1745 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1746 jpeg_read_header(dinfo, TRUE);
1747 }
1748 this->headerRead=0;
1749 jpegSubsamp=getSubsamp(dinfo);
1750 if(jpegSubsamp<0)
1751 _throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1752
1753 if(jpegSubsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1754 _throw("tjDecompressToYUVPlanes(): Invalid argument");
1755
1756 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1757 if(width==0) width=jpegwidth;
1758 if(height==0) height=jpegheight;
1759 for(i=0; i<NUMSF; i++)
1760 {
1761 scaledw=TJSCALED(jpegwidth, sf[i]);
1762 scaledh=TJSCALED(jpegheight, sf[i]);
1763 if(scaledw<=width && scaledh<=height)
1764 break;
1765 }
1766 if(i>=NUMSF)
1767 _throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
1768 if(dinfo->num_components>3)
1769 _throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
1770
1771 width=scaledw; height=scaledh;
1772 dinfo->scale_num=sf[i].num;
1773 dinfo->scale_denom=sf[i].denom;
1774 sfi=i;
1775 jpeg_calc_output_dimensions(dinfo);
1776
1777 dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
hbono@chromium.org98626972011-08-03 03:13:08 +00001778
1779 for(i=0; i<dinfo->num_components; i++)
1780 {
1781 jpeg_component_info *compptr=&dinfo->comp_info[i];
1782 int ih;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001783 iw[i]=compptr->width_in_blocks*dctsize;
1784 ih=compptr->height_in_blocks*dctsize;
1785 pw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
hbono@chromium.org98626972011-08-03 03:13:08 +00001786 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001787 ph[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
hbono@chromium.org98626972011-08-03 03:13:08 +00001788 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001789 if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
1790 th[i]=compptr->v_samp_factor*dctsize;
hbono@chromium.org98626972011-08-03 03:13:08 +00001791 tmpbufsize+=iw[i]*th[i];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001792 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
1793 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1794 ptr=dstPlanes[i];
1795 for(row=0; row<ph[i]; row++)
hbono@chromium.org98626972011-08-03 03:13:08 +00001796 {
1797 outbuf[i][row]=ptr;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001798 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
hbono@chromium.org98626972011-08-03 03:13:08 +00001799 }
1800 }
1801 if(usetmpbuf)
1802 {
1803 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001804 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
hbono@chromium.org98626972011-08-03 03:13:08 +00001805 ptr=_tmpbuf;
1806 for(i=0; i<dinfo->num_components; i++)
1807 {
1808 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001809 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
hbono@chromium.org98626972011-08-03 03:13:08 +00001810 for(row=0; row<th[i]; row++)
1811 {
1812 tmpbuf[i][row]=ptr;
1813 ptr+=iw[i];
1814 }
1815 }
1816 }
1817
1818 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
hbono@chromium.org11e6ee92012-07-19 06:04:44 +00001819 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
hbono@chromium.org98626972011-08-03 03:13:08 +00001820 dinfo->raw_data_out=TRUE;
1821
1822 jpeg_start_decompress(dinfo);
1823 for(row=0; row<(int)dinfo->output_height;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001824 row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
hbono@chromium.org98626972011-08-03 03:13:08 +00001825 {
1826 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1827 int crow[MAX_COMPONENTS];
1828 for(i=0; i<dinfo->num_components; i++)
1829 {
1830 jpeg_component_info *compptr=&dinfo->comp_info[i];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001831 if(jpegSubsamp==TJ_420)
1832 {
1833 /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1834 to be clever and use the IDCT to perform upsampling on the U and V
1835 planes. For instance, if the output image is to be scaled by 1/2
1836 relative to the JPEG image, then the scaling factor and upsampling
1837 effectively cancel each other, so a normal 8x8 IDCT can be used.
1838 However, this is not desirable when using the decompress-to-YUV
1839 functionality in TurboJPEG, since we want to output the U and V
1840 planes in their subsampled form. Thus, we have to override some
1841 internal libjpeg parameters to force it to use the "scaled" IDCT
1842 functions on the U and V planes. */
1843 compptr->_DCT_scaled_size=dctsize;
1844 compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
1845 sf[sfi].num/sf[sfi].denom*
1846 compptr->v_samp_factor/dinfo->max_v_samp_factor;
1847 dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1848 }
hbono@chromium.org98626972011-08-03 03:13:08 +00001849 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1850 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1851 else yuvptr[i]=&outbuf[i][crow[i]];
1852 }
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001853 jpeg_read_raw_data(dinfo, yuvptr,
1854 dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
hbono@chromium.org98626972011-08-03 03:13:08 +00001855 if(usetmpbuf)
1856 {
1857 int j;
1858 for(i=0; i<dinfo->num_components; i++)
1859 {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001860 for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
hbono@chromium.org98626972011-08-03 03:13:08 +00001861 {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001862 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], pw[i]);
hbono@chromium.org98626972011-08-03 03:13:08 +00001863 }
1864 }
1865 }
1866 }
1867 jpeg_finish_decompress(dinfo);
1868
1869 bailout:
1870 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1871 for(i=0; i<MAX_COMPONENTS; i++)
1872 {
1873 if(tmpbuf[i]) free(tmpbuf[i]);
1874 if(outbuf[i]) free(outbuf[i]);
1875 }
1876 if(_tmpbuf) free(_tmpbuf);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001877 if(this->jerr.warning) retval=-1;
hbono@chromium.org98626972011-08-03 03:13:08 +00001878 return retval;
1879}
1880
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001881DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
1882 const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1883 int width, int pad, int height, int flags)
1884{
1885 unsigned char *dstPlanes[3];
1886 int pw0, ph0, strides[3], retval=-1, jpegSubsamp=-1;
1887 int i, jpegwidth, jpegheight, scaledw, scaledh;
1888
1889 getdinstance(handle);
1890
1891 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
1892 || !isPow2(pad) || height<0)
1893 _throw("tjDecompressToYUV2(): Invalid argument");
1894
1895 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1896 jpeg_read_header(dinfo, TRUE);
1897 jpegSubsamp=getSubsamp(dinfo);
1898 if(jpegSubsamp<0)
1899 _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1900
1901 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1902 if(width==0) width=jpegwidth;
1903 if(height==0) height=jpegheight;
1904
1905 for(i=0; i<NUMSF; i++)
1906 {
1907 scaledw=TJSCALED(jpegwidth, sf[i]);
1908 scaledh=TJSCALED(jpegheight, sf[i]);
1909 if(scaledw<=width && scaledh<=height)
1910 break;
1911 }
1912 if(i>=NUMSF)
1913 _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1914
1915 pw0=tjPlaneWidth(0, width, jpegSubsamp);
1916 ph0=tjPlaneHeight(0, height, jpegSubsamp);
1917 dstPlanes[0]=dstBuf;
1918 strides[0]=PAD(pw0, pad);
1919 if(jpegSubsamp==TJSAMP_GRAY)
1920 {
1921 strides[1]=strides[2]=0;
1922 dstPlanes[1]=dstPlanes[2]=NULL;
1923 }
1924 else
1925 {
1926 int pw1=tjPlaneWidth(1, width, jpegSubsamp);
1927 int ph1=tjPlaneHeight(1, height, jpegSubsamp);
1928 strides[1]=strides[2]=PAD(pw1, pad);
1929 dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1930 dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1931 }
1932
1933 this->headerRead=1;
1934 return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1935 strides, height, flags);
1936
1937 bailout:
1938 return retval;
1939
1940}
1941
1942DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1943 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1944 int flags)
1945{
1946 return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1947}
1948
hbono@chromium.org98626972011-08-03 03:13:08 +00001949
1950/* Transformer */
1951
1952DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1953{
1954 tjinstance *this=NULL; tjhandle handle=NULL;
1955 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1956 {
1957 snprintf(errStr, JMSG_LENGTH_MAX,
1958 "tjInitTransform(): Memory allocation failure");
1959 return NULL;
1960 }
1961 MEMZERO(this, sizeof(tjinstance));
1962 handle=_tjInitCompress(this);
1963 if(!handle) return NULL;
1964 handle=_tjInitDecompress(this);
1965 return handle;
1966}
1967
1968
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001969DLLEXPORT int DLLCALL tjTransform(tjhandle handle,
1970 const unsigned char *jpegBuf, unsigned long jpegSize, int n,
1971 unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *t, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +00001972{
1973 jpeg_transform_info *xinfo=NULL;
1974 jvirt_barray_ptr *srccoefs, *dstcoefs;
1975 int retval=0, i, jpegSubsamp;
1976
1977 getinstance(handle);
1978 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
1979 _throw("tjTransform(): Instance has not been initialized for transformation");
1980
1981 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1982 || t==NULL || flags<0)
1983 _throw("tjTransform(): Invalid argument");
1984
1985 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1986 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1987 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1988
1989 if(setjmp(this->jerr.setjmp_buffer))
1990 {
1991 /* If we get here, the JPEG code has signaled an error. */
1992 retval=-1;
1993 goto bailout;
1994 }
1995
1996 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1997
1998 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1999 ==NULL)
2000 _throw("tjTransform(): Memory allocation failure");
2001 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
2002
2003 for(i=0; i<n; i++)
2004 {
2005 xinfo[i].transform=xformtypes[t[i].op];
2006 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
2007 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
2008 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
2009 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
2010 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
2011 else xinfo[i].slow_hflip=0;
2012
2013 if(xinfo[i].crop)
2014 {
2015 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
2016 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
2017 if(t[i].r.w!=0)
2018 {
2019 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
2020 }
2021 else xinfo[i].crop_width=JCROP_UNSET;
2022 if(t[i].r.h!=0)
2023 {
2024 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
2025 }
2026 else xinfo[i].crop_height=JCROP_UNSET;
2027 }
2028 }
2029
2030 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
2031 jpeg_read_header(dinfo, TRUE);
2032 jpegSubsamp=getSubsamp(dinfo);
2033 if(jpegSubsamp<0)
2034 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
2035
2036 for(i=0; i<n; i++)
2037 {
2038 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
2039 _throw("tjTransform(): Transform is not perfect");
2040
2041 if(xinfo[i].crop)
2042 {
2043 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
2044 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
2045 {
2046 snprintf(errStr, JMSG_LENGTH_MAX,
2047 "To crop this JPEG image, x must be a multiple of %d\n"
2048 "and y must be a multiple of %d.\n",
2049 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
2050 retval=-1; goto bailout;
2051 }
2052 }
2053 }
2054
2055 srccoefs=jpeg_read_coefficients(dinfo);
2056
2057 for(i=0; i<n; i++)
2058 {
2059 int w, h, alloc=1;
2060 if(!xinfo[i].crop)
2061 {
2062 w=dinfo->image_width; h=dinfo->image_height;
2063 }
2064 else
2065 {
2066 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
2067 }
2068 if(flags&TJFLAG_NOREALLOC)
2069 {
2070 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
2071 }
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00002072 if(!(t[i].options&TJXOPT_NOOUTPUT))
2073 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
hbono@chromium.org98626972011-08-03 03:13:08 +00002074 jpeg_copy_critical_parameters(dinfo, cinfo);
2075 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
2076 &xinfo[i]);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00002077 if(!(t[i].options&TJXOPT_NOOUTPUT))
2078 {
2079 jpeg_write_coefficients(cinfo, dstcoefs);
2080 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
2081 }
2082 else jinit_c_master_control(cinfo, TRUE);
hbono@chromium.org98626972011-08-03 03:13:08 +00002083 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
2084 &xinfo[i]);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00002085 if(t[i].customFilter)
2086 {
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00002087 int ci, y; JDIMENSION by;
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00002088 for(ci=0; ci<cinfo->num_components; ci++)
2089 {
2090 jpeg_component_info *compptr=&cinfo->comp_info[ci];
2091 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2092 DCTSIZE};
2093 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2094 compptr->height_in_blocks*DCTSIZE};
2095 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
2096 {
2097 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
2098 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
2099 TRUE);
2100 for(y=0; y<compptr->v_samp_factor; y++)
2101 {
2102 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
2103 ci, i, &t[i])==-1)
2104 _throw("tjTransform(): Error in custom filter");
2105 arrayRegion.y+=DCTSIZE;
2106 }
2107 }
2108 }
2109 }
2110 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
hbono@chromium.org98626972011-08-03 03:13:08 +00002111 }
2112
2113 jpeg_finish_decompress(dinfo);
2114
2115 bailout:
2116 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
2117 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
2118 if(xinfo) free(xinfo);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002119 if(this->jerr.warning) retval=-1;
hbono@chromium.org98626972011-08-03 03:13:08 +00002120 return retval;
2121}