DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 1 | /* Copyright (C)2004 Landmark Graphics Corporation |
| 2 | * Copyright (C)2005 Sun Microsystems, Inc. |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 3 | * Copyright (C)2009-2011 D. R. Commander |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 4 | * |
| 5 | * This library is free software and may be redistributed and/or modified under |
| 6 | * the terms of the wxWindows Library License, Version 3.1 or (at your option) |
| 7 | * any later version. The full license is in the LICENSE.txt file included |
| 8 | * with this distribution. |
| 9 | * |
| 10 | * This library is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * wxWindows Library License for more details. |
| 14 | */ |
| 15 | |
| 16 | // This implements a JPEG compressor/decompressor using the libjpeg API |
| 17 | |
| 18 | #include <stdio.h> |
| 19 | #include <stdlib.h> |
| 20 | #include <string.h> |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 21 | #define JPEG_INTERNALS |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 22 | #include <jpeglib.h> |
| 23 | #include <jerror.h> |
| 24 | #include <setjmp.h> |
| 25 | #include "./turbojpeg.h" |
DRC | 890f1e0 | 2011-02-26 22:02:37 +0000 | [diff] [blame] | 26 | #include "transupp.h" |
DRC | 2a2e451 | 2011-01-05 22:33:24 +0000 | [diff] [blame] | 27 | |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 28 | #ifndef min |
| 29 | #define min(a,b) ((a)<(b)?(a):(b)) |
| 30 | #endif |
| 31 | |
| 32 | #define PAD(v, p) ((v+(p)-1)&(~((p)-1))) |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 33 | |
| 34 | |
| 35 | // Error handling |
| 36 | |
| 37 | static char lasterror[JMSG_LENGTH_MAX]="No error"; |
| 38 | |
| 39 | typedef struct _error_mgr |
| 40 | { |
| 41 | struct jpeg_error_mgr pub; |
| 42 | jmp_buf jb; |
| 43 | } error_mgr; |
| 44 | |
| 45 | static void my_error_exit(j_common_ptr cinfo) |
| 46 | { |
| 47 | error_mgr *myerr = (error_mgr *)cinfo->err; |
| 48 | (*cinfo->err->output_message)(cinfo); |
| 49 | longjmp(myerr->jb, 1); |
| 50 | } |
| 51 | |
| 52 | static void my_output_message(j_common_ptr cinfo) |
| 53 | { |
| 54 | (*cinfo->err->format_message)(cinfo, lasterror); |
| 55 | } |
| 56 | |
| 57 | |
| 58 | // Global structures, macros, etc. |
| 59 | |
| 60 | typedef struct _jpgstruct |
| 61 | { |
| 62 | struct jpeg_compress_struct cinfo; |
| 63 | struct jpeg_decompress_struct dinfo; |
| 64 | struct jpeg_destination_mgr jdms; |
| 65 | struct jpeg_source_mgr jsms; |
| 66 | error_mgr jerr; |
| 67 | int initc, initd; |
| 68 | } jpgstruct; |
| 69 | |
| 70 | static const int hsampfactor[NUMSUBOPT]={1, 2, 2, 1}; |
| 71 | static const int vsampfactor[NUMSUBOPT]={1, 1, 2, 1}; |
DRC | 1fe80f8 | 2010-12-14 01:21:29 +0000 | [diff] [blame] | 72 | static const int pixelsize[NUMSUBOPT]={3, 3, 3, 1}; |
DRC | 890f1e0 | 2011-02-26 22:02:37 +0000 | [diff] [blame] | 73 | static const JXFORM_CODE xformtypes[NUMXFORMOPT]={ |
| 74 | JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE, |
| 75 | JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270 |
| 76 | }; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 77 | |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 78 | #define _throw(c) {sprintf(lasterror, "%s", c); retval=-1; goto bailout;} |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 79 | #define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \ |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 80 | if(!j) {sprintf(lasterror, "Invalid handle"); return -1;} |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 81 | |
| 82 | |
| 83 | // CO |
| 84 | |
| 85 | static boolean empty_output_buffer(struct jpeg_compress_struct *cinfo) |
| 86 | { |
| 87 | ERREXIT(cinfo, JERR_BUFFER_SIZE); |
| 88 | return TRUE; |
| 89 | } |
| 90 | |
| 91 | static void destination_noop(struct jpeg_compress_struct *cinfo) |
| 92 | { |
| 93 | } |
| 94 | |
DRC | 890f1e0 | 2011-02-26 22:02:37 +0000 | [diff] [blame] | 95 | static tjhandle _tjInitCompress(jpgstruct *j) |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 96 | { |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 97 | j->cinfo.err=jpeg_std_error(&j->jerr.pub); |
| 98 | j->jerr.pub.error_exit=my_error_exit; |
| 99 | j->jerr.pub.output_message=my_output_message; |
| 100 | |
| 101 | if(setjmp(j->jerr.jb)) |
| 102 | { // this will execute if LIBJPEG has an error |
| 103 | if(j) free(j); return NULL; |
DRC | efa4ddc | 2010-10-13 19:22:50 +0000 | [diff] [blame] | 104 | } |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 105 | |
| 106 | jpeg_create_compress(&j->cinfo); |
| 107 | j->cinfo.dest=&j->jdms; |
| 108 | j->jdms.init_destination=destination_noop; |
| 109 | j->jdms.empty_output_buffer=empty_output_buffer; |
| 110 | j->jdms.term_destination=destination_noop; |
| 111 | |
| 112 | j->initc=1; |
| 113 | return (tjhandle)j; |
| 114 | } |
| 115 | |
DRC | 890f1e0 | 2011-02-26 22:02:37 +0000 | [diff] [blame] | 116 | DLLEXPORT tjhandle DLLCALL tjInitCompress(void) |
| 117 | { |
| 118 | jpgstruct *j=NULL; |
| 119 | if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL) |
| 120 | {sprintf(lasterror, "Memory allocation failure"); return NULL;} |
| 121 | memset(j, 0, sizeof(jpgstruct)); |
| 122 | return _tjInitCompress(j); |
| 123 | } |
| 124 | |
DRC | 8424160 | 2011-02-25 02:08:23 +0000 | [diff] [blame] | 125 | |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 126 | DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height) |
| 127 | { |
DRC | f3cf973 | 2011-02-22 00:16:14 +0000 | [diff] [blame] | 128 | unsigned long retval=0; |
| 129 | if(width<1 || height<1) |
| 130 | _throw("Invalid argument in TJBUFSIZE()"); |
| 131 | |
| 132 | // This allows for rare corner cases in which a JPEG image can actually be |
| 133 | // larger than the uncompressed input (we wouldn't mention it if it hadn't |
DRC | b28fc57 | 2011-02-22 06:41:29 +0000 | [diff] [blame] | 134 | // happened before.) |
DRC | f3cf973 | 2011-02-22 00:16:14 +0000 | [diff] [blame] | 135 | retval=((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048; |
| 136 | |
| 137 | bailout: |
| 138 | return retval; |
| 139 | } |
| 140 | |
DRC | 8424160 | 2011-02-25 02:08:23 +0000 | [diff] [blame] | 141 | |
DRC | f3cf973 | 2011-02-22 00:16:14 +0000 | [diff] [blame] | 142 | DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height, |
| 143 | int subsamp) |
| 144 | { |
| 145 | unsigned long retval=0; |
| 146 | int pw, ph, cw, ch; |
| 147 | if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT) |
| 148 | _throw("Invalid argument in TJBUFSIZEYUV()"); |
| 149 | pw=PAD(width, hsampfactor[subsamp]); |
| 150 | ph=PAD(height, vsampfactor[subsamp]); |
| 151 | cw=pw/hsampfactor[subsamp]; ch=ph/vsampfactor[subsamp]; |
| 152 | retval=PAD(pw, 4)*ph + (subsamp==TJ_GRAYSCALE? 0:PAD(cw, 4)*ch*2); |
| 153 | |
| 154 | bailout: |
| 155 | return retval; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 156 | } |
| 157 | |
DRC | 8424160 | 2011-02-25 02:08:23 +0000 | [diff] [blame] | 158 | |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 159 | DLLEXPORT int DLLCALL tjCompress(tjhandle h, |
| 160 | unsigned char *srcbuf, int width, int pitch, int height, int ps, |
| 161 | unsigned char *dstbuf, unsigned long *size, |
| 162 | int jpegsub, int qual, int flags) |
| 163 | { |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 164 | int i, retval=0; JSAMPROW *row_pointer=NULL; |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 165 | JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS]; |
| 166 | JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS]; |
| 167 | JSAMPROW *outbuf[MAX_COMPONENTS]; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 168 | |
| 169 | checkhandle(h); |
| 170 | |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 171 | for(i=0; i<MAX_COMPONENTS; i++) |
| 172 | { |
| 173 | tmpbuf[i]=NULL; _tmpbuf[i]=NULL; |
| 174 | tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL; |
| 175 | } |
| 176 | |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 177 | if(srcbuf==NULL || width<=0 || pitch<0 || height<=0 |
| 178 | || dstbuf==NULL || size==NULL |
| 179 | || jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100) |
| 180 | _throw("Invalid argument in tjCompress()"); |
DRC | 09854f5 | 2010-11-04 22:39:59 +0000 | [diff] [blame] | 181 | if(ps!=3 && ps!=4 && ps!=1) |
| 182 | _throw("This compressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale input"); |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 183 | if(!j->initc) _throw("Instance has not been initialized for compression"); |
| 184 | |
| 185 | if(pitch==0) pitch=width*ps; |
| 186 | |
| 187 | j->cinfo.image_width = width; |
| 188 | j->cinfo.image_height = height; |
| 189 | j->cinfo.input_components = ps; |
| 190 | |
DRC | 09854f5 | 2010-11-04 22:39:59 +0000 | [diff] [blame] | 191 | if(ps==1) j->cinfo.in_color_space = JCS_GRAYSCALE; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 192 | #if JCS_EXTENSIONS==1 |
DRC | 09854f5 | 2010-11-04 22:39:59 +0000 | [diff] [blame] | 193 | else j->cinfo.in_color_space = JCS_EXT_RGB; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 194 | if(ps==3 && (flags&TJ_BGR)) |
| 195 | j->cinfo.in_color_space = JCS_EXT_BGR; |
| 196 | else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) |
| 197 | j->cinfo.in_color_space = JCS_EXT_RGBX; |
| 198 | else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) |
| 199 | j->cinfo.in_color_space = JCS_EXT_BGRX; |
| 200 | else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) |
| 201 | j->cinfo.in_color_space = JCS_EXT_XBGR; |
| 202 | else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) |
| 203 | j->cinfo.in_color_space = JCS_EXT_XRGB; |
| 204 | #else |
| 205 | #error "TurboJPEG requires JPEG colorspace extensions" |
| 206 | #endif |
| 207 | |
DRC | 0c6a271 | 2010-02-22 08:34:44 +0000 | [diff] [blame] | 208 | if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); |
| 209 | else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1"); |
| 210 | else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); |
| 211 | |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 212 | if(setjmp(j->jerr.jb)) |
| 213 | { // this will execute if LIBJPEG has an error |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 214 | retval=-1; |
| 215 | goto bailout; |
DRC | efa4ddc | 2010-10-13 19:22:50 +0000 | [diff] [blame] | 216 | } |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 217 | |
| 218 | jpeg_set_defaults(&j->cinfo); |
| 219 | |
| 220 | jpeg_set_quality(&j->cinfo, qual, TRUE); |
| 221 | if(jpegsub==TJ_GRAYSCALE) |
| 222 | jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE); |
| 223 | else |
| 224 | jpeg_set_colorspace(&j->cinfo, JCS_YCbCr); |
DRC | e1716b8 | 2011-02-18 03:19:43 +0000 | [diff] [blame] | 225 | if(qual>=96) j->cinfo.dct_method=JDCT_ISLOW; |
| 226 | else j->cinfo.dct_method=JDCT_FASTEST; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 227 | |
| 228 | j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub]; |
| 229 | j->cinfo.comp_info[1].h_samp_factor=1; |
| 230 | j->cinfo.comp_info[2].h_samp_factor=1; |
| 231 | j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub]; |
| 232 | j->cinfo.comp_info[1].v_samp_factor=1; |
| 233 | j->cinfo.comp_info[2].v_samp_factor=1; |
| 234 | |
| 235 | j->jdms.next_output_byte = dstbuf; |
| 236 | j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height); |
| 237 | |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 238 | jpeg_start_compress(&j->cinfo, TRUE); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 239 | if(flags&TJ_YUV) |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 240 | { |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 241 | j_compress_ptr cinfo=&j->cinfo; |
| 242 | int row; |
| 243 | int pw=PAD(width, cinfo->max_h_samp_factor); |
| 244 | int ph=PAD(height, cinfo->max_v_samp_factor); |
| 245 | int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS]; |
| 246 | jpeg_component_info *compptr; |
| 247 | JSAMPLE *ptr=dstbuf; unsigned long yuvsize=0; |
| 248 | |
| 249 | if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL) |
| 250 | _throw("Memory allocation failed in tjCompress()"); |
| 251 | for(i=0; i<height; i++) |
| 252 | { |
| 253 | if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch]; |
| 254 | else row_pointer[i]= &srcbuf[i*pitch]; |
| 255 | } |
| 256 | if(height<ph) |
| 257 | for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1]; |
| 258 | |
| 259 | for(i=0; i<cinfo->num_components; i++) |
| 260 | { |
| 261 | compptr=&cinfo->comp_info[i]; |
DRC | 5742307 | 2011-01-05 23:35:53 +0000 | [diff] [blame] | 262 | _tmpbuf[i]=(JSAMPLE *)malloc( |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 263 | PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE) |
DRC | 5742307 | 2011-01-05 23:35:53 +0000 | [diff] [blame] | 264 | /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 265 | if(!_tmpbuf[i]) _throw("Memory allocation failure"); |
DRC | 2a2e451 | 2011-01-05 22:33:24 +0000 | [diff] [blame] | 266 | tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 267 | if(!tmpbuf[i]) _throw("Memory allocation failure"); |
| 268 | for(row=0; row<cinfo->max_v_samp_factor; row++) |
DRC | 5742307 | 2011-01-05 23:35:53 +0000 | [diff] [blame] | 269 | { |
| 270 | unsigned char *_tmpbuf_aligned= |
| 271 | (unsigned char *)PAD((size_t)_tmpbuf[i], 16); |
| 272 | tmpbuf[i][row]=&_tmpbuf_aligned[ |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 273 | PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE) |
| 274 | /compptr->h_samp_factor, 16) * row]; |
DRC | 5742307 | 2011-01-05 23:35:53 +0000 | [diff] [blame] | 275 | } |
| 276 | _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16) |
| 277 | * compptr->v_samp_factor + 16); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 278 | if(!_tmpbuf2[i]) _throw("Memory allocation failure"); |
DRC | 2a2e451 | 2011-01-05 22:33:24 +0000 | [diff] [blame] | 279 | tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 280 | if(!tmpbuf2[i]) _throw("Memory allocation failure"); |
| 281 | for(row=0; row<compptr->v_samp_factor; row++) |
DRC | 5742307 | 2011-01-05 23:35:53 +0000 | [diff] [blame] | 282 | { |
| 283 | unsigned char *_tmpbuf2_aligned= |
| 284 | (unsigned char *)PAD((size_t)_tmpbuf2[i], 16); |
| 285 | tmpbuf2[i][row]=&_tmpbuf2_aligned[ |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 286 | PAD(compptr->width_in_blocks*DCTSIZE, 16) * row]; |
DRC | 5742307 | 2011-01-05 23:35:53 +0000 | [diff] [blame] | 287 | } |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 288 | cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor; |
| 289 | ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor; |
DRC | 2a2e451 | 2011-01-05 22:33:24 +0000 | [diff] [blame] | 290 | outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 291 | if(!outbuf[i]) _throw("Memory allocation failure"); |
| 292 | for(row=0; row<ch[i]; row++) |
| 293 | { |
| 294 | outbuf[i][row]=ptr; |
| 295 | ptr+=PAD(cw[i], 4); |
| 296 | } |
| 297 | } |
| 298 | yuvsize=(unsigned long)(ptr-dstbuf); |
| 299 | |
| 300 | for(row=0; row<ph; row+=cinfo->max_v_samp_factor) |
| 301 | { |
| 302 | (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, |
| 303 | 0, cinfo->max_v_samp_factor); |
| 304 | (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0); |
| 305 | for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; |
| 306 | i++, compptr++) |
| 307 | jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i], |
| 308 | row*compptr->v_samp_factor/cinfo->max_v_samp_factor, |
| 309 | compptr->v_samp_factor, cw[i]); |
| 310 | } |
| 311 | *size=yuvsize; |
| 312 | cinfo->next_scanline+=height; |
DRC | 6ee5459 | 2011-03-01 08:18:30 +0000 | [diff] [blame] | 313 | jpeg_abort_compress(&j->cinfo); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 314 | } |
| 315 | else |
| 316 | { |
| 317 | if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL) |
| 318 | _throw("Memory allocation failed in tjCompress()"); |
| 319 | for(i=0; i<height; i++) |
| 320 | { |
| 321 | if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch]; |
| 322 | else row_pointer[i]= &srcbuf[i*pitch]; |
| 323 | } |
| 324 | while(j->cinfo.next_scanline<j->cinfo.image_height) |
| 325 | { |
| 326 | jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline], |
| 327 | j->cinfo.image_height-j->cinfo.next_scanline); |
| 328 | } |
DRC | 6ee5459 | 2011-03-01 08:18:30 +0000 | [diff] [blame] | 329 | jpeg_finish_compress(&j->cinfo); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 330 | *size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height) |
| 331 | -(unsigned long)(j->jdms.free_in_buffer); |
DRC | 6ee5459 | 2011-03-01 08:18:30 +0000 | [diff] [blame] | 332 | } |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 333 | |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 334 | bailout: |
DRC | b28fc57 | 2011-02-22 06:41:29 +0000 | [diff] [blame] | 335 | if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo); |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 336 | if(row_pointer) free(row_pointer); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 337 | for(i=0; i<MAX_COMPONENTS; i++) |
| 338 | { |
| 339 | if(tmpbuf[i]!=NULL) free(tmpbuf[i]); |
DRC | 5742307 | 2011-01-05 23:35:53 +0000 | [diff] [blame] | 340 | if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 341 | if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]); |
DRC | 5742307 | 2011-01-05 23:35:53 +0000 | [diff] [blame] | 342 | if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]); |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 343 | if(outbuf[i]!=NULL) free(outbuf[i]); |
| 344 | } |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 345 | return retval; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 346 | } |
| 347 | |
| 348 | |
DRC | 8424160 | 2011-02-25 02:08:23 +0000 | [diff] [blame] | 349 | DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle h, |
| 350 | unsigned char *srcbuf, int width, int pitch, int height, int ps, |
| 351 | unsigned char *dstbuf, int subsamp, int flags) |
| 352 | { |
| 353 | unsigned long size; |
| 354 | return tjCompress(h, srcbuf, width, pitch, height, ps, dstbuf, &size, |
| 355 | subsamp, 0, flags|TJ_YUV); |
| 356 | } |
| 357 | |
| 358 | |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 359 | // DEC |
| 360 | |
| 361 | static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo) |
| 362 | { |
| 363 | ERREXIT(dinfo, JERR_BUFFER_SIZE); |
| 364 | return TRUE; |
| 365 | } |
| 366 | |
| 367 | static void skip_input_data (struct jpeg_decompress_struct *dinfo, long num_bytes) |
| 368 | { |
| 369 | dinfo->src->next_input_byte += (size_t) num_bytes; |
| 370 | dinfo->src->bytes_in_buffer -= (size_t) num_bytes; |
| 371 | } |
| 372 | |
| 373 | static void source_noop (struct jpeg_decompress_struct *dinfo) |
| 374 | { |
| 375 | } |
| 376 | |
DRC | 890f1e0 | 2011-02-26 22:02:37 +0000 | [diff] [blame] | 377 | static tjhandle _tjInitDecompress(jpgstruct *j) |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 378 | { |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 379 | j->dinfo.err=jpeg_std_error(&j->jerr.pub); |
| 380 | j->jerr.pub.error_exit=my_error_exit; |
| 381 | j->jerr.pub.output_message=my_output_message; |
| 382 | |
| 383 | if(setjmp(j->jerr.jb)) |
| 384 | { // this will execute if LIBJPEG has an error |
| 385 | free(j); return NULL; |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 386 | } |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 387 | |
| 388 | jpeg_create_decompress(&j->dinfo); |
| 389 | j->dinfo.src=&j->jsms; |
| 390 | j->jsms.init_source=source_noop; |
| 391 | j->jsms.fill_input_buffer = fill_input_buffer; |
| 392 | j->jsms.skip_input_data = skip_input_data; |
| 393 | j->jsms.resync_to_restart = jpeg_resync_to_restart; |
| 394 | j->jsms.term_source = source_noop; |
| 395 | |
| 396 | j->initd=1; |
| 397 | return (tjhandle)j; |
| 398 | } |
| 399 | |
DRC | 890f1e0 | 2011-02-26 22:02:37 +0000 | [diff] [blame] | 400 | DLLEXPORT tjhandle DLLCALL tjInitDecompress(void) |
| 401 | { |
| 402 | jpgstruct *j; |
| 403 | if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL) |
| 404 | {sprintf(lasterror, "Memory allocation failure"); return NULL;} |
| 405 | memset(j, 0, sizeof(jpgstruct)); |
| 406 | return _tjInitDecompress(j); |
| 407 | } |
| 408 | |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 409 | |
DRC | 1fe80f8 | 2010-12-14 01:21:29 +0000 | [diff] [blame] | 410 | DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle h, |
| 411 | unsigned char *srcbuf, unsigned long size, |
| 412 | int *width, int *height, int *jpegsub) |
| 413 | { |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 414 | int i, k, retval=0; |
DRC | 1fe80f8 | 2010-12-14 01:21:29 +0000 | [diff] [blame] | 415 | |
| 416 | checkhandle(h); |
| 417 | |
| 418 | if(srcbuf==NULL || size<=0 || width==NULL || height==NULL || jpegsub==NULL) |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 419 | _throw("Invalid argument in tjDecompressHeader2()"); |
DRC | 1fe80f8 | 2010-12-14 01:21:29 +0000 | [diff] [blame] | 420 | if(!j->initd) _throw("Instance has not been initialized for decompression"); |
| 421 | |
| 422 | if(setjmp(j->jerr.jb)) |
| 423 | { // this will execute if LIBJPEG has an error |
| 424 | return -1; |
| 425 | } |
| 426 | |
| 427 | j->jsms.bytes_in_buffer = size; |
| 428 | j->jsms.next_input_byte = srcbuf; |
| 429 | |
| 430 | jpeg_read_header(&j->dinfo, TRUE); |
| 431 | |
| 432 | *width=j->dinfo.image_width; *height=j->dinfo.image_height; |
| 433 | *jpegsub=-1; |
| 434 | for(i=0; i<NUMSUBOPT; i++) |
| 435 | { |
| 436 | if(j->dinfo.num_components==pixelsize[i]) |
| 437 | { |
| 438 | if(j->dinfo.comp_info[0].h_samp_factor==hsampfactor[i] |
| 439 | && j->dinfo.comp_info[0].v_samp_factor==vsampfactor[i]) |
| 440 | { |
| 441 | int match=0; |
| 442 | for(k=1; k<j->dinfo.num_components; k++) |
| 443 | { |
| 444 | if(j->dinfo.comp_info[k].h_samp_factor==1 |
| 445 | && j->dinfo.comp_info[k].v_samp_factor==1) |
| 446 | match++; |
| 447 | } |
| 448 | if(match==j->dinfo.num_components-1) |
| 449 | { |
| 450 | *jpegsub=i; break; |
| 451 | } |
| 452 | } |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | jpeg_abort_decompress(&j->dinfo); |
| 457 | |
| 458 | if(*jpegsub<0) _throw("Could not determine subsampling type for JPEG image"); |
| 459 | if(*width<1 || *height<1) _throw("Invalid data returned in header"); |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 460 | |
| 461 | bailout: |
| 462 | return retval; |
| 463 | } |
| 464 | |
| 465 | |
| 466 | DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h, |
| 467 | unsigned char *srcbuf, unsigned long size, |
| 468 | int *width, int *height) |
| 469 | { |
| 470 | int jpegsub; |
| 471 | return tjDecompressHeader2(h, srcbuf, size, width, height, &jpegsub); |
DRC | 1fe80f8 | 2010-12-14 01:21:29 +0000 | [diff] [blame] | 472 | } |
| 473 | |
| 474 | |
DRC | 1b1e886 | 2011-02-26 19:53:58 +0000 | [diff] [blame] | 475 | DLLEXPORT int DLLCALL tjGetScaledSize(int input_width, int input_height, |
DRC | b28fc57 | 2011-02-22 06:41:29 +0000 | [diff] [blame] | 476 | int *output_width, int *output_height) |
| 477 | { |
| 478 | int i, retval=0, scaledw=0, scaledh=0; |
| 479 | |
| 480 | if(input_width<1 || input_height<1 || output_width==NULL |
| 481 | || output_height==NULL || *output_width<0 || *output_height<0) |
DRC | 1b1e886 | 2011-02-26 19:53:58 +0000 | [diff] [blame] | 482 | _throw("Invalid argument in tjGetScaledSize()"); |
DRC | b28fc57 | 2011-02-22 06:41:29 +0000 | [diff] [blame] | 483 | |
| 484 | if(*output_width==0) *output_width=input_width; |
| 485 | if(*output_height==0) *output_height=input_height; |
| 486 | if(*output_width<input_width || *output_height<input_height) |
| 487 | { |
| 488 | for(i=1; i<=8; i*=2) |
| 489 | { |
| 490 | scaledw=(input_width+i-1)/i; |
| 491 | scaledh=(input_height+i-1)/i; |
| 492 | if(scaledw<=*output_width && scaledh<=*output_height) |
| 493 | break; |
| 494 | } |
| 495 | *output_width=scaledw; *output_height=scaledh; |
| 496 | } |
| 497 | |
| 498 | bailout: |
| 499 | return retval; |
| 500 | } |
| 501 | |
| 502 | |
| 503 | DLLEXPORT int DLLCALL tjDecompress(tjhandle h, |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 504 | unsigned char *srcbuf, unsigned long size, |
DRC | b28fc57 | 2011-02-22 06:41:29 +0000 | [diff] [blame] | 505 | unsigned char *dstbuf, int width, int pitch, int height, int ps, |
| 506 | int flags) |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 507 | { |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 508 | int i, row, retval=0; JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS]; |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 509 | int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS], |
| 510 | tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS]; |
| 511 | JSAMPLE *_tmpbuf=NULL; JSAMPROW *tmpbuf[MAX_COMPONENTS]; |
DRC | b28fc57 | 2011-02-22 06:41:29 +0000 | [diff] [blame] | 512 | int scale_num=1, scale_denom=1, jpegwidth, jpegheight, scaledw, scaledh; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 513 | |
| 514 | checkhandle(h); |
| 515 | |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 516 | for(i=0; i<MAX_COMPONENTS; i++) |
| 517 | { |
| 518 | tmpbuf[i]=NULL; outbuf[i]=NULL; |
| 519 | } |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 520 | |
DRC | b28fc57 | 2011-02-22 06:41:29 +0000 | [diff] [blame] | 521 | if(srcbuf==NULL || size<=0 |
| 522 | || dstbuf==NULL || width<0 || pitch<0 || height<0) |
| 523 | _throw("Invalid argument in tjDecompress()"); |
DRC | 09854f5 | 2010-11-04 22:39:59 +0000 | [diff] [blame] | 524 | if(ps!=3 && ps!=4 && ps!=1) |
| 525 | _throw("This decompressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale output"); |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 526 | if(!j->initd) _throw("Instance has not been initialized for decompression"); |
| 527 | |
DRC | 0c6a271 | 2010-02-22 08:34:44 +0000 | [diff] [blame] | 528 | if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); |
| 529 | else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1"); |
| 530 | else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); |
| 531 | |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 532 | if(setjmp(j->jerr.jb)) |
| 533 | { // this will execute if LIBJPEG has an error |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 534 | retval=-1; |
| 535 | goto bailout; |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 536 | } |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 537 | |
| 538 | j->jsms.bytes_in_buffer = size; |
| 539 | j->jsms.next_input_byte = srcbuf; |
| 540 | |
| 541 | jpeg_read_header(&j->dinfo, TRUE); |
| 542 | |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 543 | if(flags&TJ_YUV) |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 544 | { |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 545 | j_decompress_ptr dinfo=&j->dinfo; |
| 546 | JSAMPLE *ptr=dstbuf; |
| 547 | |
| 548 | for(i=0; i<dinfo->num_components; i++) |
| 549 | { |
| 550 | jpeg_component_info *compptr=&dinfo->comp_info[i]; |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 551 | int ih; |
| 552 | iw[i]=compptr->width_in_blocks*DCTSIZE; |
| 553 | ih=compptr->height_in_blocks*DCTSIZE; |
DRC | 8ed7b81 | 2011-02-15 08:31:34 +0000 | [diff] [blame] | 554 | cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor) |
| 555 | *compptr->h_samp_factor/dinfo->max_h_samp_factor; |
| 556 | ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor) |
| 557 | *compptr->v_samp_factor/dinfo->max_v_samp_factor; |
DRC | a6f4fca | 2010-12-11 06:01:11 +0000 | [diff] [blame] | 558 | if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1; |
| 559 | th[i]=compptr->v_samp_factor*DCTSIZE; |
| 560 | tmpbufsize+=iw[i]*th[i]; |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 561 | if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL) |
DRC | 8424160 | 2011-02-25 02:08:23 +0000 | [diff] [blame] | 562 | _throw("Memory allocation failed in tjDecompress()"); |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 563 | for(row=0; row<ch[i]; row++) |
| 564 | { |
| 565 | outbuf[i][row]=ptr; |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 566 | ptr+=PAD(cw[i], 4); |
| 567 | } |
| 568 | } |
| 569 | if(usetmpbuf) |
| 570 | { |
| 571 | if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL) |
DRC | 8424160 | 2011-02-25 02:08:23 +0000 | [diff] [blame] | 572 | _throw("Memory allocation failed in tjDecompress()"); |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 573 | ptr=_tmpbuf; |
| 574 | for(i=0; i<dinfo->num_components; i++) |
| 575 | { |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 576 | if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL) |
DRC | 8424160 | 2011-02-25 02:08:23 +0000 | [diff] [blame] | 577 | _throw("Memory allocation failed in tjDecompress()"); |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 578 | for(row=0; row<th[i]; row++) |
| 579 | { |
| 580 | tmpbuf[i][row]=ptr; |
| 581 | ptr+=iw[i]; |
| 582 | } |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 583 | } |
| 584 | } |
| 585 | } |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 586 | |
DRC | 09854f5 | 2010-11-04 22:39:59 +0000 | [diff] [blame] | 587 | if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 588 | #if JCS_EXTENSIONS==1 |
DRC | 09854f5 | 2010-11-04 22:39:59 +0000 | [diff] [blame] | 589 | else j->dinfo.out_color_space = JCS_EXT_RGB; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 590 | if(ps==3 && (flags&TJ_BGR)) |
| 591 | j->dinfo.out_color_space = JCS_EXT_BGR; |
| 592 | else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) |
| 593 | j->dinfo.out_color_space = JCS_EXT_RGBX; |
| 594 | else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) |
| 595 | j->dinfo.out_color_space = JCS_EXT_BGRX; |
| 596 | else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) |
| 597 | j->dinfo.out_color_space = JCS_EXT_XBGR; |
| 598 | else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) |
| 599 | j->dinfo.out_color_space = JCS_EXT_XRGB; |
| 600 | #else |
| 601 | #error "TurboJPEG requires JPEG colorspace extensions" |
| 602 | #endif |
DRC | fbb6747 | 2010-11-24 04:02:37 +0000 | [diff] [blame] | 603 | |
DRC | 61e51f9 | 2009-04-05 21:53:20 +0000 | [diff] [blame] | 604 | if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE; |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 605 | if(flags&TJ_YUV) j->dinfo.raw_data_out=TRUE; |
DRC | 8ed7b81 | 2011-02-15 08:31:34 +0000 | [diff] [blame] | 606 | else |
| 607 | { |
DRC | 8424160 | 2011-02-25 02:08:23 +0000 | [diff] [blame] | 608 | jpegwidth=j->dinfo.image_width; jpegheight=j->dinfo.image_height; |
| 609 | if(width==0) width=jpegwidth; |
| 610 | if(height==0) height=jpegheight; |
| 611 | if(width<jpegwidth || height<jpegheight) |
| 612 | { |
| 613 | for(i=1; i<=8; i*=2) |
| 614 | { |
| 615 | scaledw=(jpegwidth+i-1)/i; |
| 616 | scaledh=(jpegheight+i-1)/i; |
| 617 | if(scaledw<=width && scaledh<=height) |
| 618 | break; |
| 619 | } |
| 620 | if(scaledw>width || scaledh>height) |
| 621 | _throw("Could not scale down to desired image dimensions"); |
| 622 | width=scaledw; height=scaledh; |
| 623 | scale_denom=i; |
| 624 | } |
DRC | 8ed7b81 | 2011-02-15 08:31:34 +0000 | [diff] [blame] | 625 | j->dinfo.scale_num=scale_num; |
| 626 | j->dinfo.scale_denom=scale_denom; |
| 627 | } |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 628 | |
| 629 | jpeg_start_decompress(&j->dinfo); |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 630 | if(flags&TJ_YUV) |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 631 | { |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 632 | j_decompress_ptr dinfo=&j->dinfo; |
| 633 | for(row=0; row<dinfo->output_height; |
| 634 | row+=dinfo->max_v_samp_factor*DCTSIZE) |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 635 | { |
| 636 | JSAMPARRAY yuvptr[MAX_COMPONENTS]; |
DRC | a6f4fca | 2010-12-11 06:01:11 +0000 | [diff] [blame] | 637 | int crow[MAX_COMPONENTS]; |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 638 | for(i=0; i<dinfo->num_components; i++) |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 639 | { |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 640 | jpeg_component_info *compptr=&dinfo->comp_info[i]; |
DRC | a6f4fca | 2010-12-11 06:01:11 +0000 | [diff] [blame] | 641 | crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor; |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 642 | if(usetmpbuf) yuvptr[i]=tmpbuf[i]; |
DRC | a6f4fca | 2010-12-11 06:01:11 +0000 | [diff] [blame] | 643 | else yuvptr[i]=&outbuf[i][crow[i]]; |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 644 | } |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 645 | jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE); |
| 646 | if(usetmpbuf) |
| 647 | { |
| 648 | int j; |
| 649 | for(i=0; i<dinfo->num_components; i++) |
| 650 | { |
DRC | a6f4fca | 2010-12-11 06:01:11 +0000 | [diff] [blame] | 651 | for(j=0; j<min(th[i], ch[i]-crow[i]); j++) |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 652 | { |
DRC | a6f4fca | 2010-12-11 06:01:11 +0000 | [diff] [blame] | 653 | memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]); |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 654 | } |
| 655 | } |
| 656 | } |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 657 | } |
| 658 | } |
| 659 | else |
| 660 | { |
DRC | 8ed7b81 | 2011-02-15 08:31:34 +0000 | [diff] [blame] | 661 | if(pitch==0) pitch=j->dinfo.output_width*ps; |
| 662 | if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW) |
| 663 | *j->dinfo.output_height))==NULL) |
DRC | 8ed7b81 | 2011-02-15 08:31:34 +0000 | [diff] [blame] | 664 | _throw("Memory allocation failed in tjInitDecompress()"); |
DRC | 8ed7b81 | 2011-02-15 08:31:34 +0000 | [diff] [blame] | 665 | for(i=0; i<j->dinfo.output_height; i++) |
| 666 | { |
| 667 | if(flags&TJ_BOTTOMUP) |
| 668 | row_pointer[i]= &dstbuf[(j->dinfo.output_height-i-1)*pitch]; |
| 669 | else row_pointer[i]= &dstbuf[i*pitch]; |
| 670 | } |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 671 | while(j->dinfo.output_scanline<j->dinfo.output_height) |
| 672 | { |
| 673 | jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline], |
| 674 | j->dinfo.output_height-j->dinfo.output_scanline); |
| 675 | } |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 676 | } |
| 677 | jpeg_finish_decompress(&j->dinfo); |
| 678 | |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 679 | bailout: |
DRC | b28fc57 | 2011-02-22 06:41:29 +0000 | [diff] [blame] | 680 | if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo); |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 681 | for(i=0; i<MAX_COMPONENTS; i++) |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 682 | { |
| 683 | if(tmpbuf[i]) free(tmpbuf[i]); |
DRC | 9e17f7d | 2010-12-10 04:59:13 +0000 | [diff] [blame] | 684 | if(outbuf[i]) free(outbuf[i]); |
DRC | f9cf5c7 | 2010-12-10 10:58:49 +0000 | [diff] [blame] | 685 | } |
| 686 | if(_tmpbuf) free(_tmpbuf); |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 687 | if(row_pointer) free(row_pointer); |
DRC | 91e86ba | 2011-02-15 05:24:08 +0000 | [diff] [blame] | 688 | return retval; |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 689 | } |
| 690 | |
| 691 | |
DRC | 8424160 | 2011-02-25 02:08:23 +0000 | [diff] [blame] | 692 | DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle h, |
| 693 | unsigned char *srcbuf, unsigned long size, |
| 694 | unsigned char *dstbuf, int flags) |
| 695 | { |
| 696 | return tjDecompress(h, srcbuf, size, dstbuf, 1, 0, 1, 3, flags|TJ_YUV); |
| 697 | } |
| 698 | |
| 699 | |
DRC | 890f1e0 | 2011-02-26 22:02:37 +0000 | [diff] [blame] | 700 | // Transformation |
| 701 | |
| 702 | DLLEXPORT tjhandle DLLCALL tjInitTransform(void) |
| 703 | { |
| 704 | jpgstruct *j=NULL; tjhandle tj=NULL; |
| 705 | if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL) |
| 706 | {sprintf(lasterror, "Memory allocation failure"); return NULL;} |
| 707 | memset(j, 0, sizeof(jpgstruct)); |
| 708 | tj=_tjInitCompress(j); |
| 709 | if(!tj) return NULL; |
| 710 | tj=_tjInitDecompress(j); |
| 711 | return tj; |
| 712 | } |
| 713 | |
| 714 | |
| 715 | DLLEXPORT int DLLCALL tjTransform(tjhandle hnd, |
| 716 | unsigned char *srcbuf, unsigned long srcsize, |
| 717 | unsigned char *dstbuf, unsigned long *dstsize, |
| 718 | int x, int y, int w, int h, int op, int options, int flags) |
| 719 | { |
| 720 | jpeg_transform_info xinfo; |
| 721 | jvirt_barray_ptr *srccoefs, *dstcoefs; |
| 722 | int retval=0; |
| 723 | |
| 724 | checkhandle(hnd); |
| 725 | |
| 726 | if(srcbuf==NULL || srcsize<=0 || dstbuf==NULL || dstsize==NULL |
| 727 | || x<0 || y<0 || w<0 || h<0 || op<0 || op>=NUMXFORMOPT |
| 728 | || flags<0) |
| 729 | _throw("Invalid argument in tjTransform()"); |
| 730 | if(!j->initc || !j->initd) |
| 731 | _throw("Instance has not been initialized for transformation"); |
| 732 | |
| 733 | if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); |
| 734 | else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1"); |
| 735 | else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); |
| 736 | |
| 737 | if(setjmp(j->jerr.jb)) |
| 738 | { // this will execute if LIBJPEG has an error |
| 739 | retval=-1; |
| 740 | goto bailout; |
| 741 | } |
| 742 | |
| 743 | j->jsms.bytes_in_buffer=srcsize; |
| 744 | j->jsms.next_input_byte=srcbuf; |
| 745 | |
| 746 | xinfo.transform=xformtypes[op]; |
| 747 | xinfo.perfect=(options&TJXFORM_PERFECT)? 1:0; |
| 748 | xinfo.trim=(options&TJXFORM_TRIM)? 1:0; |
| 749 | xinfo.force_grayscale=(options&TJXFORM_GRAY)? 1:0; |
| 750 | xinfo.crop=(options&TJXFORM_CROP)? 1:0; |
| 751 | |
| 752 | if(xinfo.crop) |
| 753 | { |
| 754 | xinfo.crop_xoffset=x; xinfo.crop_xoffset_set=JCROP_POS; |
| 755 | xinfo.crop_yoffset=y; xinfo.crop_yoffset_set=JCROP_POS; |
| 756 | if(w!=0) |
| 757 | { |
| 758 | xinfo.crop_width=w; xinfo.crop_width_set=JCROP_POS; |
| 759 | } |
| 760 | if(h!=0) |
| 761 | { |
| 762 | xinfo.crop_height=h; xinfo.crop_height_set=JCROP_POS; |
| 763 | } |
| 764 | } |
| 765 | |
| 766 | jcopy_markers_setup(&j->dinfo, JCOPYOPT_NONE); |
| 767 | jpeg_read_header(&j->dinfo, TRUE); |
| 768 | |
| 769 | if(!jtransform_request_workspace(&j->dinfo, &xinfo)) |
| 770 | _throw("Transform is not perfect"); |
| 771 | |
| 772 | if(!xinfo.crop) |
| 773 | { |
| 774 | w=j->dinfo.image_width; h=j->dinfo.image_height; |
| 775 | } |
| 776 | else |
| 777 | { |
| 778 | w=xinfo.crop_width; h=xinfo.crop_height; |
| 779 | } |
| 780 | |
| 781 | j->jdms.next_output_byte=dstbuf; |
| 782 | j->jdms.free_in_buffer=TJBUFSIZE(w, h); |
| 783 | |
| 784 | if(xinfo.crop) |
| 785 | { |
| 786 | if((x%xinfo.iMCU_sample_width)!=0 || (y%xinfo.iMCU_sample_height)!=0) |
| 787 | { |
| 788 | sprintf(lasterror, "To crop this JPEG image, x must be a multiple of %d and y must be a multiple\n" |
| 789 | "of %d.\n", xinfo.iMCU_sample_width, xinfo.iMCU_sample_height); |
| 790 | retval=-1; goto bailout; |
| 791 | } |
| 792 | } |
| 793 | |
| 794 | srccoefs=jpeg_read_coefficients(&j->dinfo); |
| 795 | jpeg_copy_critical_parameters(&j->dinfo, &j->cinfo); |
| 796 | dstcoefs=jtransform_adjust_parameters(&j->dinfo, &j->cinfo, srccoefs, |
| 797 | &xinfo); |
| 798 | jpeg_write_coefficients(&j->cinfo, dstcoefs); |
| 799 | jcopy_markers_execute(&j->dinfo, &j->cinfo, JCOPYOPT_ALL); |
| 800 | jtransform_execute_transformation(&j->dinfo, &j->cinfo, srccoefs, &xinfo); |
| 801 | |
| 802 | jpeg_finish_compress(&j->cinfo); |
| 803 | jpeg_finish_decompress(&j->dinfo); |
| 804 | |
| 805 | *dstsize=TJBUFSIZE(w, h)-(unsigned long)(j->jdms.free_in_buffer); |
| 806 | |
| 807 | bailout: |
| 808 | if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo); |
| 809 | if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo); |
| 810 | return retval; |
| 811 | } |
| 812 | |
| 813 | |
DRC | 2e7b76b | 2009-04-03 12:04:24 +0000 | [diff] [blame] | 814 | // General |
| 815 | |
| 816 | DLLEXPORT char* DLLCALL tjGetErrorStr(void) |
| 817 | { |
| 818 | return lasterror; |
| 819 | } |
| 820 | |
| 821 | DLLEXPORT int DLLCALL tjDestroy(tjhandle h) |
| 822 | { |
| 823 | checkhandle(h); |
| 824 | if(setjmp(j->jerr.jb)) return -1; |
| 825 | if(j->initc) jpeg_destroy_compress(&j->cinfo); |
| 826 | if(j->initd) jpeg_destroy_decompress(&j->dinfo); |
| 827 | free(j); |
| 828 | return 0; |
| 829 | } |