blob: 9117273df304e6b1d66b2352aa9e097a9cb2aa59 [file] [log] [blame]
hbono@chromium.org98626972011-08-03 03:13:08 +00001/*
noel@chromium.org3395bcc2014-04-14 06:56:00 +00002 * Copyright (C)2009-2012, 2014 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>
34#include <jinclude.h>
35#define JPEG_INTERNALS
36#include <jpeglib.h>
37#include <jerror.h>
38#include <setjmp.h>
39#include "./turbojpeg.h"
40#include "./tjutil.h"
41#include "transupp.h"
42
43extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
44 unsigned long *, boolean);
45extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
46
47#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
48
49
50/* Error handling (based on example in example.c) */
51
52static char errStr[JMSG_LENGTH_MAX]="No error";
53
54struct my_error_mgr
55{
56 struct jpeg_error_mgr pub;
57 jmp_buf setjmp_buffer;
58};
59typedef struct my_error_mgr *my_error_ptr;
60
61static void my_error_exit(j_common_ptr cinfo)
62{
63 my_error_ptr myerr=(my_error_ptr)cinfo->err;
64 (*cinfo->err->output_message)(cinfo);
65 longjmp(myerr->setjmp_buffer, 1);
66}
67
68/* Based on output_message() in jerror.c */
69
70static void my_output_message(j_common_ptr cinfo)
71{
72 (*cinfo->err->format_message)(cinfo, errStr);
73}
74
75
76/* Global structures, macros, etc. */
77
78enum {COMPRESS=1, DECOMPRESS=2};
79
80typedef struct _tjinstance
81{
82 struct jpeg_compress_struct cinfo;
83 struct jpeg_decompress_struct dinfo;
84 struct my_error_mgr jerr;
85 int init;
86} tjinstance;
87
88static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
89
90static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
91{
92 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
93 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
94};
95
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +000096#define NUMSF 16
hbono@chromium.org98626972011-08-03 03:13:08 +000097static const tjscalingfactor sf[NUMSF]={
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +000098 {2, 1},
99 {15, 8},
100 {7, 4},
101 {13, 8},
102 {3, 2},
103 {11, 8},
104 {5, 4},
105 {9, 8},
hbono@chromium.org98626972011-08-03 03:13:08 +0000106 {1, 1},
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000107 {7, 8},
108 {3, 4},
109 {5, 8},
hbono@chromium.org98626972011-08-03 03:13:08 +0000110 {1, 2},
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000111 {3, 8},
hbono@chromium.org98626972011-08-03 03:13:08 +0000112 {1, 4},
113 {1, 8}
114};
115
116#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
117 retval=-1; goto bailout;}
118#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
119 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
120 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
121 return -1;} \
122 cinfo=&this->cinfo; dinfo=&this->dinfo;
123
124static int getPixelFormat(int pixelSize, int flags)
125{
126 if(pixelSize==1) return TJPF_GRAY;
127 if(pixelSize==3)
128 {
129 if(flags&TJ_BGR) return TJPF_BGR;
130 else return TJPF_RGB;
131 }
132 if(pixelSize==4)
133 {
134 if(flags&TJ_ALPHAFIRST)
135 {
136 if(flags&TJ_BGR) return TJPF_XBGR;
137 else return TJPF_XRGB;
138 }
139 else
140 {
141 if(flags&TJ_BGR) return TJPF_BGRX;
142 else return TJPF_RGBX;
143 }
144 }
145 return -1;
146}
147
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000148static int setCompDefaults(struct jpeg_compress_struct *cinfo,
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000149 int pixelFormat, int subsamp, int jpegQual, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +0000150{
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000151 int retval=0;
152
hbono@chromium.org98626972011-08-03 03:13:08 +0000153 switch(pixelFormat)
154 {
155 case TJPF_GRAY:
156 cinfo->in_color_space=JCS_GRAYSCALE; break;
157 #if JCS_EXTENSIONS==1
158 case TJPF_RGB:
159 cinfo->in_color_space=JCS_EXT_RGB; break;
160 case TJPF_BGR:
161 cinfo->in_color_space=JCS_EXT_BGR; break;
162 case TJPF_RGBX:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000163 case TJPF_RGBA:
hbono@chromium.org98626972011-08-03 03:13:08 +0000164 cinfo->in_color_space=JCS_EXT_RGBX; break;
165 case TJPF_BGRX:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000166 case TJPF_BGRA:
hbono@chromium.org98626972011-08-03 03:13:08 +0000167 cinfo->in_color_space=JCS_EXT_BGRX; break;
168 case TJPF_XRGB:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000169 case TJPF_ARGB:
hbono@chromium.org98626972011-08-03 03:13:08 +0000170 cinfo->in_color_space=JCS_EXT_XRGB; break;
171 case TJPF_XBGR:
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000172 case TJPF_ABGR:
hbono@chromium.org98626972011-08-03 03:13:08 +0000173 cinfo->in_color_space=JCS_EXT_XBGR; break;
174 #else
175 case TJPF_RGB:
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000176 case TJPF_BGR:
177 case TJPF_RGBX:
178 case TJPF_BGRX:
179 case TJPF_XRGB:
180 case TJPF_XBGR:
181 case TJPF_RGBA:
182 case TJPF_BGRA:
183 case TJPF_ARGB:
184 case TJPF_ABGR:
185 cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
186 break;
hbono@chromium.org98626972011-08-03 03:13:08 +0000187 #endif
188 }
189
190 cinfo->input_components=tjPixelSize[pixelFormat];
191 jpeg_set_defaults(cinfo);
192 if(jpegQual>=0)
193 {
194 jpeg_set_quality(cinfo, jpegQual, TRUE);
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000195 if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
hbono@chromium.org98626972011-08-03 03:13:08 +0000196 else cinfo->dct_method=JDCT_FASTEST;
197 }
198 if(subsamp==TJSAMP_GRAY)
199 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
200 else
201 jpeg_set_colorspace(cinfo, JCS_YCbCr);
202
203 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
204 cinfo->comp_info[1].h_samp_factor=1;
205 cinfo->comp_info[2].h_samp_factor=1;
206 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
207 cinfo->comp_info[1].v_samp_factor=1;
208 cinfo->comp_info[2].v_samp_factor=1;
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000209
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000210 return retval;
hbono@chromium.org98626972011-08-03 03:13:08 +0000211}
212
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000213static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000214 int pixelFormat, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +0000215{
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000216 int retval=0;
217
hbono@chromium.org98626972011-08-03 03:13:08 +0000218 switch(pixelFormat)
219 {
220 case TJPF_GRAY:
221 dinfo->out_color_space=JCS_GRAYSCALE; break;
222 #if JCS_EXTENSIONS==1
223 case TJPF_RGB:
224 dinfo->out_color_space=JCS_EXT_RGB; break;
225 case TJPF_BGR:
226 dinfo->out_color_space=JCS_EXT_BGR; break;
227 case TJPF_RGBX:
228 dinfo->out_color_space=JCS_EXT_RGBX; break;
229 case TJPF_BGRX:
230 dinfo->out_color_space=JCS_EXT_BGRX; break;
231 case TJPF_XRGB:
232 dinfo->out_color_space=JCS_EXT_XRGB; break;
233 case TJPF_XBGR:
234 dinfo->out_color_space=JCS_EXT_XBGR; break;
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000235 #if JCS_ALPHA_EXTENSIONS==1
236 case TJPF_RGBA:
237 dinfo->out_color_space=JCS_EXT_RGBA; break;
238 case TJPF_BGRA:
239 dinfo->out_color_space=JCS_EXT_BGRA; break;
240 case TJPF_ARGB:
241 dinfo->out_color_space=JCS_EXT_ARGB; break;
242 case TJPF_ABGR:
243 dinfo->out_color_space=JCS_EXT_ABGR; break;
244 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000245 #else
246 case TJPF_RGB:
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000247 case TJPF_BGR:
248 case TJPF_RGBX:
249 case TJPF_BGRX:
250 case TJPF_XRGB:
251 case TJPF_XBGR:
252 case TJPF_RGBA:
253 case TJPF_BGRA:
254 case TJPF_ARGB:
255 case TJPF_ABGR:
256 dinfo->out_color_space=JCS_RGB; break;
hbono@chromium.org0ec930e2012-01-18 07:01:04 +0000257 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000258 default:
259 _throw("Unsupported pixel format");
hbono@chromium.org98626972011-08-03 03:13:08 +0000260 }
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000261
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000262 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
263
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000264 bailout:
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000265 return retval;
hbono@chromium.org98626972011-08-03 03:13:08 +0000266}
267
268
269static int getSubsamp(j_decompress_ptr dinfo)
270{
271 int retval=-1, i, k;
272 for(i=0; i<NUMSUBOPT; i++)
273 {
274 if(dinfo->num_components==pixelsize[i])
275 {
276 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
277 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
278 {
279 int match=0;
280 for(k=1; k<dinfo->num_components; k++)
281 {
282 if(dinfo->comp_info[k].h_samp_factor==1
283 && dinfo->comp_info[k].v_samp_factor==1)
284 match++;
285 }
286 if(match==dinfo->num_components-1)
287 {
288 retval=i; break;
289 }
290 }
291 }
292 }
293 return retval;
294}
295
296
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000297#ifndef JCS_EXTENSIONS
298
299/* Conversion functions to emulate the colorspace extensions. This allows the
300 TurboJPEG wrapper to be used with libjpeg */
301
302#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
303 int rowPad=pitch-width*PS; \
304 while(height--) \
305 { \
306 unsigned char *endOfRow=src+width*PS; \
307 while(src<endOfRow) \
308 { \
309 dst[RGB_RED]=src[ROFFSET]; \
310 dst[RGB_GREEN]=src[GOFFSET]; \
311 dst[RGB_BLUE]=src[BOFFSET]; \
312 dst+=RGB_PIXELSIZE; src+=PS; \
313 } \
314 src+=rowPad; \
315 } \
316}
317
318static unsigned char *toRGB(unsigned char *src, int width, int pitch,
319 int height, int pixelFormat, unsigned char *dst)
320{
321 unsigned char *retval=src;
322 switch(pixelFormat)
323 {
324 case TJPF_RGB:
325 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
326 retval=dst; TORGB(3, 0, 1, 2);
327 #endif
328 break;
329 case TJPF_BGR:
330 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
331 retval=dst; TORGB(3, 2, 1, 0);
332 #endif
333 break;
334 case TJPF_RGBX:
335 case TJPF_RGBA:
336 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
337 retval=dst; TORGB(4, 0, 1, 2);
338 #endif
339 break;
340 case TJPF_BGRX:
341 case TJPF_BGRA:
342 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
343 retval=dst; TORGB(4, 2, 1, 0);
344 #endif
345 break;
346 case TJPF_XRGB:
347 case TJPF_ARGB:
348 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
349 retval=dst; TORGB(4, 1, 2, 3);
350 #endif
351 break;
352 case TJPF_XBGR:
353 case TJPF_ABGR:
354 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
355 retval=dst; TORGB(4, 3, 2, 1);
356 #endif
357 break;
358 }
359 return retval;
360}
361
362#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
363 int rowPad=pitch-width*PS; \
364 while(height--) \
365 { \
366 unsigned char *endOfRow=dst+width*PS; \
367 while(dst<endOfRow) \
368 { \
369 dst[ROFFSET]=src[RGB_RED]; \
370 dst[GOFFSET]=src[RGB_GREEN]; \
371 dst[BOFFSET]=src[RGB_BLUE]; \
372 SETALPHA \
373 dst+=PS; src+=RGB_PIXELSIZE; \
374 } \
375 dst+=rowPad; \
376 } \
377}
378
379static void fromRGB(unsigned char *src, unsigned char *dst, int width,
380 int pitch, int height, int pixelFormat)
381{
382 switch(pixelFormat)
383 {
384 case TJPF_RGB:
385 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
386 FROMRGB(3, 0, 1, 2,);
387 #endif
388 break;
389 case TJPF_BGR:
390 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
391 FROMRGB(3, 2, 1, 0,);
392 #endif
393 break;
394 case TJPF_RGBX:
395 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
396 FROMRGB(4, 0, 1, 2,);
397 #endif
398 break;
399 case TJPF_RGBA:
400 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
401 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
402 #endif
403 break;
404 case TJPF_BGRX:
405 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
406 FROMRGB(4, 2, 1, 0,);
407 #endif
408 break;
409 case TJPF_BGRA:
410 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
411 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
412 #endif
413 break;
414 case TJPF_XRGB:
415 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
416 FROMRGB(4, 1, 2, 3,); return;
417 #endif
418 break;
419 case TJPF_ARGB:
420 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
421 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
422 #endif
423 break;
424 case TJPF_XBGR:
425 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
426 FROMRGB(4, 3, 2, 1,); return;
427 #endif
428 break;
429 case TJPF_ABGR:
430 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
431 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
432 #endif
433 break;
434 }
435}
436
437#endif
438
439
hbono@chromium.org98626972011-08-03 03:13:08 +0000440/* General API functions */
441
442DLLEXPORT char* DLLCALL tjGetErrorStr(void)
443{
444 return errStr;
445}
446
447
448DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
449{
450 getinstance(handle);
451 if(setjmp(this->jerr.setjmp_buffer)) return -1;
452 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
453 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
454 free(this);
455 return 0;
456}
457
458
459/* These are exposed mainly because Windows can't malloc() and free() across
460 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
461 with turbojpeg.dll for compatibility reasons. However, these functions
462 can potentially be used for other purposes by different implementations. */
463
464DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
465{
466 if(buf) free(buf);
467}
468
469
470DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
471{
472 return (unsigned char *)malloc(bytes);
473}
474
475
476/* Compressor */
477
478static tjhandle _tjInitCompress(tjinstance *this)
479{
480 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
481
482 /* This is also straight out of example.c */
483 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
484 this->jerr.pub.error_exit=my_error_exit;
485 this->jerr.pub.output_message=my_output_message;
486
487 if(setjmp(this->jerr.setjmp_buffer))
488 {
489 /* If we get here, the JPEG code has signaled an error. */
490 if(this) free(this); return NULL;
491 }
492
493 jpeg_create_compress(&this->cinfo);
494 /* Make an initial call so it will create the destination manager */
495 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
496
497 this->init|=COMPRESS;
498 return (tjhandle)this;
499}
500
501DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
502{
503 tjinstance *this=NULL;
504 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
505 {
506 snprintf(errStr, JMSG_LENGTH_MAX,
507 "tjInitCompress(): Memory allocation failure");
508 return NULL;
509 }
510 MEMZERO(this, sizeof(tjinstance));
511 return _tjInitCompress(this);
512}
513
514
515DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
516 int jpegSubsamp)
517{
518 unsigned long retval=0; int mcuw, mcuh, chromasf;
519 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
520 _throw("tjBufSize(): Invalid argument");
521
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000522 /* This allows for rare corner cases in which a JPEG image can actually be
523 larger than the uncompressed input (we wouldn't mention it if it hadn't
524 happened before.) */
hbono@chromium.org98626972011-08-03 03:13:08 +0000525 mcuw=tjMCUWidth[jpegSubsamp];
526 mcuh=tjMCUHeight[jpegSubsamp];
527 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
528 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
529
530 bailout:
531 return retval;
532}
533
hbono@chromium.org98626972011-08-03 03:13:08 +0000534DLLEXPORT 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
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000540 /* 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.) */
hbono@chromium.org98626972011-08-03 03:13:08 +0000543 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);
hbono@chromium.org98626972011-08-03 03:13:08 +0000689
690 for(i=0; i<MAX_COMPONENTS; i++)
691 {
692 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
693 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
694 }
695
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000696 if((this->init&COMPRESS)==0)
697 _throw("tjEncodeYUV2(): Instance has not been initialized for compression");
698
hbono@chromium.org98626972011-08-03 03:13:08 +0000699 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
700 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
701 || subsamp>=NUMSUBOPT)
702 _throw("tjEncodeYUV2(): Invalid argument");
703
704 if(setjmp(this->jerr.setjmp_buffer))
705 {
706 /* If we get here, the JPEG code has signaled an error. */
707 retval=-1;
708 goto bailout;
709 }
710
711 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
712
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000713 #ifndef JCS_EXTENSIONS
714 if(pixelFormat!=TJPF_GRAY)
715 {
716 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
717 if(!rgbBuf) _throw("tjEncodeYUV2(): Memory allocation failure");
718 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
719 pitch=width*RGB_PIXELSIZE;
720 }
721 #endif
722
hbono@chromium.org98626972011-08-03 03:13:08 +0000723 cinfo->image_width=width;
724 cinfo->image_height=height;
725
726 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
727 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
728 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
729
730 yuvsize=tjBufSizeYUV(width, height, subsamp);
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
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000733 /* Execute only the parts of jpeg_start_compress() that we need. If we
734 were to call the whole jpeg_start_compress() function, then it would try
735 to write the file headers, which could overflow the output buffer if the
736 YUV image were very small. */
737 if(cinfo->global_state!=CSTATE_START)
738 _throw("tjEncodeYUV3(): libjpeg API is in the wrong state");
739 (*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
740 jinit_c_master_control(cinfo, FALSE);
741 jinit_color_converter(cinfo);
742 jinit_downsampler(cinfo);
743 (*cinfo->cconvert->start_pass)(cinfo);
744
hbono@chromium.org98626972011-08-03 03:13:08 +0000745 pw=PAD(width, cinfo->max_h_samp_factor);
746 ph=PAD(height, cinfo->max_v_samp_factor);
747
748 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
749 _throw("tjEncodeYUV2(): Memory allocation failure");
750 for(i=0; i<height; i++)
751 {
752 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
753 else row_pointer[i]=&srcBuf[i*pitch];
754 }
755 if(height<ph)
756 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
757
758 for(i=0; i<cinfo->num_components; i++)
759 {
760 compptr=&cinfo->comp_info[i];
761 _tmpbuf[i]=(JSAMPLE *)malloc(
762 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
763 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
764 if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
765 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
766 if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
767 for(row=0; row<cinfo->max_v_samp_factor; row++)
768 {
769 unsigned char *_tmpbuf_aligned=
770 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
771 tmpbuf[i][row]=&_tmpbuf_aligned[
772 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
773 /compptr->h_samp_factor, 16) * row];
774 }
775 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
776 * compptr->v_samp_factor + 16);
777 if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
778 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
779 if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
780 for(row=0; row<compptr->v_samp_factor; row++)
781 {
782 unsigned char *_tmpbuf2_aligned=
783 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
784 tmpbuf2[i][row]=&_tmpbuf2_aligned[
785 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
786 }
787 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
788 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
789 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
790 if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
791 for(row=0; row<ch[i]; row++)
792 {
793 outbuf[i][row]=ptr;
794 ptr+=PAD(cw[i], 4);
795 }
796 }
797 if(yuvsize!=(unsigned long)(ptr-dstBuf))
798 _throw("tjEncodeYUV2(): Generated image is not the correct size");
799
800 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
801 {
802 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
803 cinfo->max_v_samp_factor);
804 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
805 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
806 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
807 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
808 compptr->v_samp_factor, cw[i]);
809 }
810 cinfo->next_scanline+=height;
811 jpeg_abort_compress(cinfo);
812
813 bailout:
814 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000815 #ifndef JCS_EXTENSIONS
816 if(rgbBuf) free(rgbBuf);
817 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000818 if(row_pointer) free(row_pointer);
819 for(i=0; i<MAX_COMPONENTS; i++)
820 {
821 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
822 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
823 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
824 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
825 if(outbuf[i]!=NULL) free(outbuf[i]);
826 }
827 return retval;
828}
829
830DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
831 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
832 int subsamp, int flags)
833{
834 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
835 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
836}
837
838
839/* Decompressor */
840
841static tjhandle _tjInitDecompress(tjinstance *this)
842{
843 unsigned char buffer[1];
844
845 /* This is also straight out of example.c */
846 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
847 this->jerr.pub.error_exit=my_error_exit;
848 this->jerr.pub.output_message=my_output_message;
849
850 if(setjmp(this->jerr.setjmp_buffer))
851 {
852 /* If we get here, the JPEG code has signaled an error. */
853 if(this) free(this); return NULL;
854 }
855
856 jpeg_create_decompress(&this->dinfo);
857 /* Make an initial call so it will create the source manager */
858 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
859
860 this->init|=DECOMPRESS;
861 return (tjhandle)this;
862}
863
864DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
865{
866 tjinstance *this;
867 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
868 {
869 snprintf(errStr, JMSG_LENGTH_MAX,
870 "tjInitDecompress(): Memory allocation failure");
871 return NULL;
872 }
873 MEMZERO(this, sizeof(tjinstance));
874 return _tjInitDecompress(this);
875}
876
877
878DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
879 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
880 int *jpegSubsamp)
881{
882 int retval=0;
883
884 getinstance(handle);
885 if((this->init&DECOMPRESS)==0)
886 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
887
888 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
889 || jpegSubsamp==NULL)
890 _throw("tjDecompressHeader2(): Invalid argument");
891
892 if(setjmp(this->jerr.setjmp_buffer))
893 {
894 /* If we get here, the JPEG code has signaled an error. */
895 return -1;
896 }
897
898 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
899 jpeg_read_header(dinfo, TRUE);
900
901 *width=dinfo->image_width;
902 *height=dinfo->image_height;
903 *jpegSubsamp=getSubsamp(dinfo);
904
905 jpeg_abort_decompress(dinfo);
906
907 if(*jpegSubsamp<0)
908 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
909 if(*width<1 || *height<1)
910 _throw("tjDecompressHeader2(): Invalid data returned in header");
911
912 bailout:
913 return retval;
914}
915
916DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
917 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
918{
919 int jpegSubsamp;
920 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
921 &jpegSubsamp);
922}
923
924
925DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
926{
927 if(numscalingfactors==NULL)
928 {
929 snprintf(errStr, JMSG_LENGTH_MAX,
930 "tjGetScalingFactors(): Invalid argument");
931 return NULL;
932 }
933
934 *numscalingfactors=NUMSF;
935 return (tjscalingfactor *)sf;
936}
937
938
939DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
940 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
941 int height, int pixelFormat, int flags)
942{
943 int i, retval=0; JSAMPROW *row_pointer=NULL;
944 int jpegwidth, jpegheight, scaledw, scaledh;
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000945 #ifndef JCS_EXTENSIONS
946 unsigned char *rgbBuf=NULL;
947 unsigned char *_dstBuf=NULL; int _pitch=0;
948 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +0000949
950 getinstance(handle);
951 if((this->init&DECOMPRESS)==0)
952 _throw("tjDecompress2(): Instance has not been initialized for decompression");
953
954 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
955 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
956 _throw("tjDecompress2(): Invalid argument");
957
958 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
959 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
960 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
961
962 if(setjmp(this->jerr.setjmp_buffer))
963 {
964 /* If we get here, the JPEG code has signaled an error. */
965 retval=-1;
966 goto bailout;
967 }
968
969 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
970 jpeg_read_header(dinfo, TRUE);
hbono@chromium.org11e6ee92012-07-19 06:04:44 +0000971 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000972 {
973 retval=-1; goto bailout;
974 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000975
976 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
977
978 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
979 if(width==0) width=jpegwidth;
980 if(height==0) height=jpegheight;
981 for(i=0; i<NUMSF; i++)
982 {
983 scaledw=TJSCALED(jpegwidth, sf[i]);
984 scaledh=TJSCALED(jpegheight, sf[i]);
985 if(scaledw<=width && scaledh<=height)
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000986 break;
hbono@chromium.org98626972011-08-03 03:13:08 +0000987 }
988 if(scaledw>width || scaledh>height)
989 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
990 width=scaledw; height=scaledh;
991 dinfo->scale_num=sf[i].num;
992 dinfo->scale_denom=sf[i].denom;
993
994 jpeg_start_decompress(dinfo);
995 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000996
997 #ifndef JCS_EXTENSIONS
998 if(pixelFormat!=TJPF_GRAY &&
999 (RGB_RED!=tjRedOffset[pixelFormat] ||
1000 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1001 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1002 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1003 {
1004 rgbBuf=(unsigned char *)malloc(width*height*3);
1005 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1006 _pitch=pitch; pitch=width*3;
1007 _dstBuf=dstBuf; dstBuf=rgbBuf;
1008 }
1009 #endif
1010
hbono@chromium.org98626972011-08-03 03:13:08 +00001011 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1012 *dinfo->output_height))==NULL)
1013 _throw("tjDecompress2(): Memory allocation failure");
1014 for(i=0; i<(int)dinfo->output_height; i++)
1015 {
1016 if(flags&TJFLAG_BOTTOMUP)
1017 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1018 else row_pointer[i]=&dstBuf[i*pitch];
1019 }
1020 while(dinfo->output_scanline<dinfo->output_height)
1021 {
1022 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1023 dinfo->output_height-dinfo->output_scanline);
1024 }
1025 jpeg_finish_decompress(dinfo);
1026
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001027 #ifndef JCS_EXTENSIONS
1028 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1029 #endif
1030
hbono@chromium.org98626972011-08-03 03:13:08 +00001031 bailout:
1032 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001033 #ifndef JCS_EXTENSIONS
1034 if(rgbBuf) free(rgbBuf);
1035 #endif
hbono@chromium.org98626972011-08-03 03:13:08 +00001036 if(row_pointer) free(row_pointer);
1037 return retval;
1038}
1039
1040DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1041 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1042 int height, int pixelSize, int flags)
1043{
1044 if(flags&TJ_YUV)
1045 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1046 else
1047 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1048 height, getPixelFormat(pixelSize, flags), flags);
1049}
1050
1051
1052DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1053 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1054 int flags)
1055{
1056 int i, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
1057 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1058 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1059 JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS];
1060
1061 getinstance(handle);
hbono@chromium.org98626972011-08-03 03:13:08 +00001062
1063 for(i=0; i<MAX_COMPONENTS; i++)
1064 {
1065 tmpbuf[i]=NULL; outbuf[i]=NULL;
1066 }
1067
noel@chromium.org3395bcc2014-04-14 06:56:00 +00001068 if((this->init&DECOMPRESS)==0)
1069 _throw("tjDecompressToYUV(): Instance has not been initialized for decompression");
1070
hbono@chromium.org98626972011-08-03 03:13:08 +00001071 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
1072 _throw("tjDecompressToYUV(): Invalid argument");
1073
1074 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1075 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1076 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1077
1078 if(setjmp(this->jerr.setjmp_buffer))
1079 {
1080 /* If we get here, the JPEG code has signaled an error. */
1081 retval=-1;
1082 goto bailout;
1083 }
1084
1085 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1086 jpeg_read_header(dinfo, TRUE);
1087
1088 for(i=0; i<dinfo->num_components; i++)
1089 {
1090 jpeg_component_info *compptr=&dinfo->comp_info[i];
1091 int ih;
1092 iw[i]=compptr->width_in_blocks*DCTSIZE;
1093 ih=compptr->height_in_blocks*DCTSIZE;
1094 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
1095 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
1096 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
1097 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
1098 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
1099 th[i]=compptr->v_samp_factor*DCTSIZE;
1100 tmpbufsize+=iw[i]*th[i];
1101 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
1102 _throw("tjDecompressToYUV(): Memory allocation failure");
1103 for(row=0; row<ch[i]; row++)
1104 {
1105 outbuf[i][row]=ptr;
1106 ptr+=PAD(cw[i], 4);
1107 }
1108 }
1109 if(usetmpbuf)
1110 {
1111 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1112 _throw("tjDecompressToYUV(): Memory allocation failure");
1113 ptr=_tmpbuf;
1114 for(i=0; i<dinfo->num_components; i++)
1115 {
1116 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1117 _throw("tjDecompressToYUV(): Memory allocation failure");
1118 for(row=0; row<th[i]; row++)
1119 {
1120 tmpbuf[i][row]=ptr;
1121 ptr+=iw[i];
1122 }
1123 }
1124 }
1125
1126 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
hbono@chromium.org11e6ee92012-07-19 06:04:44 +00001127 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
hbono@chromium.org98626972011-08-03 03:13:08 +00001128 dinfo->raw_data_out=TRUE;
1129
1130 jpeg_start_decompress(dinfo);
1131 for(row=0; row<(int)dinfo->output_height;
1132 row+=dinfo->max_v_samp_factor*DCTSIZE)
1133 {
1134 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1135 int crow[MAX_COMPONENTS];
1136 for(i=0; i<dinfo->num_components; i++)
1137 {
1138 jpeg_component_info *compptr=&dinfo->comp_info[i];
1139 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1140 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1141 else yuvptr[i]=&outbuf[i][crow[i]];
1142 }
1143 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
1144 if(usetmpbuf)
1145 {
1146 int j;
1147 for(i=0; i<dinfo->num_components; i++)
1148 {
1149 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
1150 {
1151 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
1152 }
1153 }
1154 }
1155 }
1156 jpeg_finish_decompress(dinfo);
1157
1158 bailout:
1159 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1160 for(i=0; i<MAX_COMPONENTS; i++)
1161 {
1162 if(tmpbuf[i]) free(tmpbuf[i]);
1163 if(outbuf[i]) free(outbuf[i]);
1164 }
1165 if(_tmpbuf) free(_tmpbuf);
1166 return retval;
1167}
1168
1169
1170/* Transformer */
1171
1172DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1173{
1174 tjinstance *this=NULL; tjhandle handle=NULL;
1175 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1176 {
1177 snprintf(errStr, JMSG_LENGTH_MAX,
1178 "tjInitTransform(): Memory allocation failure");
1179 return NULL;
1180 }
1181 MEMZERO(this, sizeof(tjinstance));
1182 handle=_tjInitCompress(this);
1183 if(!handle) return NULL;
1184 handle=_tjInitDecompress(this);
1185 return handle;
1186}
1187
1188
1189DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1190 unsigned long jpegSize, int n, unsigned char **dstBufs,
1191 unsigned long *dstSizes, tjtransform *t, int flags)
1192{
1193 jpeg_transform_info *xinfo=NULL;
1194 jvirt_barray_ptr *srccoefs, *dstcoefs;
1195 int retval=0, i, jpegSubsamp;
1196
1197 getinstance(handle);
1198 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
1199 _throw("tjTransform(): Instance has not been initialized for transformation");
1200
1201 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1202 || t==NULL || flags<0)
1203 _throw("tjTransform(): Invalid argument");
1204
1205 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1206 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1207 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1208
1209 if(setjmp(this->jerr.setjmp_buffer))
1210 {
1211 /* If we get here, the JPEG code has signaled an error. */
1212 retval=-1;
1213 goto bailout;
1214 }
1215
1216 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1217
1218 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1219 ==NULL)
1220 _throw("tjTransform(): Memory allocation failure");
1221 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
1222
1223 for(i=0; i<n; i++)
1224 {
1225 xinfo[i].transform=xformtypes[t[i].op];
1226 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1227 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1228 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1229 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1230 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
1231 else xinfo[i].slow_hflip=0;
1232
1233 if(xinfo[i].crop)
1234 {
1235 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
1236 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
1237 if(t[i].r.w!=0)
1238 {
1239 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
1240 }
1241 else xinfo[i].crop_width=JCROP_UNSET;
1242 if(t[i].r.h!=0)
1243 {
1244 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
1245 }
1246 else xinfo[i].crop_height=JCROP_UNSET;
1247 }
1248 }
1249
1250 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1251 jpeg_read_header(dinfo, TRUE);
1252 jpegSubsamp=getSubsamp(dinfo);
1253 if(jpegSubsamp<0)
1254 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
1255
1256 for(i=0; i<n; i++)
1257 {
1258 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
1259 _throw("tjTransform(): Transform is not perfect");
1260
1261 if(xinfo[i].crop)
1262 {
1263 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1264 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1265 {
1266 snprintf(errStr, JMSG_LENGTH_MAX,
1267 "To crop this JPEG image, x must be a multiple of %d\n"
1268 "and y must be a multiple of %d.\n",
1269 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1270 retval=-1; goto bailout;
1271 }
1272 }
1273 }
1274
1275 srccoefs=jpeg_read_coefficients(dinfo);
1276
1277 for(i=0; i<n; i++)
1278 {
1279 int w, h, alloc=1;
1280 if(!xinfo[i].crop)
1281 {
1282 w=dinfo->image_width; h=dinfo->image_height;
1283 }
1284 else
1285 {
1286 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
1287 }
1288 if(flags&TJFLAG_NOREALLOC)
1289 {
1290 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
1291 }
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001292 if(!(t[i].options&TJXOPT_NOOUTPUT))
1293 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
hbono@chromium.org98626972011-08-03 03:13:08 +00001294 jpeg_copy_critical_parameters(dinfo, cinfo);
1295 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
1296 &xinfo[i]);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001297 if(!(t[i].options&TJXOPT_NOOUTPUT))
1298 {
1299 jpeg_write_coefficients(cinfo, dstcoefs);
1300 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1301 }
1302 else jinit_c_master_control(cinfo, TRUE);
hbono@chromium.org98626972011-08-03 03:13:08 +00001303 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
1304 &xinfo[i]);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001305 if(t[i].customFilter)
1306 {
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +00001307 int ci, y; JDIMENSION by;
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001308 for(ci=0; ci<cinfo->num_components; ci++)
1309 {
1310 jpeg_component_info *compptr=&cinfo->comp_info[ci];
1311 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1312 DCTSIZE};
1313 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1314 compptr->height_in_blocks*DCTSIZE};
1315 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1316 {
1317 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1318 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1319 TRUE);
1320 for(y=0; y<compptr->v_samp_factor; y++)
1321 {
1322 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
1323 ci, i, &t[i])==-1)
1324 _throw("tjTransform(): Error in custom filter");
1325 arrayRegion.y+=DCTSIZE;
1326 }
1327 }
1328 }
1329 }
1330 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
hbono@chromium.org98626972011-08-03 03:13:08 +00001331 }
1332
1333 jpeg_finish_decompress(dinfo);
1334
1335 bailout:
1336 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1337 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1338 if(xinfo) free(xinfo);
1339 return retval;
1340}