blob: 21599c8604e63a44c1475a954f8080b9a516dd19 [file] [log] [blame]
hbono@chromium.org98626972011-08-03 03:13:08 +00001/*
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00002 * Copyright (C)2009-2012 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
29/* TurboJPEG/OSS: this implements the TurboJPEG API using libjpeg-turbo */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <jinclude.h>
34#define JPEG_INTERNALS
35#include <jpeglib.h>
36#include <jerror.h>
37#include <setjmp.h>
38#include "./turbojpeg.h"
39#include "./tjutil.h"
40#include "transupp.h"
41
42extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
43 unsigned long *, boolean);
44extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
45
46#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
47
48
49/* Error handling (based on example in example.c) */
50
51static char errStr[JMSG_LENGTH_MAX]="No error";
52
53struct my_error_mgr
54{
55 struct jpeg_error_mgr pub;
56 jmp_buf setjmp_buffer;
57};
58typedef struct my_error_mgr *my_error_ptr;
59
60static void my_error_exit(j_common_ptr cinfo)
61{
62 my_error_ptr myerr=(my_error_ptr)cinfo->err;
63 (*cinfo->err->output_message)(cinfo);
64 longjmp(myerr->setjmp_buffer, 1);
65}
66
67/* Based on output_message() in jerror.c */
68
69static void my_output_message(j_common_ptr cinfo)
70{
71 (*cinfo->err->format_message)(cinfo, errStr);
72}
73
74
75/* Global structures, macros, etc. */
76
77enum {COMPRESS=1, DECOMPRESS=2};
78
79typedef struct _tjinstance
80{
81 struct jpeg_compress_struct cinfo;
82 struct jpeg_decompress_struct dinfo;
83 struct my_error_mgr jerr;
84 int init;
85} tjinstance;
86
87static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
88
89static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
90{
91 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
92 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
93};
94
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +000095#define NUMSF 16
hbono@chromium.org98626972011-08-03 03:13:08 +000096static const tjscalingfactor sf[NUMSF]={
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +000097 {2, 1},
98 {15, 8},
99 {7, 4},
100 {13, 8},
101 {3, 2},
102 {11, 8},
103 {5, 4},
104 {9, 8},
hbono@chromium.org98626972011-08-03 03:13:08 +0000105 {1, 1},
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000106 {7, 8},
107 {3, 4},
108 {5, 8},
hbono@chromium.org98626972011-08-03 03:13:08 +0000109 {1, 2},
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000110 {3, 8},
hbono@chromium.org98626972011-08-03 03:13:08 +0000111 {1, 4},
112 {1, 8}
113};
114
115#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
116 retval=-1; goto bailout;}
117#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
118 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
119 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
120 return -1;} \
121 cinfo=&this->cinfo; dinfo=&this->dinfo;
122
123static int getPixelFormat(int pixelSize, int flags)
124{
125 if(pixelSize==1) return TJPF_GRAY;
126 if(pixelSize==3)
127 {
128 if(flags&TJ_BGR) return TJPF_BGR;
129 else return TJPF_RGB;
130 }
131 if(pixelSize==4)
132 {
133 if(flags&TJ_ALPHAFIRST)
134 {
135 if(flags&TJ_BGR) return TJPF_XBGR;
136 else return TJPF_XRGB;
137 }
138 else
139 {
140 if(flags&TJ_BGR) return TJPF_BGRX;
141 else return TJPF_RGBX;
142 }
143 }
144 return -1;
145}
146
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000147static int setCompDefaults(struct jpeg_compress_struct *cinfo,
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000148 int pixelFormat, int subsamp, int jpegQual, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +0000149{
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000150 int retval=0;
151
hbono@chromium.org98626972011-08-03 03:13:08 +0000152 switch(pixelFormat)
153 {
154 case TJPF_GRAY:
155 cinfo->in_color_space=JCS_GRAYSCALE; break;
156 #if JCS_EXTENSIONS==1
157 case TJPF_RGB:
158 cinfo->in_color_space=JCS_EXT_RGB; break;
159 case TJPF_BGR:
160 cinfo->in_color_space=JCS_EXT_BGR; break;
161 case TJPF_RGBX:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000162 case TJPF_RGBA:
hbono@chromium.org98626972011-08-03 03:13:08 +0000163 cinfo->in_color_space=JCS_EXT_RGBX; break;
164 case TJPF_BGRX:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000165 case TJPF_BGRA:
hbono@chromium.org98626972011-08-03 03:13:08 +0000166 cinfo->in_color_space=JCS_EXT_BGRX; break;
167 case TJPF_XRGB:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000168 case TJPF_ARGB:
hbono@chromium.org98626972011-08-03 03:13:08 +0000169 cinfo->in_color_space=JCS_EXT_XRGB; break;
170 case TJPF_XBGR:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000171 case TJPF_ABGR:
hbono@chromium.org98626972011-08-03 03:13:08 +0000172 cinfo->in_color_space=JCS_EXT_XBGR; break;
173 #else
174 case TJPF_RGB:
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000175 case TJPF_BGR:
176 case TJPF_RGBX:
177 case TJPF_BGRX:
178 case TJPF_XRGB:
179 case TJPF_XBGR:
180 case TJPF_RGBA:
181 case TJPF_BGRA:
182 case TJPF_ARGB:
183 case TJPF_ABGR:
184 cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
185 break;
hbono@chromium.org98626972011-08-03 03:13:08 +0000186 #endif
187 }
188
189 cinfo->input_components=tjPixelSize[pixelFormat];
190 jpeg_set_defaults(cinfo);
191 if(jpegQual>=0)
192 {
193 jpeg_set_quality(cinfo, jpegQual, TRUE);
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000194 if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
hbono@chromium.org98626972011-08-03 03:13:08 +0000195 else cinfo->dct_method=JDCT_FASTEST;
196 }
197 if(subsamp==TJSAMP_GRAY)
198 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
199 else
200 jpeg_set_colorspace(cinfo, JCS_YCbCr);
201
202 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
203 cinfo->comp_info[1].h_samp_factor=1;
204 cinfo->comp_info[2].h_samp_factor=1;
205 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
206 cinfo->comp_info[1].v_samp_factor=1;
207 cinfo->comp_info[2].v_samp_factor=1;
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000208
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000209 return retval;
hbono@chromium.org98626972011-08-03 03:13:08 +0000210}
211
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000212static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000213 int pixelFormat, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +0000214{
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000215 int retval=0;
216
hbono@chromium.org98626972011-08-03 03:13:08 +0000217 switch(pixelFormat)
218 {
219 case TJPF_GRAY:
220 dinfo->out_color_space=JCS_GRAYSCALE; break;
221 #if JCS_EXTENSIONS==1
222 case TJPF_RGB:
223 dinfo->out_color_space=JCS_EXT_RGB; break;
224 case TJPF_BGR:
225 dinfo->out_color_space=JCS_EXT_BGR; break;
226 case TJPF_RGBX:
227 dinfo->out_color_space=JCS_EXT_RGBX; break;
228 case TJPF_BGRX:
229 dinfo->out_color_space=JCS_EXT_BGRX; break;
230 case TJPF_XRGB:
231 dinfo->out_color_space=JCS_EXT_XRGB; break;
232 case TJPF_XBGR:
233 dinfo->out_color_space=JCS_EXT_XBGR; break;
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000234 #if JCS_ALPHA_EXTENSIONS==1
235 case TJPF_RGBA:
236 dinfo->out_color_space=JCS_EXT_RGBA; break;
237 case TJPF_BGRA:
238 dinfo->out_color_space=JCS_EXT_BGRA; break;
239 case TJPF_ARGB:
240 dinfo->out_color_space=JCS_EXT_ARGB; break;
241 case TJPF_ABGR:
242 dinfo->out_color_space=JCS_EXT_ABGR; break;
243 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000244 #else
245 case TJPF_RGB:
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000246 case TJPF_BGR:
247 case TJPF_RGBX:
248 case TJPF_BGRX:
249 case TJPF_XRGB:
250 case TJPF_XBGR:
251 case TJPF_RGBA:
252 case TJPF_BGRA:
253 case TJPF_ARGB:
254 case TJPF_ABGR:
255 dinfo->out_color_space=JCS_RGB; break;
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000256 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000257 default:
258 _throw("Unsupported pixel format");
hbono@chromium.org98626972011-08-03 03:13:08 +0000259 }
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000260
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000261 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
262
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000263 bailout:
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000264 return retval;
hbono@chromium.org98626972011-08-03 03:13:08 +0000265}
266
267
268static int getSubsamp(j_decompress_ptr dinfo)
269{
270 int retval=-1, i, k;
271 for(i=0; i<NUMSUBOPT; i++)
272 {
273 if(dinfo->num_components==pixelsize[i])
274 {
275 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
276 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
277 {
278 int match=0;
279 for(k=1; k<dinfo->num_components; k++)
280 {
281 if(dinfo->comp_info[k].h_samp_factor==1
282 && dinfo->comp_info[k].v_samp_factor==1)
283 match++;
284 }
285 if(match==dinfo->num_components-1)
286 {
287 retval=i; break;
288 }
289 }
290 }
291 }
292 return retval;
293}
294
295
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000296#ifndef JCS_EXTENSIONS
297
298/* Conversion functions to emulate the colorspace extensions. This allows the
299 TurboJPEG wrapper to be used with libjpeg */
300
301#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
302 int rowPad=pitch-width*PS; \
303 while(height--) \
304 { \
305 unsigned char *endOfRow=src+width*PS; \
306 while(src<endOfRow) \
307 { \
308 dst[RGB_RED]=src[ROFFSET]; \
309 dst[RGB_GREEN]=src[GOFFSET]; \
310 dst[RGB_BLUE]=src[BOFFSET]; \
311 dst+=RGB_PIXELSIZE; src+=PS; \
312 } \
313 src+=rowPad; \
314 } \
315}
316
317static unsigned char *toRGB(unsigned char *src, int width, int pitch,
318 int height, int pixelFormat, unsigned char *dst)
319{
320 unsigned char *retval=src;
321 switch(pixelFormat)
322 {
323 case TJPF_RGB:
324 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
325 retval=dst; TORGB(3, 0, 1, 2);
326 #endif
327 break;
328 case TJPF_BGR:
329 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
330 retval=dst; TORGB(3, 2, 1, 0);
331 #endif
332 break;
333 case TJPF_RGBX:
334 case TJPF_RGBA:
335 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
336 retval=dst; TORGB(4, 0, 1, 2);
337 #endif
338 break;
339 case TJPF_BGRX:
340 case TJPF_BGRA:
341 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
342 retval=dst; TORGB(4, 2, 1, 0);
343 #endif
344 break;
345 case TJPF_XRGB:
346 case TJPF_ARGB:
347 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
348 retval=dst; TORGB(4, 1, 2, 3);
349 #endif
350 break;
351 case TJPF_XBGR:
352 case TJPF_ABGR:
353 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
354 retval=dst; TORGB(4, 3, 2, 1);
355 #endif
356 break;
357 }
358 return retval;
359}
360
361#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
362 int rowPad=pitch-width*PS; \
363 while(height--) \
364 { \
365 unsigned char *endOfRow=dst+width*PS; \
366 while(dst<endOfRow) \
367 { \
368 dst[ROFFSET]=src[RGB_RED]; \
369 dst[GOFFSET]=src[RGB_GREEN]; \
370 dst[BOFFSET]=src[RGB_BLUE]; \
371 SETALPHA \
372 dst+=PS; src+=RGB_PIXELSIZE; \
373 } \
374 dst+=rowPad; \
375 } \
376}
377
378static void fromRGB(unsigned char *src, unsigned char *dst, int width,
379 int pitch, int height, int pixelFormat)
380{
381 switch(pixelFormat)
382 {
383 case TJPF_RGB:
384 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
385 FROMRGB(3, 0, 1, 2,);
386 #endif
387 break;
388 case TJPF_BGR:
389 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
390 FROMRGB(3, 2, 1, 0,);
391 #endif
392 break;
393 case TJPF_RGBX:
394 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
395 FROMRGB(4, 0, 1, 2,);
396 #endif
397 break;
398 case TJPF_RGBA:
399 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
400 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
401 #endif
402 break;
403 case TJPF_BGRX:
404 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
405 FROMRGB(4, 2, 1, 0,);
406 #endif
407 break;
408 case TJPF_BGRA:
409 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
410 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
411 #endif
412 break;
413 case TJPF_XRGB:
414 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
415 FROMRGB(4, 1, 2, 3,); return;
416 #endif
417 break;
418 case TJPF_ARGB:
419 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
420 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
421 #endif
422 break;
423 case TJPF_XBGR:
424 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
425 FROMRGB(4, 3, 2, 1,); return;
426 #endif
427 break;
428 case TJPF_ABGR:
429 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
430 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
431 #endif
432 break;
433 }
434}
435
436#endif
437
438
hbono@chromium.org98626972011-08-03 03:13:08 +0000439/* General API functions */
440
441DLLEXPORT char* DLLCALL tjGetErrorStr(void)
442{
443 return errStr;
444}
445
446
447DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
448{
449 getinstance(handle);
450 if(setjmp(this->jerr.setjmp_buffer)) return -1;
451 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
452 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
453 free(this);
454 return 0;
455}
456
457
458/* These are exposed mainly because Windows can't malloc() and free() across
459 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
460 with turbojpeg.dll for compatibility reasons. However, these functions
461 can potentially be used for other purposes by different implementations. */
462
463DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
464{
465 if(buf) free(buf);
466}
467
468
469DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
470{
471 return (unsigned char *)malloc(bytes);
472}
473
474
475/* Compressor */
476
477static tjhandle _tjInitCompress(tjinstance *this)
478{
479 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
480
481 /* This is also straight out of example.c */
482 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
483 this->jerr.pub.error_exit=my_error_exit;
484 this->jerr.pub.output_message=my_output_message;
485
486 if(setjmp(this->jerr.setjmp_buffer))
487 {
488 /* If we get here, the JPEG code has signaled an error. */
489 if(this) free(this); return NULL;
490 }
491
492 jpeg_create_compress(&this->cinfo);
493 /* Make an initial call so it will create the destination manager */
494 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
495
496 this->init|=COMPRESS;
497 return (tjhandle)this;
498}
499
500DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
501{
502 tjinstance *this=NULL;
503 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
504 {
505 snprintf(errStr, JMSG_LENGTH_MAX,
506 "tjInitCompress(): Memory allocation failure");
507 return NULL;
508 }
509 MEMZERO(this, sizeof(tjinstance));
510 return _tjInitCompress(this);
511}
512
513
514DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
515 int jpegSubsamp)
516{
517 unsigned long retval=0; int mcuw, mcuh, chromasf;
518 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
519 _throw("tjBufSize(): Invalid argument");
520
521 // This allows for rare corner cases in which a JPEG image can actually be
522 // larger than the uncompressed input (we wouldn't mention it if it hadn't
523 // happened before.)
524 mcuw=tjMCUWidth[jpegSubsamp];
525 mcuh=tjMCUHeight[jpegSubsamp];
526 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
527 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
528
529 bailout:
530 return retval;
531}
532
533
534DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
535{
536 unsigned long retval=0;
537 if(width<1 || height<1)
538 _throw("TJBUFSIZE(): Invalid argument");
539
540 // This allows for rare corner cases in which a JPEG image can actually be
541 // larger than the uncompressed input (we wouldn't mention it if it hadn't
542 // happened before.)
543 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
544
545 bailout:
546 return retval;
547}
548
549
550DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
551 int subsamp)
552{
553 unsigned long retval=0;
554 int pw, ph, cw, ch;
555 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
556 _throw("tjBufSizeYUV(): Invalid argument");
557 pw=PAD(width, tjMCUWidth[subsamp]/8);
558 ph=PAD(height, tjMCUHeight[subsamp]/8);
559 cw=pw*8/tjMCUWidth[subsamp]; ch=ph*8/tjMCUHeight[subsamp];
560 retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2);
561
562 bailout:
563 return retval;
564}
565
566
567DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
568 int subsamp)
569{
570 return tjBufSizeYUV(width, height, subsamp);
571}
572
573
574DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
575 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
576 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
577{
578 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000579 #ifndef JCS_EXTENSIONS
580 unsigned char *rgbBuf=NULL;
581 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000582
583 getinstance(handle)
584 if((this->init&COMPRESS)==0)
585 _throw("tjCompress2(): Instance has not been initialized for compression");
586
587 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
588 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
589 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
590 _throw("tjCompress2(): Invalid argument");
591
592 if(setjmp(this->jerr.setjmp_buffer))
593 {
594 /* If we get here, the JPEG code has signaled an error. */
595 retval=-1;
596 goto bailout;
597 }
598
599 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
600
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000601 #ifndef JCS_EXTENSIONS
602 if(pixelFormat!=TJPF_GRAY)
603 {
604 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
605 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
606 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
607 pitch=width*RGB_PIXELSIZE;
608 }
609 #endif
610
hbono@chromium.org98626972011-08-03 03:13:08 +0000611 cinfo->image_width=width;
612 cinfo->image_height=height;
613
614 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
615 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
616 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
617
618 if(flags&TJFLAG_NOREALLOC)
619 {
620 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
621 }
622 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000623 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000624 return -1;
hbono@chromium.org98626972011-08-03 03:13:08 +0000625
626 jpeg_start_compress(cinfo, TRUE);
627 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
628 _throw("tjCompress2(): Memory allocation failure");
629 for(i=0; i<height; i++)
630 {
631 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
632 else row_pointer[i]=&srcBuf[i*pitch];
633 }
634 while(cinfo->next_scanline<cinfo->image_height)
635 {
636 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
637 cinfo->image_height-cinfo->next_scanline);
638 }
639 jpeg_finish_compress(cinfo);
640
641 bailout:
642 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000643 #ifndef JCS_EXTENSIONS
644 if(rgbBuf) free(rgbBuf);
645 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000646 if(row_pointer) free(row_pointer);
647 return retval;
648}
649
650DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
651 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
652 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
653{
654 int retval=0; unsigned long size;
655 if(flags&TJ_YUV)
656 {
657 size=tjBufSizeYUV(width, height, jpegSubsamp);
658 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
659 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
660 }
661 else
662 {
663 retval=tjCompress2(handle, srcBuf, width, pitch, height,
664 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
665 flags|TJFLAG_NOREALLOC);
666 }
667 *jpegSize=size;
668 return retval;
669}
670
671
672DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
673 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
674 int subsamp, int flags)
675{
676 int i, retval=0; JSAMPROW *row_pointer=NULL;
677 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
678 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
679 JSAMPROW *outbuf[MAX_COMPONENTS];
680 int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
681 JSAMPLE *ptr=dstBuf;
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000682 unsigned long yuvsize=0;
hbono@chromium.org98626972011-08-03 03:13:08 +0000683 jpeg_component_info *compptr;
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000684 #ifndef JCS_EXTENSIONS
685 unsigned char *rgbBuf=NULL;
686 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000687
688 getinstance(handle);
689 if((this->init&COMPRESS)==0)
690 _throw("tjEncodeYUV2(): Instance has not been initialized for compression");
691
692 for(i=0; i<MAX_COMPONENTS; i++)
693 {
694 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
695 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
696 }
697
698 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
699 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
700 || subsamp>=NUMSUBOPT)
701 _throw("tjEncodeYUV2(): Invalid argument");
702
703 if(setjmp(this->jerr.setjmp_buffer))
704 {
705 /* If we get here, the JPEG code has signaled an error. */
706 retval=-1;
707 goto bailout;
708 }
709
710 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
711
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000712 #ifndef JCS_EXTENSIONS
713 if(pixelFormat!=TJPF_GRAY)
714 {
715 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
716 if(!rgbBuf) _throw("tjEncodeYUV2(): Memory allocation failure");
717 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
718 pitch=width*RGB_PIXELSIZE;
719 }
720 #endif
721
hbono@chromium.org98626972011-08-03 03:13:08 +0000722 cinfo->image_width=width;
723 cinfo->image_height=height;
724
725 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
726 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
727 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
728
729 yuvsize=tjBufSizeYUV(width, height, subsamp);
730 jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0);
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000731 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
hbono@chromium.org98626972011-08-03 03:13:08 +0000732
733 jpeg_start_compress(cinfo, TRUE);
734 pw=PAD(width, cinfo->max_h_samp_factor);
735 ph=PAD(height, cinfo->max_v_samp_factor);
736
737 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
738 _throw("tjEncodeYUV2(): Memory allocation failure");
739 for(i=0; i<height; i++)
740 {
741 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
742 else row_pointer[i]=&srcBuf[i*pitch];
743 }
744 if(height<ph)
745 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
746
747 for(i=0; i<cinfo->num_components; i++)
748 {
749 compptr=&cinfo->comp_info[i];
750 _tmpbuf[i]=(JSAMPLE *)malloc(
751 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
752 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
753 if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
754 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
755 if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
756 for(row=0; row<cinfo->max_v_samp_factor; row++)
757 {
758 unsigned char *_tmpbuf_aligned=
759 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
760 tmpbuf[i][row]=&_tmpbuf_aligned[
761 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
762 /compptr->h_samp_factor, 16) * row];
763 }
764 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
765 * compptr->v_samp_factor + 16);
766 if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
767 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
768 if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
769 for(row=0; row<compptr->v_samp_factor; row++)
770 {
771 unsigned char *_tmpbuf2_aligned=
772 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
773 tmpbuf2[i][row]=&_tmpbuf2_aligned[
774 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
775 }
776 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
777 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
778 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
779 if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
780 for(row=0; row<ch[i]; row++)
781 {
782 outbuf[i][row]=ptr;
783 ptr+=PAD(cw[i], 4);
784 }
785 }
786 if(yuvsize!=(unsigned long)(ptr-dstBuf))
787 _throw("tjEncodeYUV2(): Generated image is not the correct size");
788
789 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
790 {
791 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
792 cinfo->max_v_samp_factor);
793 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
794 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
795 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
796 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
797 compptr->v_samp_factor, cw[i]);
798 }
799 cinfo->next_scanline+=height;
800 jpeg_abort_compress(cinfo);
801
802 bailout:
803 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000804 #ifndef JCS_EXTENSIONS
805 if(rgbBuf) free(rgbBuf);
806 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000807 if(row_pointer) free(row_pointer);
808 for(i=0; i<MAX_COMPONENTS; i++)
809 {
810 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
811 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
812 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
813 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
814 if(outbuf[i]!=NULL) free(outbuf[i]);
815 }
816 return retval;
817}
818
819DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
820 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
821 int subsamp, int flags)
822{
823 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
824 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
825}
826
827
828/* Decompressor */
829
830static tjhandle _tjInitDecompress(tjinstance *this)
831{
832 unsigned char buffer[1];
833
834 /* This is also straight out of example.c */
835 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
836 this->jerr.pub.error_exit=my_error_exit;
837 this->jerr.pub.output_message=my_output_message;
838
839 if(setjmp(this->jerr.setjmp_buffer))
840 {
841 /* If we get here, the JPEG code has signaled an error. */
842 if(this) free(this); return NULL;
843 }
844
845 jpeg_create_decompress(&this->dinfo);
846 /* Make an initial call so it will create the source manager */
847 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
848
849 this->init|=DECOMPRESS;
850 return (tjhandle)this;
851}
852
853DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
854{
855 tjinstance *this;
856 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
857 {
858 snprintf(errStr, JMSG_LENGTH_MAX,
859 "tjInitDecompress(): Memory allocation failure");
860 return NULL;
861 }
862 MEMZERO(this, sizeof(tjinstance));
863 return _tjInitDecompress(this);
864}
865
866
867DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
868 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
869 int *jpegSubsamp)
870{
871 int retval=0;
872
873 getinstance(handle);
874 if((this->init&DECOMPRESS)==0)
875 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
876
877 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
878 || jpegSubsamp==NULL)
879 _throw("tjDecompressHeader2(): Invalid argument");
880
881 if(setjmp(this->jerr.setjmp_buffer))
882 {
883 /* If we get here, the JPEG code has signaled an error. */
884 return -1;
885 }
886
887 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
888 jpeg_read_header(dinfo, TRUE);
889
890 *width=dinfo->image_width;
891 *height=dinfo->image_height;
892 *jpegSubsamp=getSubsamp(dinfo);
893
894 jpeg_abort_decompress(dinfo);
895
896 if(*jpegSubsamp<0)
897 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
898 if(*width<1 || *height<1)
899 _throw("tjDecompressHeader2(): Invalid data returned in header");
900
901 bailout:
902 return retval;
903}
904
905DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
906 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
907{
908 int jpegSubsamp;
909 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
910 &jpegSubsamp);
911}
912
913
914DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
915{
916 if(numscalingfactors==NULL)
917 {
918 snprintf(errStr, JMSG_LENGTH_MAX,
919 "tjGetScalingFactors(): Invalid argument");
920 return NULL;
921 }
922
923 *numscalingfactors=NUMSF;
924 return (tjscalingfactor *)sf;
925}
926
927
928DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
929 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
930 int height, int pixelFormat, int flags)
931{
932 int i, retval=0; JSAMPROW *row_pointer=NULL;
933 int jpegwidth, jpegheight, scaledw, scaledh;
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000934 #ifndef JCS_EXTENSIONS
935 unsigned char *rgbBuf=NULL;
936 unsigned char *_dstBuf=NULL; int _pitch=0;
937 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000938
939 getinstance(handle);
940 if((this->init&DECOMPRESS)==0)
941 _throw("tjDecompress2(): Instance has not been initialized for decompression");
942
943 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
944 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
945 _throw("tjDecompress2(): Invalid argument");
946
947 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
948 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
949 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
950
951 if(setjmp(this->jerr.setjmp_buffer))
952 {
953 /* If we get here, the JPEG code has signaled an error. */
954 retval=-1;
955 goto bailout;
956 }
957
958 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
959 jpeg_read_header(dinfo, TRUE);
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000960 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000961 {
962 retval=-1; goto bailout;
963 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000964
965 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
966
967 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
968 if(width==0) width=jpegwidth;
969 if(height==0) height=jpegheight;
970 for(i=0; i<NUMSF; i++)
971 {
972 scaledw=TJSCALED(jpegwidth, sf[i]);
973 scaledh=TJSCALED(jpegheight, sf[i]);
974 if(scaledw<=width && scaledh<=height)
975 break;
976 }
977 if(scaledw>width || scaledh>height)
978 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
979 width=scaledw; height=scaledh;
980 dinfo->scale_num=sf[i].num;
981 dinfo->scale_denom=sf[i].denom;
982
983 jpeg_start_decompress(dinfo);
984 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000985
986 #ifndef JCS_EXTENSIONS
987 if(pixelFormat!=TJPF_GRAY &&
988 (RGB_RED!=tjRedOffset[pixelFormat] ||
989 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
990 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
991 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
992 {
993 rgbBuf=(unsigned char *)malloc(width*height*3);
994 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
995 _pitch=pitch; pitch=width*3;
996 _dstBuf=dstBuf; dstBuf=rgbBuf;
997 }
998 #endif
999
hbono@chromium.org98626972011-08-03 03:13:08 +00001000 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1001 *dinfo->output_height))==NULL)
1002 _throw("tjDecompress2(): Memory allocation failure");
1003 for(i=0; i<(int)dinfo->output_height; i++)
1004 {
1005 if(flags&TJFLAG_BOTTOMUP)
1006 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1007 else row_pointer[i]=&dstBuf[i*pitch];
1008 }
1009 while(dinfo->output_scanline<dinfo->output_height)
1010 {
1011 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1012 dinfo->output_height-dinfo->output_scanline);
1013 }
1014 jpeg_finish_decompress(dinfo);
1015
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001016 #ifndef JCS_EXTENSIONS
1017 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1018 #endif
1019
hbono@chromium.org98626972011-08-03 03:13:08 +00001020 bailout:
1021 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001022 #ifndef JCS_EXTENSIONS
1023 if(rgbBuf) free(rgbBuf);
1024 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +00001025 if(row_pointer) free(row_pointer);
1026 return retval;
1027}
1028
1029DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1030 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1031 int height, int pixelSize, int flags)
1032{
1033 if(flags&TJ_YUV)
1034 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1035 else
1036 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1037 height, getPixelFormat(pixelSize, flags), flags);
1038}
1039
1040
1041DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1042 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1043 int flags)
1044{
1045 int i, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
1046 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1047 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1048 JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS];
1049
1050 getinstance(handle);
1051 if((this->init&DECOMPRESS)==0)
1052 _throw("tjDecompressToYUV(): Instance has not been initialized for decompression");
1053
1054 for(i=0; i<MAX_COMPONENTS; i++)
1055 {
1056 tmpbuf[i]=NULL; outbuf[i]=NULL;
1057 }
1058
1059 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
1060 _throw("tjDecompressToYUV(): Invalid argument");
1061
1062 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1063 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1064 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1065
1066 if(setjmp(this->jerr.setjmp_buffer))
1067 {
1068 /* If we get here, the JPEG code has signaled an error. */
1069 retval=-1;
1070 goto bailout;
1071 }
1072
1073 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1074 jpeg_read_header(dinfo, TRUE);
1075
1076 for(i=0; i<dinfo->num_components; i++)
1077 {
1078 jpeg_component_info *compptr=&dinfo->comp_info[i];
1079 int ih;
1080 iw[i]=compptr->width_in_blocks*DCTSIZE;
1081 ih=compptr->height_in_blocks*DCTSIZE;
1082 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
1083 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
1084 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
1085 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
1086 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
1087 th[i]=compptr->v_samp_factor*DCTSIZE;
1088 tmpbufsize+=iw[i]*th[i];
1089 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
1090 _throw("tjDecompressToYUV(): Memory allocation failure");
1091 for(row=0; row<ch[i]; row++)
1092 {
1093 outbuf[i][row]=ptr;
1094 ptr+=PAD(cw[i], 4);
1095 }
1096 }
1097 if(usetmpbuf)
1098 {
1099 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1100 _throw("tjDecompressToYUV(): Memory allocation failure");
1101 ptr=_tmpbuf;
1102 for(i=0; i<dinfo->num_components; i++)
1103 {
1104 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1105 _throw("tjDecompressToYUV(): Memory allocation failure");
1106 for(row=0; row<th[i]; row++)
1107 {
1108 tmpbuf[i][row]=ptr;
1109 ptr+=iw[i];
1110 }
1111 }
1112 }
1113
1114 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
hbono@chromium.org11e6ee92012-07-19 06:04:44 +00001115 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
hbono@chromium.org98626972011-08-03 03:13:08 +00001116 dinfo->raw_data_out=TRUE;
1117
1118 jpeg_start_decompress(dinfo);
1119 for(row=0; row<(int)dinfo->output_height;
1120 row+=dinfo->max_v_samp_factor*DCTSIZE)
1121 {
1122 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1123 int crow[MAX_COMPONENTS];
1124 for(i=0; i<dinfo->num_components; i++)
1125 {
1126 jpeg_component_info *compptr=&dinfo->comp_info[i];
1127 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1128 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1129 else yuvptr[i]=&outbuf[i][crow[i]];
1130 }
1131 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
1132 if(usetmpbuf)
1133 {
1134 int j;
1135 for(i=0; i<dinfo->num_components; i++)
1136 {
1137 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
1138 {
1139 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
1140 }
1141 }
1142 }
1143 }
1144 jpeg_finish_decompress(dinfo);
1145
1146 bailout:
1147 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1148 for(i=0; i<MAX_COMPONENTS; i++)
1149 {
1150 if(tmpbuf[i]) free(tmpbuf[i]);
1151 if(outbuf[i]) free(outbuf[i]);
1152 }
1153 if(_tmpbuf) free(_tmpbuf);
1154 return retval;
1155}
1156
1157
1158/* Transformer */
1159
1160DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1161{
1162 tjinstance *this=NULL; tjhandle handle=NULL;
1163 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1164 {
1165 snprintf(errStr, JMSG_LENGTH_MAX,
1166 "tjInitTransform(): Memory allocation failure");
1167 return NULL;
1168 }
1169 MEMZERO(this, sizeof(tjinstance));
1170 handle=_tjInitCompress(this);
1171 if(!handle) return NULL;
1172 handle=_tjInitDecompress(this);
1173 return handle;
1174}
1175
1176
1177DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1178 unsigned long jpegSize, int n, unsigned char **dstBufs,
1179 unsigned long *dstSizes, tjtransform *t, int flags)
1180{
1181 jpeg_transform_info *xinfo=NULL;
1182 jvirt_barray_ptr *srccoefs, *dstcoefs;
1183 int retval=0, i, jpegSubsamp;
1184
1185 getinstance(handle);
1186 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
1187 _throw("tjTransform(): Instance has not been initialized for transformation");
1188
1189 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1190 || t==NULL || flags<0)
1191 _throw("tjTransform(): Invalid argument");
1192
1193 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1194 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1195 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1196
1197 if(setjmp(this->jerr.setjmp_buffer))
1198 {
1199 /* If we get here, the JPEG code has signaled an error. */
1200 retval=-1;
1201 goto bailout;
1202 }
1203
1204 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1205
1206 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1207 ==NULL)
1208 _throw("tjTransform(): Memory allocation failure");
1209 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
1210
1211 for(i=0; i<n; i++)
1212 {
1213 xinfo[i].transform=xformtypes[t[i].op];
1214 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1215 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1216 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1217 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1218 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
1219 else xinfo[i].slow_hflip=0;
1220
1221 if(xinfo[i].crop)
1222 {
1223 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
1224 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
1225 if(t[i].r.w!=0)
1226 {
1227 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
1228 }
1229 else xinfo[i].crop_width=JCROP_UNSET;
1230 if(t[i].r.h!=0)
1231 {
1232 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
1233 }
1234 else xinfo[i].crop_height=JCROP_UNSET;
1235 }
1236 }
1237
1238 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1239 jpeg_read_header(dinfo, TRUE);
1240 jpegSubsamp=getSubsamp(dinfo);
1241 if(jpegSubsamp<0)
1242 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
1243
1244 for(i=0; i<n; i++)
1245 {
1246 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
1247 _throw("tjTransform(): Transform is not perfect");
1248
1249 if(xinfo[i].crop)
1250 {
1251 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1252 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1253 {
1254 snprintf(errStr, JMSG_LENGTH_MAX,
1255 "To crop this JPEG image, x must be a multiple of %d\n"
1256 "and y must be a multiple of %d.\n",
1257 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1258 retval=-1; goto bailout;
1259 }
1260 }
1261 }
1262
1263 srccoefs=jpeg_read_coefficients(dinfo);
1264
1265 for(i=0; i<n; i++)
1266 {
1267 int w, h, alloc=1;
1268 if(!xinfo[i].crop)
1269 {
1270 w=dinfo->image_width; h=dinfo->image_height;
1271 }
1272 else
1273 {
1274 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
1275 }
1276 if(flags&TJFLAG_NOREALLOC)
1277 {
1278 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
1279 }
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001280 if(!(t[i].options&TJXOPT_NOOUTPUT))
1281 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
hbono@chromium.org98626972011-08-03 03:13:08 +00001282 jpeg_copy_critical_parameters(dinfo, cinfo);
1283 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
1284 &xinfo[i]);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001285 if(!(t[i].options&TJXOPT_NOOUTPUT))
1286 {
1287 jpeg_write_coefficients(cinfo, dstcoefs);
1288 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1289 }
1290 else jinit_c_master_control(cinfo, TRUE);
hbono@chromium.org98626972011-08-03 03:13:08 +00001291 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
1292 &xinfo[i]);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001293 if(t[i].customFilter)
1294 {
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001295 int ci, y; JDIMENSION by;
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001296 for(ci=0; ci<cinfo->num_components; ci++)
1297 {
1298 jpeg_component_info *compptr=&cinfo->comp_info[ci];
1299 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1300 DCTSIZE};
1301 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1302 compptr->height_in_blocks*DCTSIZE};
1303 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1304 {
1305 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1306 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1307 TRUE);
1308 for(y=0; y<compptr->v_samp_factor; y++)
1309 {
1310 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
1311 ci, i, &t[i])==-1)
1312 _throw("tjTransform(): Error in custom filter");
1313 arrayRegion.y+=DCTSIZE;
1314 }
1315 }
1316 }
1317 }
1318 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
hbono@chromium.org98626972011-08-03 03:13:08 +00001319 }
1320
1321 jpeg_finish_decompress(dinfo);
1322
1323 bailout:
1324 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1325 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1326 if(xinfo) free(xinfo);
1327 return retval;
1328}