blob: 9fc60cecd9605d87518a705d6a5d4a19cb782b07 [file] [log] [blame]
hbono@chromium.org98626972011-08-03 03:13:08 +00001/*
2 * Copyright (C)2009-2011 D. R. Commander. All Rights Reserved.
3 *
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
95#define NUMSF 4
96static const tjscalingfactor sf[NUMSF]={
97 {1, 1},
98 {1, 2},
99 {1, 4},
100 {1, 8}
101};
102
103#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
104 retval=-1; goto bailout;}
105#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
106 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
107 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
108 return -1;} \
109 cinfo=&this->cinfo; dinfo=&this->dinfo;
110
111static int getPixelFormat(int pixelSize, int flags)
112{
113 if(pixelSize==1) return TJPF_GRAY;
114 if(pixelSize==3)
115 {
116 if(flags&TJ_BGR) return TJPF_BGR;
117 else return TJPF_RGB;
118 }
119 if(pixelSize==4)
120 {
121 if(flags&TJ_ALPHAFIRST)
122 {
123 if(flags&TJ_BGR) return TJPF_XBGR;
124 else return TJPF_XRGB;
125 }
126 else
127 {
128 if(flags&TJ_BGR) return TJPF_BGRX;
129 else return TJPF_RGBX;
130 }
131 }
132 return -1;
133}
134
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000135static int setCompDefaults(struct jpeg_compress_struct *cinfo,
hbono@chromium.org98626972011-08-03 03:13:08 +0000136 int pixelFormat, int subsamp, int jpegQual)
137{
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000138 int retval=0;
139
hbono@chromium.org98626972011-08-03 03:13:08 +0000140 switch(pixelFormat)
141 {
142 case TJPF_GRAY:
143 cinfo->in_color_space=JCS_GRAYSCALE; break;
144 #if JCS_EXTENSIONS==1
145 case TJPF_RGB:
146 cinfo->in_color_space=JCS_EXT_RGB; break;
147 case TJPF_BGR:
148 cinfo->in_color_space=JCS_EXT_BGR; break;
149 case TJPF_RGBX:
150 cinfo->in_color_space=JCS_EXT_RGBX; break;
151 case TJPF_BGRX:
152 cinfo->in_color_space=JCS_EXT_BGRX; break;
153 case TJPF_XRGB:
154 cinfo->in_color_space=JCS_EXT_XRGB; break;
155 case TJPF_XBGR:
156 cinfo->in_color_space=JCS_EXT_XBGR; break;
157 #else
158 case TJPF_RGB:
159 if(RGB_RED==0 && RGB_GREEN==1 && RGB_BLUE==2 && RGB_PIXELSIZE==3)
160 {
161 cinfo->in_color_space=JCS_RGB; break;
162 }
163 default:
164 _throw("Unsupported pixel format");
165 #endif
166 }
167
168 cinfo->input_components=tjPixelSize[pixelFormat];
169 jpeg_set_defaults(cinfo);
170 if(jpegQual>=0)
171 {
172 jpeg_set_quality(cinfo, jpegQual, TRUE);
173 if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW;
174 else cinfo->dct_method=JDCT_FASTEST;
175 }
176 if(subsamp==TJSAMP_GRAY)
177 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
178 else
179 jpeg_set_colorspace(cinfo, JCS_YCbCr);
180
181 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
182 cinfo->comp_info[1].h_samp_factor=1;
183 cinfo->comp_info[2].h_samp_factor=1;
184 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
185 cinfo->comp_info[1].v_samp_factor=1;
186 cinfo->comp_info[2].v_samp_factor=1;
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000187
188 #if JCS_EXTENSIONS!=1
189 bailout:
190 #endif
191 return retval;
hbono@chromium.org98626972011-08-03 03:13:08 +0000192}
193
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000194static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
hbono@chromium.org98626972011-08-03 03:13:08 +0000195 int pixelFormat)
196{
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000197 int retval=0;
198
hbono@chromium.org98626972011-08-03 03:13:08 +0000199 switch(pixelFormat)
200 {
201 case TJPF_GRAY:
202 dinfo->out_color_space=JCS_GRAYSCALE; break;
203 #if JCS_EXTENSIONS==1
204 case TJPF_RGB:
205 dinfo->out_color_space=JCS_EXT_RGB; break;
206 case TJPF_BGR:
207 dinfo->out_color_space=JCS_EXT_BGR; break;
208 case TJPF_RGBX:
209 dinfo->out_color_space=JCS_EXT_RGBX; break;
210 case TJPF_BGRX:
211 dinfo->out_color_space=JCS_EXT_BGRX; break;
212 case TJPF_XRGB:
213 dinfo->out_color_space=JCS_EXT_XRGB; break;
214 case TJPF_XBGR:
215 dinfo->out_color_space=JCS_EXT_XBGR; break;
216 #else
217 case TJPF_RGB:
218 if(RGB_RED==0 && RGB_GREEN==1 && RGB_BLUE==2 && RGB_PIXELSIZE==3)
219 {
220 dinfo->out_color_space=JCS_RGB; break;
221 }
222 default:
223 _throw("Unsupported pixel format");
224 #endif
225 }
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000226
227 #if JCS_EXTENSIONS!=1
228 bailout:
229 #endif
230 return retval;
hbono@chromium.org98626972011-08-03 03:13:08 +0000231}
232
233
234static int getSubsamp(j_decompress_ptr dinfo)
235{
236 int retval=-1, i, k;
237 for(i=0; i<NUMSUBOPT; i++)
238 {
239 if(dinfo->num_components==pixelsize[i])
240 {
241 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
242 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
243 {
244 int match=0;
245 for(k=1; k<dinfo->num_components; k++)
246 {
247 if(dinfo->comp_info[k].h_samp_factor==1
248 && dinfo->comp_info[k].v_samp_factor==1)
249 match++;
250 }
251 if(match==dinfo->num_components-1)
252 {
253 retval=i; break;
254 }
255 }
256 }
257 }
258 return retval;
259}
260
261
262/* General API functions */
263
264DLLEXPORT char* DLLCALL tjGetErrorStr(void)
265{
266 return errStr;
267}
268
269
270DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
271{
272 getinstance(handle);
273 if(setjmp(this->jerr.setjmp_buffer)) return -1;
274 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
275 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
276 free(this);
277 return 0;
278}
279
280
281/* These are exposed mainly because Windows can't malloc() and free() across
282 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
283 with turbojpeg.dll for compatibility reasons. However, these functions
284 can potentially be used for other purposes by different implementations. */
285
286DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
287{
288 if(buf) free(buf);
289}
290
291
292DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
293{
294 return (unsigned char *)malloc(bytes);
295}
296
297
298/* Compressor */
299
300static tjhandle _tjInitCompress(tjinstance *this)
301{
302 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
303
304 /* This is also straight out of example.c */
305 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
306 this->jerr.pub.error_exit=my_error_exit;
307 this->jerr.pub.output_message=my_output_message;
308
309 if(setjmp(this->jerr.setjmp_buffer))
310 {
311 /* If we get here, the JPEG code has signaled an error. */
312 if(this) free(this); return NULL;
313 }
314
315 jpeg_create_compress(&this->cinfo);
316 /* Make an initial call so it will create the destination manager */
317 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
318
319 this->init|=COMPRESS;
320 return (tjhandle)this;
321}
322
323DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
324{
325 tjinstance *this=NULL;
326 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
327 {
328 snprintf(errStr, JMSG_LENGTH_MAX,
329 "tjInitCompress(): Memory allocation failure");
330 return NULL;
331 }
332 MEMZERO(this, sizeof(tjinstance));
333 return _tjInitCompress(this);
334}
335
336
337DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
338 int jpegSubsamp)
339{
340 unsigned long retval=0; int mcuw, mcuh, chromasf;
341 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
342 _throw("tjBufSize(): Invalid argument");
343
344 // This allows for rare corner cases in which a JPEG image can actually be
345 // larger than the uncompressed input (we wouldn't mention it if it hadn't
346 // happened before.)
347 mcuw=tjMCUWidth[jpegSubsamp];
348 mcuh=tjMCUHeight[jpegSubsamp];
349 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
350 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
351
352 bailout:
353 return retval;
354}
355
356
357DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
358{
359 unsigned long retval=0;
360 if(width<1 || height<1)
361 _throw("TJBUFSIZE(): Invalid argument");
362
363 // This allows for rare corner cases in which a JPEG image can actually be
364 // larger than the uncompressed input (we wouldn't mention it if it hadn't
365 // happened before.)
366 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
367
368 bailout:
369 return retval;
370}
371
372
373DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
374 int subsamp)
375{
376 unsigned long retval=0;
377 int pw, ph, cw, ch;
378 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
379 _throw("tjBufSizeYUV(): Invalid argument");
380 pw=PAD(width, tjMCUWidth[subsamp]/8);
381 ph=PAD(height, tjMCUHeight[subsamp]/8);
382 cw=pw*8/tjMCUWidth[subsamp]; ch=ph*8/tjMCUHeight[subsamp];
383 retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2);
384
385 bailout:
386 return retval;
387}
388
389
390DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
391 int subsamp)
392{
393 return tjBufSizeYUV(width, height, subsamp);
394}
395
396
397DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
398 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
399 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
400{
401 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
402
403 getinstance(handle)
404 if((this->init&COMPRESS)==0)
405 _throw("tjCompress2(): Instance has not been initialized for compression");
406
407 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
408 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
409 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
410 _throw("tjCompress2(): Invalid argument");
411
412 if(setjmp(this->jerr.setjmp_buffer))
413 {
414 /* If we get here, the JPEG code has signaled an error. */
415 retval=-1;
416 goto bailout;
417 }
418
419 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
420
421 cinfo->image_width=width;
422 cinfo->image_height=height;
423
424 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
425 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
426 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
427
428 if(flags&TJFLAG_NOREALLOC)
429 {
430 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
431 }
432 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000433 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1)
434 return -1;
hbono@chromium.org98626972011-08-03 03:13:08 +0000435
436 jpeg_start_compress(cinfo, TRUE);
437 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
438 _throw("tjCompress2(): Memory allocation failure");
439 for(i=0; i<height; i++)
440 {
441 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
442 else row_pointer[i]=&srcBuf[i*pitch];
443 }
444 while(cinfo->next_scanline<cinfo->image_height)
445 {
446 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
447 cinfo->image_height-cinfo->next_scanline);
448 }
449 jpeg_finish_compress(cinfo);
450
451 bailout:
452 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
453 if(row_pointer) free(row_pointer);
454 return retval;
455}
456
457DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
458 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
459 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
460{
461 int retval=0; unsigned long size;
462 if(flags&TJ_YUV)
463 {
464 size=tjBufSizeYUV(width, height, jpegSubsamp);
465 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
466 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
467 }
468 else
469 {
470 retval=tjCompress2(handle, srcBuf, width, pitch, height,
471 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
472 flags|TJFLAG_NOREALLOC);
473 }
474 *jpegSize=size;
475 return retval;
476}
477
478
479DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
480 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
481 int subsamp, int flags)
482{
483 int i, retval=0; JSAMPROW *row_pointer=NULL;
484 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
485 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
486 JSAMPROW *outbuf[MAX_COMPONENTS];
487 int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
488 JSAMPLE *ptr=dstBuf;
489 unsigned long yuvsize=0;
490 jpeg_component_info *compptr;
491
492 getinstance(handle);
493 if((this->init&COMPRESS)==0)
494 _throw("tjEncodeYUV2(): Instance has not been initialized for compression");
495
496 for(i=0; i<MAX_COMPONENTS; i++)
497 {
498 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
499 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
500 }
501
502 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
503 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
504 || subsamp>=NUMSUBOPT)
505 _throw("tjEncodeYUV2(): Invalid argument");
506
507 if(setjmp(this->jerr.setjmp_buffer))
508 {
509 /* If we get here, the JPEG code has signaled an error. */
510 retval=-1;
511 goto bailout;
512 }
513
514 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
515
516 cinfo->image_width=width;
517 cinfo->image_height=height;
518
519 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
520 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
521 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
522
523 yuvsize=tjBufSizeYUV(width, height, subsamp);
524 jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000525 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1)==-1) return -1;
hbono@chromium.org98626972011-08-03 03:13:08 +0000526
527 jpeg_start_compress(cinfo, TRUE);
528 pw=PAD(width, cinfo->max_h_samp_factor);
529 ph=PAD(height, cinfo->max_v_samp_factor);
530
531 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
532 _throw("tjEncodeYUV2(): Memory allocation failure");
533 for(i=0; i<height; i++)
534 {
535 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
536 else row_pointer[i]=&srcBuf[i*pitch];
537 }
538 if(height<ph)
539 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
540
541 for(i=0; i<cinfo->num_components; i++)
542 {
543 compptr=&cinfo->comp_info[i];
544 _tmpbuf[i]=(JSAMPLE *)malloc(
545 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
546 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
547 if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
548 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
549 if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
550 for(row=0; row<cinfo->max_v_samp_factor; row++)
551 {
552 unsigned char *_tmpbuf_aligned=
553 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
554 tmpbuf[i][row]=&_tmpbuf_aligned[
555 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
556 /compptr->h_samp_factor, 16) * row];
557 }
558 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
559 * compptr->v_samp_factor + 16);
560 if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
561 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
562 if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
563 for(row=0; row<compptr->v_samp_factor; row++)
564 {
565 unsigned char *_tmpbuf2_aligned=
566 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
567 tmpbuf2[i][row]=&_tmpbuf2_aligned[
568 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
569 }
570 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
571 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
572 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
573 if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
574 for(row=0; row<ch[i]; row++)
575 {
576 outbuf[i][row]=ptr;
577 ptr+=PAD(cw[i], 4);
578 }
579 }
580 if(yuvsize!=(unsigned long)(ptr-dstBuf))
581 _throw("tjEncodeYUV2(): Generated image is not the correct size");
582
583 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
584 {
585 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
586 cinfo->max_v_samp_factor);
587 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
588 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
589 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
590 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
591 compptr->v_samp_factor, cw[i]);
592 }
593 cinfo->next_scanline+=height;
594 jpeg_abort_compress(cinfo);
595
596 bailout:
597 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
598 if(row_pointer) free(row_pointer);
599 for(i=0; i<MAX_COMPONENTS; i++)
600 {
601 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
602 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
603 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
604 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
605 if(outbuf[i]!=NULL) free(outbuf[i]);
606 }
607 return retval;
608}
609
610DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
611 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
612 int subsamp, int flags)
613{
614 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
615 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
616}
617
618
619/* Decompressor */
620
621static tjhandle _tjInitDecompress(tjinstance *this)
622{
623 unsigned char buffer[1];
624
625 /* This is also straight out of example.c */
626 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
627 this->jerr.pub.error_exit=my_error_exit;
628 this->jerr.pub.output_message=my_output_message;
629
630 if(setjmp(this->jerr.setjmp_buffer))
631 {
632 /* If we get here, the JPEG code has signaled an error. */
633 if(this) free(this); return NULL;
634 }
635
636 jpeg_create_decompress(&this->dinfo);
637 /* Make an initial call so it will create the source manager */
638 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
639
640 this->init|=DECOMPRESS;
641 return (tjhandle)this;
642}
643
644DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
645{
646 tjinstance *this;
647 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
648 {
649 snprintf(errStr, JMSG_LENGTH_MAX,
650 "tjInitDecompress(): Memory allocation failure");
651 return NULL;
652 }
653 MEMZERO(this, sizeof(tjinstance));
654 return _tjInitDecompress(this);
655}
656
657
658DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
659 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
660 int *jpegSubsamp)
661{
662 int retval=0;
663
664 getinstance(handle);
665 if((this->init&DECOMPRESS)==0)
666 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
667
668 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
669 || jpegSubsamp==NULL)
670 _throw("tjDecompressHeader2(): Invalid argument");
671
672 if(setjmp(this->jerr.setjmp_buffer))
673 {
674 /* If we get here, the JPEG code has signaled an error. */
675 return -1;
676 }
677
678 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
679 jpeg_read_header(dinfo, TRUE);
680
681 *width=dinfo->image_width;
682 *height=dinfo->image_height;
683 *jpegSubsamp=getSubsamp(dinfo);
684
685 jpeg_abort_decompress(dinfo);
686
687 if(*jpegSubsamp<0)
688 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
689 if(*width<1 || *height<1)
690 _throw("tjDecompressHeader2(): Invalid data returned in header");
691
692 bailout:
693 return retval;
694}
695
696DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
697 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
698{
699 int jpegSubsamp;
700 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
701 &jpegSubsamp);
702}
703
704
705DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
706{
707 if(numscalingfactors==NULL)
708 {
709 snprintf(errStr, JMSG_LENGTH_MAX,
710 "tjGetScalingFactors(): Invalid argument");
711 return NULL;
712 }
713
714 *numscalingfactors=NUMSF;
715 return (tjscalingfactor *)sf;
716}
717
718
719DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
720 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
721 int height, int pixelFormat, int flags)
722{
723 int i, retval=0; JSAMPROW *row_pointer=NULL;
724 int jpegwidth, jpegheight, scaledw, scaledh;
725
726 getinstance(handle);
727 if((this->init&DECOMPRESS)==0)
728 _throw("tjDecompress2(): Instance has not been initialized for decompression");
729
730 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
731 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
732 _throw("tjDecompress2(): Invalid argument");
733
734 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
735 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
736 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
737
738 if(setjmp(this->jerr.setjmp_buffer))
739 {
740 /* If we get here, the JPEG code has signaled an error. */
741 retval=-1;
742 goto bailout;
743 }
744
745 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
746 jpeg_read_header(dinfo, TRUE);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000747 if(setDecompDefaults(dinfo, pixelFormat)==-1) return -1;
hbono@chromium.org98626972011-08-03 03:13:08 +0000748
749 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
750
751 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
752 if(width==0) width=jpegwidth;
753 if(height==0) height=jpegheight;
754 for(i=0; i<NUMSF; i++)
755 {
756 scaledw=TJSCALED(jpegwidth, sf[i]);
757 scaledh=TJSCALED(jpegheight, sf[i]);
758 if(scaledw<=width && scaledh<=height)
759 break;
760 }
761 if(scaledw>width || scaledh>height)
762 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
763 width=scaledw; height=scaledh;
764 dinfo->scale_num=sf[i].num;
765 dinfo->scale_denom=sf[i].denom;
766
767 jpeg_start_decompress(dinfo);
768 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
769 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
770 *dinfo->output_height))==NULL)
771 _throw("tjDecompress2(): Memory allocation failure");
772 for(i=0; i<(int)dinfo->output_height; i++)
773 {
774 if(flags&TJFLAG_BOTTOMUP)
775 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
776 else row_pointer[i]=&dstBuf[i*pitch];
777 }
778 while(dinfo->output_scanline<dinfo->output_height)
779 {
780 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
781 dinfo->output_height-dinfo->output_scanline);
782 }
783 jpeg_finish_decompress(dinfo);
784
785 bailout:
786 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
787 if(row_pointer) free(row_pointer);
788 return retval;
789}
790
791DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
792 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
793 int height, int pixelSize, int flags)
794{
795 if(flags&TJ_YUV)
796 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
797 else
798 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
799 height, getPixelFormat(pixelSize, flags), flags);
800}
801
802
803DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
804 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
805 int flags)
806{
807 int i, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
808 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
809 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
810 JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS];
811
812 getinstance(handle);
813 if((this->init&DECOMPRESS)==0)
814 _throw("tjDecompressToYUV(): Instance has not been initialized for decompression");
815
816 for(i=0; i<MAX_COMPONENTS; i++)
817 {
818 tmpbuf[i]=NULL; outbuf[i]=NULL;
819 }
820
821 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
822 _throw("tjDecompressToYUV(): Invalid argument");
823
824 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
825 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
826 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
827
828 if(setjmp(this->jerr.setjmp_buffer))
829 {
830 /* If we get here, the JPEG code has signaled an error. */
831 retval=-1;
832 goto bailout;
833 }
834
835 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
836 jpeg_read_header(dinfo, TRUE);
837
838 for(i=0; i<dinfo->num_components; i++)
839 {
840 jpeg_component_info *compptr=&dinfo->comp_info[i];
841 int ih;
842 iw[i]=compptr->width_in_blocks*DCTSIZE;
843 ih=compptr->height_in_blocks*DCTSIZE;
844 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
845 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
846 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
847 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
848 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
849 th[i]=compptr->v_samp_factor*DCTSIZE;
850 tmpbufsize+=iw[i]*th[i];
851 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
852 _throw("tjDecompressToYUV(): Memory allocation failure");
853 for(row=0; row<ch[i]; row++)
854 {
855 outbuf[i][row]=ptr;
856 ptr+=PAD(cw[i], 4);
857 }
858 }
859 if(usetmpbuf)
860 {
861 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
862 _throw("tjDecompressToYUV(): Memory allocation failure");
863 ptr=_tmpbuf;
864 for(i=0; i<dinfo->num_components; i++)
865 {
866 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
867 _throw("tjDecompressToYUV(): Memory allocation failure");
868 for(row=0; row<th[i]; row++)
869 {
870 tmpbuf[i][row]=ptr;
871 ptr+=iw[i];
872 }
873 }
874 }
875
876 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
877 dinfo->raw_data_out=TRUE;
878
879 jpeg_start_decompress(dinfo);
880 for(row=0; row<(int)dinfo->output_height;
881 row+=dinfo->max_v_samp_factor*DCTSIZE)
882 {
883 JSAMPARRAY yuvptr[MAX_COMPONENTS];
884 int crow[MAX_COMPONENTS];
885 for(i=0; i<dinfo->num_components; i++)
886 {
887 jpeg_component_info *compptr=&dinfo->comp_info[i];
888 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
889 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
890 else yuvptr[i]=&outbuf[i][crow[i]];
891 }
892 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
893 if(usetmpbuf)
894 {
895 int j;
896 for(i=0; i<dinfo->num_components; i++)
897 {
898 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
899 {
900 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
901 }
902 }
903 }
904 }
905 jpeg_finish_decompress(dinfo);
906
907 bailout:
908 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
909 for(i=0; i<MAX_COMPONENTS; i++)
910 {
911 if(tmpbuf[i]) free(tmpbuf[i]);
912 if(outbuf[i]) free(outbuf[i]);
913 }
914 if(_tmpbuf) free(_tmpbuf);
915 return retval;
916}
917
918
919/* Transformer */
920
921DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
922{
923 tjinstance *this=NULL; tjhandle handle=NULL;
924 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
925 {
926 snprintf(errStr, JMSG_LENGTH_MAX,
927 "tjInitTransform(): Memory allocation failure");
928 return NULL;
929 }
930 MEMZERO(this, sizeof(tjinstance));
931 handle=_tjInitCompress(this);
932 if(!handle) return NULL;
933 handle=_tjInitDecompress(this);
934 return handle;
935}
936
937
938DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
939 unsigned long jpegSize, int n, unsigned char **dstBufs,
940 unsigned long *dstSizes, tjtransform *t, int flags)
941{
942 jpeg_transform_info *xinfo=NULL;
943 jvirt_barray_ptr *srccoefs, *dstcoefs;
944 int retval=0, i, jpegSubsamp;
945
946 getinstance(handle);
947 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
948 _throw("tjTransform(): Instance has not been initialized for transformation");
949
950 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
951 || t==NULL || flags<0)
952 _throw("tjTransform(): Invalid argument");
953
954 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
955 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
956 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
957
958 if(setjmp(this->jerr.setjmp_buffer))
959 {
960 /* If we get here, the JPEG code has signaled an error. */
961 retval=-1;
962 goto bailout;
963 }
964
965 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
966
967 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
968 ==NULL)
969 _throw("tjTransform(): Memory allocation failure");
970 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
971
972 for(i=0; i<n; i++)
973 {
974 xinfo[i].transform=xformtypes[t[i].op];
975 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
976 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
977 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
978 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
979 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
980 else xinfo[i].slow_hflip=0;
981
982 if(xinfo[i].crop)
983 {
984 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
985 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
986 if(t[i].r.w!=0)
987 {
988 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
989 }
990 else xinfo[i].crop_width=JCROP_UNSET;
991 if(t[i].r.h!=0)
992 {
993 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
994 }
995 else xinfo[i].crop_height=JCROP_UNSET;
996 }
997 }
998
999 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1000 jpeg_read_header(dinfo, TRUE);
1001 jpegSubsamp=getSubsamp(dinfo);
1002 if(jpegSubsamp<0)
1003 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
1004
1005 for(i=0; i<n; i++)
1006 {
1007 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
1008 _throw("tjTransform(): Transform is not perfect");
1009
1010 if(xinfo[i].crop)
1011 {
1012 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1013 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1014 {
1015 snprintf(errStr, JMSG_LENGTH_MAX,
1016 "To crop this JPEG image, x must be a multiple of %d\n"
1017 "and y must be a multiple of %d.\n",
1018 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1019 retval=-1; goto bailout;
1020 }
1021 }
1022 }
1023
1024 srccoefs=jpeg_read_coefficients(dinfo);
1025
1026 for(i=0; i<n; i++)
1027 {
1028 int w, h, alloc=1;
1029 if(!xinfo[i].crop)
1030 {
1031 w=dinfo->image_width; h=dinfo->image_height;
1032 }
1033 else
1034 {
1035 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
1036 }
1037 if(flags&TJFLAG_NOREALLOC)
1038 {
1039 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
1040 }
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001041 if(!(t[i].options&TJXOPT_NOOUTPUT))
1042 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
hbono@chromium.org98626972011-08-03 03:13:08 +00001043 jpeg_copy_critical_parameters(dinfo, cinfo);
1044 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
1045 &xinfo[i]);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001046 if(!(t[i].options&TJXOPT_NOOUTPUT))
1047 {
1048 jpeg_write_coefficients(cinfo, dstcoefs);
1049 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1050 }
1051 else jinit_c_master_control(cinfo, TRUE);
hbono@chromium.org98626972011-08-03 03:13:08 +00001052 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
1053 &xinfo[i]);
hbono@chromium.orgc6beb742011-11-29 05:16:26 +00001054 if(t[i].customFilter)
1055 {
1056 int ci, by, y;
1057 for(ci=0; ci<cinfo->num_components; ci++)
1058 {
1059 jpeg_component_info *compptr=&cinfo->comp_info[ci];
1060 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1061 DCTSIZE};
1062 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1063 compptr->height_in_blocks*DCTSIZE};
1064 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1065 {
1066 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1067 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1068 TRUE);
1069 for(y=0; y<compptr->v_samp_factor; y++)
1070 {
1071 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
1072 ci, i, &t[i])==-1)
1073 _throw("tjTransform(): Error in custom filter");
1074 arrayRegion.y+=DCTSIZE;
1075 }
1076 }
1077 }
1078 }
1079 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
hbono@chromium.org98626972011-08-03 03:13:08 +00001080 }
1081
1082 jpeg_finish_decompress(dinfo);
1083
1084 bailout:
1085 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1086 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1087 if(xinfo) free(xinfo);
1088 return retval;
1089}