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