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