blob: 06cca66552a86eb3f4c44b2529c3ae2e4369ef78 [file] [log] [blame]
DRC9b28def2011-05-21 14:37:15 +00001/*
DRC38c99702014-02-11 09:45:18 +00002 * Copyright (C)2009-2014 D. R. Commander. All Rights Reserved.
DRC2e7b76b2009-04-03 12:04:24 +00003 *
DRC9b28def2011-05-21 14:37:15 +00004 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
DRC2e7b76b2009-04-03 12:04:24 +00006 *
DRC9b28def2011-05-21 14:37:15 +00007 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of the libjpeg-turbo Project nor the names of its
13 * contributors may be used to endorse or promote products derived from this
14 * software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
DRC2e7b76b2009-04-03 12:04:24 +000027 */
28
DRCbdfcb742013-01-22 13:56:34 +000029/* TurboJPEG/LJT: this implements the TurboJPEG API using libjpeg or
30 libjpeg-turbo */
DRC2e7b76b2009-04-03 12:04:24 +000031
32#include <stdio.h>
33#include <stdlib.h>
DRC0713c1b2014-08-22 13:43:33 +000034#include <ctype.h>
DRC296c71b2011-05-25 04:12:52 +000035#include <jinclude.h>
DRCfbb67472010-11-24 04:02:37 +000036#define JPEG_INTERNALS
DRC2e7b76b2009-04-03 12:04:24 +000037#include <jpeglib.h>
38#include <jerror.h>
39#include <setjmp.h>
40#include "./turbojpeg.h"
DRCa29294a2011-05-24 09:17:57 +000041#include "./tjutil.h"
DRC890f1e02011-02-26 22:02:37 +000042#include "transupp.h"
DRC418fe282013-05-07 21:17:35 +000043#include "./jpegcomp.h"
DRC2a2e4512011-01-05 22:33:24 +000044
DRC9b28def2011-05-21 14:37:15 +000045extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
46 unsigned long *, boolean);
47extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
48
DRCfbb67472010-11-24 04:02:37 +000049#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
DRCf610d612013-04-26 10:33:29 +000050#define isPow2(x) (((x)&(x-1))==0)
DRC2e7b76b2009-04-03 12:04:24 +000051
52
DRC9b28def2011-05-21 14:37:15 +000053/* Error handling (based on example in example.c) */
DRC2e7b76b2009-04-03 12:04:24 +000054
DRC9b28def2011-05-21 14:37:15 +000055static char errStr[JMSG_LENGTH_MAX]="No error";
DRC2e7b76b2009-04-03 12:04:24 +000056
DRC9b28def2011-05-21 14:37:15 +000057struct my_error_mgr
DRC2e7b76b2009-04-03 12:04:24 +000058{
59 struct jpeg_error_mgr pub;
DRC9b28def2011-05-21 14:37:15 +000060 jmp_buf setjmp_buffer;
61};
62typedef struct my_error_mgr *my_error_ptr;
DRC2e7b76b2009-04-03 12:04:24 +000063
64static void my_error_exit(j_common_ptr cinfo)
65{
DRC9b28def2011-05-21 14:37:15 +000066 my_error_ptr myerr=(my_error_ptr)cinfo->err;
DRC2e7b76b2009-04-03 12:04:24 +000067 (*cinfo->err->output_message)(cinfo);
DRC9b28def2011-05-21 14:37:15 +000068 longjmp(myerr->setjmp_buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +000069}
70
DRC9b28def2011-05-21 14:37:15 +000071/* Based on output_message() in jerror.c */
72
DRC2e7b76b2009-04-03 12:04:24 +000073static void my_output_message(j_common_ptr cinfo)
74{
DRC9b28def2011-05-21 14:37:15 +000075 (*cinfo->err->format_message)(cinfo, errStr);
DRC2e7b76b2009-04-03 12:04:24 +000076}
77
78
DRC9b28def2011-05-21 14:37:15 +000079/* Global structures, macros, etc. */
DRC2e7b76b2009-04-03 12:04:24 +000080
DRC9b28def2011-05-21 14:37:15 +000081enum {COMPRESS=1, DECOMPRESS=2};
82
83typedef struct _tjinstance
DRC2e7b76b2009-04-03 12:04:24 +000084{
85 struct jpeg_compress_struct cinfo;
86 struct jpeg_decompress_struct dinfo;
DRC9b28def2011-05-21 14:37:15 +000087 struct my_error_mgr jerr;
DRCaecea382014-08-11 18:05:41 +000088 int init, headerRead;
DRC9b28def2011-05-21 14:37:15 +000089} tjinstance;
DRC2e7b76b2009-04-03 12:04:24 +000090
DRC1f3635c2013-08-18 10:19:00 +000091static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};
DRC9b28def2011-05-21 14:37:15 +000092
DRC007a42c2011-05-22 13:55:56 +000093static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
94{
DRC890f1e02011-02-26 22:02:37 +000095 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
96 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
97};
DRC9b28def2011-05-21 14:37:15 +000098
DRCab2df6e2012-01-28 06:49:56 +000099#define NUMSF 16
DRC109a5782011-03-01 09:53:07 +0000100static const tjscalingfactor sf[NUMSF]={
DRCab2df6e2012-01-28 06:49:56 +0000101 {2, 1},
102 {15, 8},
103 {7, 4},
104 {13, 8},
105 {3, 2},
106 {11, 8},
107 {5, 4},
108 {9, 8},
DRC109a5782011-03-01 09:53:07 +0000109 {1, 1},
DRCab2df6e2012-01-28 06:49:56 +0000110 {7, 8},
111 {3, 4},
112 {5, 8},
DRC109a5782011-03-01 09:53:07 +0000113 {1, 2},
DRCab2df6e2012-01-28 06:49:56 +0000114 {3, 8},
DRC109a5782011-03-01 09:53:07 +0000115 {1, 4},
116 {1, 8}
117};
DRC2e7b76b2009-04-03 12:04:24 +0000118
DRCa29294a2011-05-24 09:17:57 +0000119#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
DRCda5220a2011-03-02 02:17:30 +0000120 retval=-1; goto bailout;}
DRC9b28def2011-05-21 14:37:15 +0000121#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
122 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
123 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
124 return -1;} \
125 cinfo=&this->cinfo; dinfo=&this->dinfo;
DRC41861622014-04-16 23:38:37 +0000126#define getcinstance(handle) tjinstance *this=(tjinstance *)handle; \
127 j_compress_ptr cinfo=NULL; \
128 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
129 return -1;} \
130 cinfo=&this->cinfo;
131#define getdinstance(handle) tjinstance *this=(tjinstance *)handle; \
132 j_decompress_ptr dinfo=NULL; \
133 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
134 return -1;} \
135 dinfo=&this->dinfo;
DRC2e7b76b2009-04-03 12:04:24 +0000136
DRC9b28def2011-05-21 14:37:15 +0000137static int getPixelFormat(int pixelSize, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000138{
DRC25b995a2011-05-21 15:34:54 +0000139 if(pixelSize==1) return TJPF_GRAY;
DRC9b28def2011-05-21 14:37:15 +0000140 if(pixelSize==3)
141 {
DRC25b995a2011-05-21 15:34:54 +0000142 if(flags&TJ_BGR) return TJPF_BGR;
143 else return TJPF_RGB;
DRC9b28def2011-05-21 14:37:15 +0000144 }
145 if(pixelSize==4)
146 {
147 if(flags&TJ_ALPHAFIRST)
148 {
DRC25b995a2011-05-21 15:34:54 +0000149 if(flags&TJ_BGR) return TJPF_XBGR;
150 else return TJPF_XRGB;
DRC9b28def2011-05-21 14:37:15 +0000151 }
152 else
153 {
DRC25b995a2011-05-21 15:34:54 +0000154 if(flags&TJ_BGR) return TJPF_BGRX;
155 else return TJPF_RGBX;
DRC9b28def2011-05-21 14:37:15 +0000156 }
157 }
158 return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000159}
160
DRCf12bb302011-09-07 05:03:18 +0000161static int setCompDefaults(struct jpeg_compress_struct *cinfo,
DRC73d74c12012-06-29 23:46:38 +0000162 int pixelFormat, int subsamp, int jpegQual, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000163{
DRCf12bb302011-09-07 05:03:18 +0000164 int retval=0;
DRC0713c1b2014-08-22 13:43:33 +0000165 char *env=NULL;
DRCf12bb302011-09-07 05:03:18 +0000166
DRC9b28def2011-05-21 14:37:15 +0000167 switch(pixelFormat)
168 {
DRC25b995a2011-05-21 15:34:54 +0000169 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000170 cinfo->in_color_space=JCS_GRAYSCALE; break;
171 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000172 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000173 cinfo->in_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000174 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000175 cinfo->in_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000176 case TJPF_RGBX:
DRC67ce3b22011-12-19 02:21:03 +0000177 case TJPF_RGBA:
DRC9b28def2011-05-21 14:37:15 +0000178 cinfo->in_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000179 case TJPF_BGRX:
DRC67ce3b22011-12-19 02:21:03 +0000180 case TJPF_BGRA:
DRC9b28def2011-05-21 14:37:15 +0000181 cinfo->in_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000182 case TJPF_XRGB:
DRC67ce3b22011-12-19 02:21:03 +0000183 case TJPF_ARGB:
DRC9b28def2011-05-21 14:37:15 +0000184 cinfo->in_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000185 case TJPF_XBGR:
DRC67ce3b22011-12-19 02:21:03 +0000186 case TJPF_ABGR:
DRC9b28def2011-05-21 14:37:15 +0000187 cinfo->in_color_space=JCS_EXT_XBGR; break;
188 #else
DRC25b995a2011-05-21 15:34:54 +0000189 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000190 case TJPF_BGR:
191 case TJPF_RGBX:
192 case TJPF_BGRX:
193 case TJPF_XRGB:
194 case TJPF_XBGR:
195 case TJPF_RGBA:
196 case TJPF_BGRA:
197 case TJPF_ARGB:
198 case TJPF_ABGR:
199 cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
200 break;
DRC9b28def2011-05-21 14:37:15 +0000201 #endif
DRCcd7c3e62013-08-23 02:49:25 +0000202 case TJPF_CMYK:
203 cinfo->in_color_space=JCS_CMYK; break;
DRCefa4ddc2010-10-13 19:22:50 +0000204 }
DRC2e7b76b2009-04-03 12:04:24 +0000205
DRC9b28def2011-05-21 14:37:15 +0000206 cinfo->input_components=tjPixelSize[pixelFormat];
207 jpeg_set_defaults(cinfo);
DRC0713c1b2014-08-22 13:43:33 +0000208
209 if((env=getenv("TJ_OPTIMIZE"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
210 cinfo->optimize_coding=TRUE;
211 if((env=getenv("TJ_ARITHMETIC"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
212 cinfo->arith_code=TRUE;
213 if((env=getenv("TJ_RESTART"))!=NULL && strlen(env)>0)
214 {
215 int temp=-1; char tempc=0;
216 if(sscanf(env, "%d%c", &temp, &tempc)>=1 && temp>=0 && temp<=65535)
217 {
218 if(toupper(tempc)=='B')
219 {
220 cinfo->restart_interval=temp;
221 cinfo->restart_in_rows=0;
222 }
223 else
224 cinfo->restart_in_rows=temp;
225 }
226 }
227
DRC9b28def2011-05-21 14:37:15 +0000228 if(jpegQual>=0)
229 {
230 jpeg_set_quality(cinfo, jpegQual, TRUE);
DRC73d74c12012-06-29 23:46:38 +0000231 if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
DRC9b28def2011-05-21 14:37:15 +0000232 else cinfo->dct_method=JDCT_FASTEST;
233 }
DRC25b995a2011-05-21 15:34:54 +0000234 if(subsamp==TJSAMP_GRAY)
DRC9b28def2011-05-21 14:37:15 +0000235 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
DRCcd7c3e62013-08-23 02:49:25 +0000236 else if(pixelFormat==TJPF_CMYK)
237 jpeg_set_colorspace(cinfo, JCS_YCCK);
238 else jpeg_set_colorspace(cinfo, JCS_YCbCr);
DRC2e7b76b2009-04-03 12:04:24 +0000239
DRC0713c1b2014-08-22 13:43:33 +0000240 if((env=getenv("TJ_PROGRESSIVE"))!=NULL && strlen(env)>0
241 && !strcmp(env, "1"))
242 jpeg_simple_progression(cinfo);
243
DRC9b28def2011-05-21 14:37:15 +0000244 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
245 cinfo->comp_info[1].h_samp_factor=1;
246 cinfo->comp_info[2].h_samp_factor=1;
DRCcd7c3e62013-08-23 02:49:25 +0000247 if(cinfo->num_components>3)
248 cinfo->comp_info[3].h_samp_factor=tjMCUWidth[subsamp]/8;
DRC9b28def2011-05-21 14:37:15 +0000249 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
250 cinfo->comp_info[1].v_samp_factor=1;
251 cinfo->comp_info[2].v_samp_factor=1;
DRCcd7c3e62013-08-23 02:49:25 +0000252 if(cinfo->num_components>3)
253 cinfo->comp_info[3].v_samp_factor=tjMCUHeight[subsamp]/8;
DRCf12bb302011-09-07 05:03:18 +0000254
DRCf12bb302011-09-07 05:03:18 +0000255 return retval;
DRC9b28def2011-05-21 14:37:15 +0000256}
257
DRCf12bb302011-09-07 05:03:18 +0000258static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
DRC73d74c12012-06-29 23:46:38 +0000259 int pixelFormat, int flags)
DRC9b28def2011-05-21 14:37:15 +0000260{
DRCf12bb302011-09-07 05:03:18 +0000261 int retval=0;
262
DRC9b28def2011-05-21 14:37:15 +0000263 switch(pixelFormat)
264 {
DRC25b995a2011-05-21 15:34:54 +0000265 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000266 dinfo->out_color_space=JCS_GRAYSCALE; break;
267 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000268 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000269 dinfo->out_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000270 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000271 dinfo->out_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000272 case TJPF_RGBX:
DRC9b28def2011-05-21 14:37:15 +0000273 dinfo->out_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000274 case TJPF_BGRX:
DRC9b28def2011-05-21 14:37:15 +0000275 dinfo->out_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000276 case TJPF_XRGB:
DRC9b28def2011-05-21 14:37:15 +0000277 dinfo->out_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000278 case TJPF_XBGR:
DRC9b28def2011-05-21 14:37:15 +0000279 dinfo->out_color_space=JCS_EXT_XBGR; break;
DRC67ce3b22011-12-19 02:21:03 +0000280 #if JCS_ALPHA_EXTENSIONS==1
281 case TJPF_RGBA:
282 dinfo->out_color_space=JCS_EXT_RGBA; break;
283 case TJPF_BGRA:
284 dinfo->out_color_space=JCS_EXT_BGRA; break;
285 case TJPF_ARGB:
286 dinfo->out_color_space=JCS_EXT_ARGB; break;
287 case TJPF_ABGR:
288 dinfo->out_color_space=JCS_EXT_ABGR; break;
289 #endif
DRC9b28def2011-05-21 14:37:15 +0000290 #else
DRC25b995a2011-05-21 15:34:54 +0000291 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000292 case TJPF_BGR:
293 case TJPF_RGBX:
294 case TJPF_BGRX:
295 case TJPF_XRGB:
296 case TJPF_XBGR:
297 case TJPF_RGBA:
298 case TJPF_BGRA:
299 case TJPF_ARGB:
300 case TJPF_ABGR:
301 dinfo->out_color_space=JCS_RGB; break;
DRC67ce3b22011-12-19 02:21:03 +0000302 #endif
DRCcd7c3e62013-08-23 02:49:25 +0000303 case TJPF_CMYK:
304 dinfo->out_color_space=JCS_CMYK; break;
DRC9b28def2011-05-21 14:37:15 +0000305 default:
306 _throw("Unsupported pixel format");
DRC9b28def2011-05-21 14:37:15 +0000307 }
DRCf12bb302011-09-07 05:03:18 +0000308
DRC73d74c12012-06-29 23:46:38 +0000309 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
310
DRCf12bb302011-09-07 05:03:18 +0000311 bailout:
DRCf12bb302011-09-07 05:03:18 +0000312 return retval;
DRC9b28def2011-05-21 14:37:15 +0000313}
314
315
DRC9b49f0e2011-07-12 03:17:23 +0000316static int getSubsamp(j_decompress_ptr dinfo)
317{
318 int retval=-1, i, k;
319 for(i=0; i<NUMSUBOPT; i++)
320 {
DRCcd7c3e62013-08-23 02:49:25 +0000321 if(dinfo->num_components==pixelsize[i]
322 || ((dinfo->jpeg_color_space==JCS_YCCK
323 || dinfo->jpeg_color_space==JCS_CMYK)
324 && pixelsize[i]==3 && dinfo->num_components==4))
DRC9b49f0e2011-07-12 03:17:23 +0000325 {
326 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
327 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
328 {
329 int match=0;
330 for(k=1; k<dinfo->num_components; k++)
331 {
DRCcd7c3e62013-08-23 02:49:25 +0000332 int href=1, vref=1;
333 if(dinfo->jpeg_color_space==JCS_YCCK && k==3)
334 {
335 href=tjMCUWidth[i]/8; vref=tjMCUHeight[i]/8;
336 }
337 if(dinfo->comp_info[k].h_samp_factor==href
338 && dinfo->comp_info[k].v_samp_factor==vref)
DRC9b49f0e2011-07-12 03:17:23 +0000339 match++;
340 }
341 if(match==dinfo->num_components-1)
342 {
343 retval=i; break;
344 }
345 }
346 }
347 }
348 return retval;
349}
350
351
DRCafc06922012-03-23 19:47:57 +0000352#ifndef JCS_EXTENSIONS
353
354/* Conversion functions to emulate the colorspace extensions. This allows the
355 TurboJPEG wrapper to be used with libjpeg */
356
357#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
358 int rowPad=pitch-width*PS; \
359 while(height--) \
360 { \
361 unsigned char *endOfRow=src+width*PS; \
362 while(src<endOfRow) \
363 { \
364 dst[RGB_RED]=src[ROFFSET]; \
365 dst[RGB_GREEN]=src[GOFFSET]; \
366 dst[RGB_BLUE]=src[BOFFSET]; \
367 dst+=RGB_PIXELSIZE; src+=PS; \
368 } \
369 src+=rowPad; \
370 } \
371}
372
373static unsigned char *toRGB(unsigned char *src, int width, int pitch,
374 int height, int pixelFormat, unsigned char *dst)
375{
376 unsigned char *retval=src;
377 switch(pixelFormat)
378 {
379 case TJPF_RGB:
380 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
381 retval=dst; TORGB(3, 0, 1, 2);
382 #endif
383 break;
384 case TJPF_BGR:
385 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
386 retval=dst; TORGB(3, 2, 1, 0);
387 #endif
388 break;
389 case TJPF_RGBX:
390 case TJPF_RGBA:
391 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
392 retval=dst; TORGB(4, 0, 1, 2);
393 #endif
394 break;
395 case TJPF_BGRX:
396 case TJPF_BGRA:
397 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
398 retval=dst; TORGB(4, 2, 1, 0);
399 #endif
400 break;
401 case TJPF_XRGB:
402 case TJPF_ARGB:
403 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
404 retval=dst; TORGB(4, 1, 2, 3);
405 #endif
406 break;
407 case TJPF_XBGR:
408 case TJPF_ABGR:
409 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
410 retval=dst; TORGB(4, 3, 2, 1);
411 #endif
412 break;
413 }
414 return retval;
415}
416
417#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
418 int rowPad=pitch-width*PS; \
419 while(height--) \
420 { \
421 unsigned char *endOfRow=dst+width*PS; \
422 while(dst<endOfRow) \
423 { \
424 dst[ROFFSET]=src[RGB_RED]; \
425 dst[GOFFSET]=src[RGB_GREEN]; \
426 dst[BOFFSET]=src[RGB_BLUE]; \
427 SETALPHA \
428 dst+=PS; src+=RGB_PIXELSIZE; \
429 } \
430 dst+=rowPad; \
431 } \
432}
433
434static void fromRGB(unsigned char *src, unsigned char *dst, int width,
435 int pitch, int height, int pixelFormat)
436{
437 switch(pixelFormat)
438 {
439 case TJPF_RGB:
440 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
441 FROMRGB(3, 0, 1, 2,);
442 #endif
443 break;
444 case TJPF_BGR:
445 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
446 FROMRGB(3, 2, 1, 0,);
447 #endif
448 break;
449 case TJPF_RGBX:
450 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
451 FROMRGB(4, 0, 1, 2,);
452 #endif
453 break;
454 case TJPF_RGBA:
455 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
456 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
457 #endif
458 break;
459 case TJPF_BGRX:
460 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
461 FROMRGB(4, 2, 1, 0,);
462 #endif
463 break;
464 case TJPF_BGRA:
465 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
466 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
467 #endif
468 break;
469 case TJPF_XRGB:
470 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
471 FROMRGB(4, 1, 2, 3,); return;
472 #endif
473 break;
474 case TJPF_ARGB:
475 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
476 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
477 #endif
478 break;
479 case TJPF_XBGR:
480 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
481 FROMRGB(4, 3, 2, 1,); return;
482 #endif
483 break;
484 case TJPF_ABGR:
485 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
486 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
487 #endif
488 break;
489 }
490}
491
492#endif
493
494
DRC9b28def2011-05-21 14:37:15 +0000495/* General API functions */
496
497DLLEXPORT char* DLLCALL tjGetErrorStr(void)
498{
499 return errStr;
500}
501
502
503DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
504{
505 getinstance(handle);
506 if(setjmp(this->jerr.setjmp_buffer)) return -1;
507 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
508 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
509 free(this);
510 return 0;
511}
512
513
DRC6b76f752011-05-24 16:52:47 +0000514/* These are exposed mainly because Windows can't malloc() and free() across
515 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
516 with turbojpeg.dll for compatibility reasons. However, these functions
517 can potentially be used for other purposes by different implementations. */
518
519DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
520{
521 if(buf) free(buf);
522}
523
524
525DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
526{
527 return (unsigned char *)malloc(bytes);
528}
529
530
DRC9b28def2011-05-21 14:37:15 +0000531/* Compressor */
532
533static tjhandle _tjInitCompress(tjinstance *this)
534{
535 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
536
537 /* This is also straight out of example.c */
538 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
539 this->jerr.pub.error_exit=my_error_exit;
540 this->jerr.pub.output_message=my_output_message;
541
542 if(setjmp(this->jerr.setjmp_buffer))
543 {
544 /* If we get here, the JPEG code has signaled an error. */
545 if(this) free(this); return NULL;
546 }
547
548 jpeg_create_compress(&this->cinfo);
549 /* Make an initial call so it will create the destination manager */
550 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
551
DRC007a42c2011-05-22 13:55:56 +0000552 this->init|=COMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000553 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000554}
555
DRC890f1e02011-02-26 22:02:37 +0000556DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
557{
DRC9b28def2011-05-21 14:37:15 +0000558 tjinstance *this=NULL;
559 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000560 {
DRC007a42c2011-05-22 13:55:56 +0000561 snprintf(errStr, JMSG_LENGTH_MAX,
562 "tjInitCompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000563 return NULL;
564 }
DRC007a42c2011-05-22 13:55:56 +0000565 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000566 return _tjInitCompress(this);
DRC890f1e02011-02-26 22:02:37 +0000567}
568
DRC84241602011-02-25 02:08:23 +0000569
DRC9b49f0e2011-07-12 03:17:23 +0000570DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
571 int jpegSubsamp)
572{
573 unsigned long retval=0; int mcuw, mcuh, chromasf;
574 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
575 _throw("tjBufSize(): Invalid argument");
576
DRC006bc582014-02-27 21:22:54 +0000577 /* This allows for rare corner cases in which a JPEG image can actually be
578 larger than the uncompressed input (we wouldn't mention it if it hadn't
579 happened before.) */
DRC9b49f0e2011-07-12 03:17:23 +0000580 mcuw=tjMCUWidth[jpegSubsamp];
581 mcuh=tjMCUHeight[jpegSubsamp];
582 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
583 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
584
585 bailout:
586 return retval;
587}
588
DRC2e7b76b2009-04-03 12:04:24 +0000589DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
590{
DRCf3cf9732011-02-22 00:16:14 +0000591 unsigned long retval=0;
592 if(width<1 || height<1)
DRC007a42c2011-05-22 13:55:56 +0000593 _throw("TJBUFSIZE(): Invalid argument");
DRCf3cf9732011-02-22 00:16:14 +0000594
DRC006bc582014-02-27 21:22:54 +0000595 /* This allows for rare corner cases in which a JPEG image can actually be
596 larger than the uncompressed input (we wouldn't mention it if it hadn't
597 happened before.) */
DRC007a42c2011-05-22 13:55:56 +0000598 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
DRCf3cf9732011-02-22 00:16:14 +0000599
600 bailout:
601 return retval;
602}
603
DRC84241602011-02-25 02:08:23 +0000604
DRCf610d612013-04-26 10:33:29 +0000605DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
DRCf3cf9732011-02-22 00:16:14 +0000606 int subsamp)
607{
DRC40dd3142014-08-17 12:23:49 +0000608 int retval=0, nc, i;
609
610 if(subsamp<0 || subsamp>=NUMSUBOPT)
DRCf610d612013-04-26 10:33:29 +0000611 _throw("tjBufSizeYUV2(): Invalid argument");
DRC40dd3142014-08-17 12:23:49 +0000612
613 nc=(subsamp==TJSAMP_GRAY? 1:3);
614 for(i=0; i<nc; i++)
615 {
DRC55620c62014-10-23 19:08:14 +0000616 int pw=tjPlaneWidth(i, width, subsamp);
617 int stride=PAD(pw, pad);
DRC40dd3142014-08-17 12:23:49 +0000618 int ph=tjPlaneHeight(i, height, subsamp);
DRC55620c62014-10-23 19:08:14 +0000619 if(pw<0 || ph<0) return -1;
DRC40dd3142014-08-17 12:23:49 +0000620 else retval+=stride*ph;
621 }
DRCf3cf9732011-02-22 00:16:14 +0000622
623 bailout:
624 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000625}
626
DRCf610d612013-04-26 10:33:29 +0000627DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
628 int subsamp)
629{
630 return tjBufSizeYUV2(width, 4, height, subsamp);
631}
DRC84241602011-02-25 02:08:23 +0000632
DRC9b49f0e2011-07-12 03:17:23 +0000633DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
634 int subsamp)
635{
636 return tjBufSizeYUV(width, height, subsamp);
637}
638
639
DRC40dd3142014-08-17 12:23:49 +0000640DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
641{
642 int pw, nc, retval=0;
643
644 if(width<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
645 _throw("tjPlaneWidth(): Invalid argument");
646 nc=(subsamp==TJSAMP_GRAY? 1:3);
647 if(componentID<0 || componentID>=nc)
648 _throw("tjPlaneWidth(): Invalid argument");
649
650 pw=PAD(width, tjMCUWidth[subsamp]/8);
651 if(componentID==0)
652 retval=pw;
653 else
654 retval=pw*8/tjMCUWidth[subsamp];
655
656 bailout:
657 return retval;
658}
659
660
661DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
662{
663 int ph, nc, retval=0;
664
665 if(height<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
666 _throw("tjPlaneHeight(): Invalid argument");
667 nc=(subsamp==TJSAMP_GRAY? 1:3);
668 if(componentID<0 || componentID>=nc)
669 _throw("tjPlaneHeight(): Invalid argument");
670
671 ph=PAD(height, tjMCUHeight[subsamp]/8);
672 if(componentID==0)
673 retval=ph;
674 else
675 retval=ph*8/tjMCUHeight[subsamp];
676
677 bailout:
678 return retval;
679}
680
681
682DLLEXPORT unsigned long DLLCALL tjPlaneSizeYUV(int componentID, int width,
683 int stride, int height, int subsamp)
684{
685 unsigned long retval=0;
686 int pw, ph;
687
688 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
689 _throw("tjPlaneSizeYUV(): Invalid argument");
690
691 pw=tjPlaneWidth(componentID, width, subsamp);
692 ph=tjPlaneHeight(componentID, height, subsamp);
DRC22409742014-10-23 18:54:42 +0000693 if(pw<0 || ph<0) return -1;
DRC40dd3142014-08-17 12:23:49 +0000694
695 if(stride==0) stride=pw;
696 else stride=abs(stride);
697
698 retval=stride*(ph-1)+pw;
699
700 bailout:
701 return retval;
702}
703
704
DRC9b28def2011-05-21 14:37:15 +0000705DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
706 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
707 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
708{
DRCff78e372011-05-24 10:17:32 +0000709 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
DRCafc06922012-03-23 19:47:57 +0000710 #ifndef JCS_EXTENSIONS
711 unsigned char *rgbBuf=NULL;
712 #endif
DRC9b28def2011-05-21 14:37:15 +0000713
DRC41861622014-04-16 23:38:37 +0000714 getcinstance(handle)
DRC9b28def2011-05-21 14:37:15 +0000715 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000716 _throw("tjCompress2(): Instance has not been initialized for compression");
DRC9b28def2011-05-21 14:37:15 +0000717
718 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
719 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
720 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
DRC007a42c2011-05-22 13:55:56 +0000721 _throw("tjCompress2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000722
723 if(setjmp(this->jerr.setjmp_buffer))
724 {
725 /* If we get here, the JPEG code has signaled an error. */
726 retval=-1;
727 goto bailout;
728 }
729
730 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
731
DRCafc06922012-03-23 19:47:57 +0000732 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +0000733 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
DRCafc06922012-03-23 19:47:57 +0000734 {
735 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
736 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
737 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
738 pitch=width*RGB_PIXELSIZE;
739 }
740 #endif
741
DRC9b28def2011-05-21 14:37:15 +0000742 cinfo->image_width=width;
743 cinfo->image_height=height;
744
DRC25b995a2011-05-21 15:34:54 +0000745 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
746 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
747 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000748
DRCff78e372011-05-24 10:17:32 +0000749 if(flags&TJFLAG_NOREALLOC)
750 {
DRC9b49f0e2011-07-12 03:17:23 +0000751 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +0000752 }
753 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
DRC73d74c12012-06-29 23:46:38 +0000754 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
DRCf12bb302011-09-07 05:03:18 +0000755 return -1;
DRC9b28def2011-05-21 14:37:15 +0000756
757 jpeg_start_compress(cinfo, TRUE);
758 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000759 _throw("tjCompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000760 for(i=0; i<height; i++)
761 {
DRC25b995a2011-05-21 15:34:54 +0000762 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000763 else row_pointer[i]=&srcBuf[i*pitch];
764 }
765 while(cinfo->next_scanline<cinfo->image_height)
766 {
767 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
768 cinfo->image_height-cinfo->next_scanline);
769 }
770 jpeg_finish_compress(cinfo);
771
772 bailout:
773 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000774 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000775 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000776 #endif
DRC9b28def2011-05-21 14:37:15 +0000777 if(row_pointer) free(row_pointer);
778 return retval;
779}
780
781DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
782 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
783 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
784{
785 int retval=0; unsigned long size;
786 if(flags&TJ_YUV)
787 {
DRC9b49f0e2011-07-12 03:17:23 +0000788 size=tjBufSizeYUV(width, height, jpegSubsamp);
DRC9b28def2011-05-21 14:37:15 +0000789 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
790 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
791 }
792 else
793 {
DRC9b28def2011-05-21 14:37:15 +0000794 retval=tjCompress2(handle, srcBuf, width, pitch, height,
795 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
DRC25b995a2011-05-21 15:34:54 +0000796 flags|TJFLAG_NOREALLOC);
DRC9b28def2011-05-21 14:37:15 +0000797 }
798 *jpegSize=size;
799 return retval;
800}
801
802
DRCaecea382014-08-11 18:05:41 +0000803DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle, unsigned char *srcBuf,
804 int width, int pitch, int height, int pixelFormat, unsigned char **dstPlanes,
805 int *strides, int subsamp, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000806{
DRC91e86ba2011-02-15 05:24:08 +0000807 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000808 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
809 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
810 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +0000811 int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +0000812 JSAMPLE *ptr;
DRC9b28def2011-05-21 14:37:15 +0000813 jpeg_component_info *compptr;
DRCafc06922012-03-23 19:47:57 +0000814 #ifndef JCS_EXTENSIONS
815 unsigned char *rgbBuf=NULL;
816 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000817
DRC41861622014-04-16 23:38:37 +0000818 getcinstance(handle);
DRCb51ee892013-10-31 05:00:19 +0000819
DRCfbb67472010-11-24 04:02:37 +0000820 for(i=0; i<MAX_COMPONENTS; i++)
821 {
822 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
823 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
824 }
825
DRCe2f8e692013-10-30 22:21:06 +0000826 if((this->init&COMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +0000827 _throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
DRCe2f8e692013-10-30 22:21:06 +0000828
DRC9b28def2011-05-21 14:37:15 +0000829 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
DRCaecea382014-08-11 18:05:41 +0000830 || pixelFormat>=TJ_NUMPF || !dstPlanes || !dstPlanes[0] || subsamp<0
831 || subsamp>=NUMSUBOPT)
832 _throw("tjEncodeYUVPlanes(): Invalid argument");
833 if(subsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
834 _throw("tjEncodeYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000835
DRC9b28def2011-05-21 14:37:15 +0000836 if(setjmp(this->jerr.setjmp_buffer))
837 {
838 /* If we get here, the JPEG code has signaled an error. */
839 retval=-1;
840 goto bailout;
841 }
DRC2e7b76b2009-04-03 12:04:24 +0000842
DRCcd7c3e62013-08-23 02:49:25 +0000843 if(pixelFormat==TJPF_CMYK)
DRCaecea382014-08-11 18:05:41 +0000844 _throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
DRCcd7c3e62013-08-23 02:49:25 +0000845
DRC9b28def2011-05-21 14:37:15 +0000846 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC2e7b76b2009-04-03 12:04:24 +0000847
DRCafc06922012-03-23 19:47:57 +0000848 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +0000849 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
DRCafc06922012-03-23 19:47:57 +0000850 {
851 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
DRCaecea382014-08-11 18:05:41 +0000852 if(!rgbBuf) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRCafc06922012-03-23 19:47:57 +0000853 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
854 pitch=width*RGB_PIXELSIZE;
855 }
856 #endif
857
DRC9b28def2011-05-21 14:37:15 +0000858 cinfo->image_width=width;
859 cinfo->image_height=height;
DRC2e7b76b2009-04-03 12:04:24 +0000860
DRC25b995a2011-05-21 15:34:54 +0000861 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
862 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
863 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000864
DRC73d74c12012-06-29 23:46:38 +0000865 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000866
DRC38c99702014-02-11 09:45:18 +0000867 /* Execute only the parts of jpeg_start_compress() that we need. If we
868 were to call the whole jpeg_start_compress() function, then it would try
869 to write the file headers, which could overflow the output buffer if the
870 YUV image were very small. */
871 if(cinfo->global_state!=CSTATE_START)
DRCaecea382014-08-11 18:05:41 +0000872 _throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
DRC38c99702014-02-11 09:45:18 +0000873 (*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
DRC38c99702014-02-11 09:45:18 +0000874 jinit_c_master_control(cinfo, FALSE);
875 jinit_color_converter(cinfo);
876 jinit_downsampler(cinfo);
DRC50cfc462014-03-06 20:03:37 +0000877 (*cinfo->cconvert->start_pass)(cinfo);
DRC38c99702014-02-11 09:45:18 +0000878
DRC40dd3142014-08-17 12:23:49 +0000879 pw0=PAD(width, cinfo->max_h_samp_factor);
880 ph0=PAD(height, cinfo->max_v_samp_factor);
DRC2e7b76b2009-04-03 12:04:24 +0000881
DRC40dd3142014-08-17 12:23:49 +0000882 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
DRCaecea382014-08-11 18:05:41 +0000883 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000884 for(i=0; i<height; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000885 {
DRC25b995a2011-05-21 15:34:54 +0000886 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000887 else row_pointer[i]=&srcBuf[i*pitch];
888 }
DRC40dd3142014-08-17 12:23:49 +0000889 if(height<ph0)
890 for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
DRCfbb67472010-11-24 04:02:37 +0000891
DRC9b28def2011-05-21 14:37:15 +0000892 for(i=0; i<cinfo->num_components; i++)
893 {
894 compptr=&cinfo->comp_info[i];
895 _tmpbuf[i]=(JSAMPLE *)malloc(
896 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
897 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRCaecea382014-08-11 18:05:41 +0000898 if(!_tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000899 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRCaecea382014-08-11 18:05:41 +0000900 if(!tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000901 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRCfbb67472010-11-24 04:02:37 +0000902 {
DRC9b28def2011-05-21 14:37:15 +0000903 unsigned char *_tmpbuf_aligned=
904 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
905 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000906 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC9b28def2011-05-21 14:37:15 +0000907 /compptr->h_samp_factor, 16) * row];
DRCfbb67472010-11-24 04:02:37 +0000908 }
DRC9b28def2011-05-21 14:37:15 +0000909 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
910 * compptr->v_samp_factor + 16);
DRCaecea382014-08-11 18:05:41 +0000911 if(!_tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000912 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCaecea382014-08-11 18:05:41 +0000913 if(!tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000914 for(row=0; row<compptr->v_samp_factor; row++)
915 {
916 unsigned char *_tmpbuf2_aligned=
917 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
918 tmpbuf2[i][row]=&_tmpbuf2_aligned[
919 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
920 }
DRC40dd3142014-08-17 12:23:49 +0000921 pw[i]=pw0*compptr->h_samp_factor/cinfo->max_h_samp_factor;
922 ph[i]=ph0*compptr->v_samp_factor/cinfo->max_v_samp_factor;
923 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
DRCaecea382014-08-11 18:05:41 +0000924 if(!outbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
925 ptr=dstPlanes[i];
DRC40dd3142014-08-17 12:23:49 +0000926 for(row=0; row<ph[i]; row++)
DRC9b28def2011-05-21 14:37:15 +0000927 {
928 outbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +0000929 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC9b28def2011-05-21 14:37:15 +0000930 }
931 }
DRCfbb67472010-11-24 04:02:37 +0000932
DRC40dd3142014-08-17 12:23:49 +0000933 for(row=0; row<ph0; row+=cinfo->max_v_samp_factor)
DRCfbb67472010-11-24 04:02:37 +0000934 {
DRC9b28def2011-05-21 14:37:15 +0000935 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
936 cinfo->max_v_samp_factor);
937 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
938 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
939 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
940 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
DRC40dd3142014-08-17 12:23:49 +0000941 compptr->v_samp_factor, pw[i]);
DRC6ee54592011-03-01 08:18:30 +0000942 }
DRC9b28def2011-05-21 14:37:15 +0000943 cinfo->next_scanline+=height;
944 jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000945
DRC91e86ba2011-02-15 05:24:08 +0000946 bailout:
DRC9b28def2011-05-21 14:37:15 +0000947 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000948 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000949 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000950 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000951 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000952 for(i=0; i<MAX_COMPONENTS; i++)
953 {
954 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000955 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000956 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000957 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000958 if(outbuf[i]!=NULL) free(outbuf[i]);
959 }
DRC91e86ba2011-02-15 05:24:08 +0000960 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000961}
962
DRCaecea382014-08-11 18:05:41 +0000963DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle, unsigned char *srcBuf,
964 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
965 int pad, int subsamp, int flags)
966{
967 unsigned char *dstPlanes[3];
DRC40dd3142014-08-17 12:23:49 +0000968 int pw0, ph0, strides[3], retval=-1;
DRCaecea382014-08-11 18:05:41 +0000969
970 if(width<=0 || height<=0 || dstBuf==NULL || pad<0 || !isPow2(pad)
971 || subsamp<0 || subsamp>=NUMSUBOPT)
972 _throw("tjEncodeYUV3(): Invalid argument");
973
DRC40dd3142014-08-17 12:23:49 +0000974 pw0=tjPlaneWidth(0, width, subsamp);
975 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +0000976 dstPlanes[0]=dstBuf;
DRC40dd3142014-08-17 12:23:49 +0000977 strides[0]=PAD(pw0, pad);
978 if(subsamp==TJSAMP_GRAY)
979 {
980 strides[1]=strides[2]=0;
981 dstPlanes[1]=dstPlanes[2]=NULL;
982 }
983 else
984 {
985 int pw1=tjPlaneWidth(1, width, subsamp);
986 int ph1=tjPlaneHeight(1, height, subsamp);
987 strides[1]=strides[2]=PAD(pw1, pad);
988 dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
989 dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
990 }
DRCaecea382014-08-11 18:05:41 +0000991
992 return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
993 dstPlanes, strides, subsamp, flags);
994
995 bailout:
996 return retval;
997}
998
DRCf610d612013-04-26 10:33:29 +0000999DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
1000 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
1001 int subsamp, int flags)
1002{
1003 return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
1004 dstBuf, 4, subsamp, flags);
1005}
1006
DRC9b28def2011-05-21 14:37:15 +00001007DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
1008 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
1009 int subsamp, int flags)
DRC84241602011-02-25 02:08:23 +00001010{
DRC9b28def2011-05-21 14:37:15 +00001011 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1012 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
DRC84241602011-02-25 02:08:23 +00001013}
1014
1015
DRCaecea382014-08-11 18:05:41 +00001016DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle,
1017 unsigned char **srcPlanes, int width, int *strides, int height, int subsamp,
1018 unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)
DRC910a3572013-10-30 23:02:57 +00001019{
1020 int i, row, retval=0, alloc=1; JSAMPROW *inbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +00001021 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
DRC910a3572013-10-30 23:02:57 +00001022 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001023 JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC910a3572013-10-30 23:02:57 +00001024
DRC41861622014-04-16 23:38:37 +00001025 getcinstance(handle)
DRCb51ee892013-10-31 05:00:19 +00001026
DRC910a3572013-10-30 23:02:57 +00001027 for(i=0; i<MAX_COMPONENTS; i++)
1028 {
1029 tmpbuf[i]=NULL; inbuf[i]=NULL;
1030 }
1031
DRC910a3572013-10-30 23:02:57 +00001032 if((this->init&COMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001033 _throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
DRC910a3572013-10-30 23:02:57 +00001034
DRCaecea382014-08-11 18:05:41 +00001035 if(!srcPlanes || !srcPlanes[0] || width<=0 || height<=0 || subsamp<0
DRC910a3572013-10-30 23:02:57 +00001036 || subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0
1037 || jpegQual>100)
DRCaecea382014-08-11 18:05:41 +00001038 _throw("tjCompressFromYUVPlanes(): Invalid argument");
1039 if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1040 _throw("tjCompressFromYUVPlanes(): Invalid argument");
DRC910a3572013-10-30 23:02:57 +00001041
1042 if(setjmp(this->jerr.setjmp_buffer))
1043 {
1044 /* If we get here, the JPEG code has signaled an error. */
1045 retval=-1;
1046 goto bailout;
1047 }
1048
1049 cinfo->image_width=width;
1050 cinfo->image_height=height;
1051
1052 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1053 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1054 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1055
1056 if(flags&TJFLAG_NOREALLOC)
1057 {
1058 alloc=0; *jpegSize=tjBufSize(width, height, subsamp);
1059 }
1060 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1061 if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1)
1062 return -1;
1063 cinfo->raw_data_in=TRUE;
1064
1065 jpeg_start_compress(cinfo, TRUE);
1066 for(i=0; i<cinfo->num_components; i++)
1067 {
1068 jpeg_component_info *compptr=&cinfo->comp_info[i];
1069 int ih;
1070 iw[i]=compptr->width_in_blocks*DCTSIZE;
1071 ih=compptr->height_in_blocks*DCTSIZE;
DRC40dd3142014-08-17 12:23:49 +00001072 pw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor)
DRC910a3572013-10-30 23:02:57 +00001073 *compptr->h_samp_factor/cinfo->max_h_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001074 ph[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor)
DRC910a3572013-10-30 23:02:57 +00001075 *compptr->v_samp_factor/cinfo->max_v_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001076 if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
DRC910a3572013-10-30 23:02:57 +00001077 th[i]=compptr->v_samp_factor*DCTSIZE;
1078 tmpbufsize+=iw[i]*th[i];
DRC40dd3142014-08-17 12:23:49 +00001079 if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001080 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1081 ptr=srcPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001082 for(row=0; row<ph[i]; row++)
DRC910a3572013-10-30 23:02:57 +00001083 {
1084 inbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001085 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC910a3572013-10-30 23:02:57 +00001086 }
1087 }
1088 if(usetmpbuf)
1089 {
1090 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRCaecea382014-08-11 18:05:41 +00001091 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
DRC910a3572013-10-30 23:02:57 +00001092 ptr=_tmpbuf;
1093 for(i=0; i<cinfo->num_components; i++)
1094 {
1095 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001096 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
DRC910a3572013-10-30 23:02:57 +00001097 for(row=0; row<th[i]; row++)
1098 {
1099 tmpbuf[i][row]=ptr;
1100 ptr+=iw[i];
1101 }
1102 }
1103 }
1104
1105 for(row=0; row<(int)cinfo->image_height;
1106 row+=cinfo->max_v_samp_factor*DCTSIZE)
1107 {
1108 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1109 int crow[MAX_COMPONENTS];
1110 for(i=0; i<cinfo->num_components; i++)
1111 {
1112 jpeg_component_info *compptr=&cinfo->comp_info[i];
1113 crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor;
1114 if(usetmpbuf)
1115 {
1116 int j, k;
DRC40dd3142014-08-17 12:23:49 +00001117 for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
DRC910a3572013-10-30 23:02:57 +00001118 {
DRC40dd3142014-08-17 12:23:49 +00001119 memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], pw[i]);
DRC006bc582014-02-27 21:22:54 +00001120 /* Duplicate last sample in row to fill out MCU */
DRC40dd3142014-08-17 12:23:49 +00001121 for(k=pw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][pw[i]-1];
DRC910a3572013-10-30 23:02:57 +00001122 }
DRC006bc582014-02-27 21:22:54 +00001123 /* Duplicate last row to fill out MCU */
DRC40dd3142014-08-17 12:23:49 +00001124 for(j=ph[i]-crow[i]; j<th[i]; j++)
1125 memcpy(tmpbuf[i][j], tmpbuf[i][ph[i]-crow[i]-1], iw[i]);
DRC910a3572013-10-30 23:02:57 +00001126 yuvptr[i]=tmpbuf[i];
1127 }
1128 else
1129 yuvptr[i]=&inbuf[i][crow[i]];
1130 }
1131 jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE);
1132 }
1133 jpeg_finish_compress(cinfo);
1134
1135 bailout:
1136 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1137 for(i=0; i<MAX_COMPONENTS; i++)
1138 {
1139 if(tmpbuf[i]) free(tmpbuf[i]);
1140 if(inbuf[i]) free(inbuf[i]);
1141 }
1142 if(_tmpbuf) free(_tmpbuf);
1143 return retval;
1144}
1145
DRCaecea382014-08-11 18:05:41 +00001146DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle, unsigned char *srcBuf,
1147 int width, int pad, int height, int subsamp, unsigned char **jpegBuf,
1148 unsigned long *jpegSize, int jpegQual, int flags)
1149{
1150 unsigned char *srcPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001151 int pw0, ph0, strides[3], retval=-1;
DRCaecea382014-08-11 18:05:41 +00001152
1153 if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
1154 || subsamp>=NUMSUBOPT)
1155 _throw("tjCompressFromYUV(): Invalid argument");
1156
DRC40dd3142014-08-17 12:23:49 +00001157 pw0=tjPlaneWidth(0, width, subsamp);
1158 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +00001159 srcPlanes[0]=srcBuf;
DRC40dd3142014-08-17 12:23:49 +00001160 strides[0]=PAD(pw0, pad);
1161 if(subsamp==TJSAMP_GRAY)
1162 {
1163 strides[1]=strides[2]=0;
1164 srcPlanes[1]=srcPlanes[2]=NULL;
1165 }
1166 else
1167 {
1168 int pw1=tjPlaneWidth(1, width, subsamp);
1169 int ph1=tjPlaneHeight(1, height, subsamp);
1170 strides[1]=strides[2]=PAD(pw1, pad);
1171 srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1172 srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1173 }
DRCaecea382014-08-11 18:05:41 +00001174
1175 return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1176 subsamp, jpegBuf, jpegSize, jpegQual, flags);
1177
1178 bailout:
1179 return retval;
1180}
1181
DRC910a3572013-10-30 23:02:57 +00001182
DRC9b28def2011-05-21 14:37:15 +00001183/* Decompressor */
DRC2e7b76b2009-04-03 12:04:24 +00001184
DRC9b28def2011-05-21 14:37:15 +00001185static tjhandle _tjInitDecompress(tjinstance *this)
DRC2e7b76b2009-04-03 12:04:24 +00001186{
DRC9b28def2011-05-21 14:37:15 +00001187 unsigned char buffer[1];
DRC2e7b76b2009-04-03 12:04:24 +00001188
DRC9b28def2011-05-21 14:37:15 +00001189 /* This is also straight out of example.c */
1190 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
1191 this->jerr.pub.error_exit=my_error_exit;
1192 this->jerr.pub.output_message=my_output_message;
DRC2e7b76b2009-04-03 12:04:24 +00001193
DRC9b28def2011-05-21 14:37:15 +00001194 if(setjmp(this->jerr.setjmp_buffer))
1195 {
1196 /* If we get here, the JPEG code has signaled an error. */
1197 if(this) free(this); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +00001198 }
DRC2e7b76b2009-04-03 12:04:24 +00001199
DRC9b28def2011-05-21 14:37:15 +00001200 jpeg_create_decompress(&this->dinfo);
1201 /* Make an initial call so it will create the source manager */
1202 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +00001203
DRC007a42c2011-05-22 13:55:56 +00001204 this->init|=DECOMPRESS;
DRC9b28def2011-05-21 14:37:15 +00001205 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +00001206}
1207
DRC890f1e02011-02-26 22:02:37 +00001208DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
1209{
DRC9b28def2011-05-21 14:37:15 +00001210 tjinstance *this;
1211 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00001212 {
DRC007a42c2011-05-22 13:55:56 +00001213 snprintf(errStr, JMSG_LENGTH_MAX,
1214 "tjInitDecompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00001215 return NULL;
1216 }
DRC007a42c2011-05-22 13:55:56 +00001217 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +00001218 return _tjInitDecompress(this);
DRC890f1e02011-02-26 22:02:37 +00001219}
1220
DRC2e7b76b2009-04-03 12:04:24 +00001221
DRCcd7c3e62013-08-23 02:49:25 +00001222DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
DRC9b28def2011-05-21 14:37:15 +00001223 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
DRCcd7c3e62013-08-23 02:49:25 +00001224 int *jpegSubsamp, int *jpegColorspace)
DRC1fe80f82010-12-14 01:21:29 +00001225{
DRC9b49f0e2011-07-12 03:17:23 +00001226 int retval=0;
DRC1fe80f82010-12-14 01:21:29 +00001227
DRC41861622014-04-16 23:38:37 +00001228 getdinstance(handle);
DRC9b28def2011-05-21 14:37:15 +00001229 if((this->init&DECOMPRESS)==0)
DRCcd7c3e62013-08-23 02:49:25 +00001230 _throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
DRC1fe80f82010-12-14 01:21:29 +00001231
DRC9b28def2011-05-21 14:37:15 +00001232 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
DRCcd7c3e62013-08-23 02:49:25 +00001233 || jpegSubsamp==NULL || jpegColorspace==NULL)
1234 _throw("tjDecompressHeader3(): Invalid argument");
DRC1fe80f82010-12-14 01:21:29 +00001235
DRC9b28def2011-05-21 14:37:15 +00001236 if(setjmp(this->jerr.setjmp_buffer))
1237 {
1238 /* If we get here, the JPEG code has signaled an error. */
DRC1fe80f82010-12-14 01:21:29 +00001239 return -1;
1240 }
1241
DRC9b28def2011-05-21 14:37:15 +00001242 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1243 jpeg_read_header(dinfo, TRUE);
DRC1fe80f82010-12-14 01:21:29 +00001244
DRC9b28def2011-05-21 14:37:15 +00001245 *width=dinfo->image_width;
1246 *height=dinfo->image_height;
DRC9b49f0e2011-07-12 03:17:23 +00001247 *jpegSubsamp=getSubsamp(dinfo);
DRCcd7c3e62013-08-23 02:49:25 +00001248 switch(dinfo->jpeg_color_space)
1249 {
1250 case JCS_GRAYSCALE: *jpegColorspace=TJCS_GRAY; break;
1251 case JCS_RGB: *jpegColorspace=TJCS_RGB; break;
1252 case JCS_YCbCr: *jpegColorspace=TJCS_YCbCr; break;
1253 case JCS_CMYK: *jpegColorspace=TJCS_CMYK; break;
1254 case JCS_YCCK: *jpegColorspace=TJCS_YCCK; break;
1255 default: *jpegColorspace=-1; break;
1256 }
DRC1fe80f82010-12-14 01:21:29 +00001257
DRC9b28def2011-05-21 14:37:15 +00001258 jpeg_abort_decompress(dinfo);
DRC1fe80f82010-12-14 01:21:29 +00001259
DRC9b28def2011-05-21 14:37:15 +00001260 if(*jpegSubsamp<0)
DRCcd7c3e62013-08-23 02:49:25 +00001261 _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1262 if(*jpegColorspace<0)
1263 _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
DRC007a42c2011-05-22 13:55:56 +00001264 if(*width<1 || *height<1)
DRCcd7c3e62013-08-23 02:49:25 +00001265 _throw("tjDecompressHeader3(): Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +00001266
1267 bailout:
1268 return retval;
1269}
1270
DRCcd7c3e62013-08-23 02:49:25 +00001271DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
1272 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
1273 int *jpegSubsamp)
1274{
1275 int jpegColorspace;
1276 return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1277 jpegSubsamp, &jpegColorspace);
1278}
1279
DRC9b28def2011-05-21 14:37:15 +00001280DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
1281 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
DRC91e86ba2011-02-15 05:24:08 +00001282{
DRC9b28def2011-05-21 14:37:15 +00001283 int jpegSubsamp;
1284 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1285 &jpegSubsamp);
DRC1fe80f82010-12-14 01:21:29 +00001286}
1287
1288
DRC109a5782011-03-01 09:53:07 +00001289DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +00001290{
DRC109a5782011-03-01 09:53:07 +00001291 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +00001292 {
DRC9b28def2011-05-21 14:37:15 +00001293 snprintf(errStr, JMSG_LENGTH_MAX,
DRC007a42c2011-05-22 13:55:56 +00001294 "tjGetScalingFactors(): Invalid argument");
DRC109a5782011-03-01 09:53:07 +00001295 return NULL;
DRCb28fc572011-02-22 06:41:29 +00001296 }
1297
DRC109a5782011-03-01 09:53:07 +00001298 *numscalingfactors=NUMSF;
1299 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +00001300}
1301
1302
DRC9b28def2011-05-21 14:37:15 +00001303DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
1304 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1305 int height, int pixelFormat, int flags)
DRC2e7b76b2009-04-03 12:04:24 +00001306{
DRC9b28def2011-05-21 14:37:15 +00001307 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRC109a5782011-03-01 09:53:07 +00001308 int jpegwidth, jpegheight, scaledw, scaledh;
DRCafc06922012-03-23 19:47:57 +00001309 #ifndef JCS_EXTENSIONS
1310 unsigned char *rgbBuf=NULL;
1311 unsigned char *_dstBuf=NULL; int _pitch=0;
1312 #endif
DRC2e7b76b2009-04-03 12:04:24 +00001313
DRC41861622014-04-16 23:38:37 +00001314 getdinstance(handle);
DRC9b28def2011-05-21 14:37:15 +00001315 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001316 _throw("tjDecompress2(): Instance has not been initialized for decompression");
DRC9b28def2011-05-21 14:37:15 +00001317
1318 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
1319 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
1320 _throw("tjDecompress2(): Invalid argument");
1321
DRC25b995a2011-05-21 15:34:54 +00001322 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1323 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1324 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +00001325
1326 if(setjmp(this->jerr.setjmp_buffer))
1327 {
1328 /* If we get here, the JPEG code has signaled an error. */
1329 retval=-1;
1330 goto bailout;
1331 }
1332
1333 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1334 jpeg_read_header(dinfo, TRUE);
DRC73d74c12012-06-29 23:46:38 +00001335 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
DRC2eda8212012-03-23 19:32:38 +00001336 {
1337 retval=-1; goto bailout;
1338 }
DRC9b28def2011-05-21 14:37:15 +00001339
DRC25b995a2011-05-21 15:34:54 +00001340 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +00001341
1342 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1343 if(width==0) width=jpegwidth;
1344 if(height==0) height=jpegheight;
1345 for(i=0; i<NUMSF; i++)
1346 {
1347 scaledw=TJSCALED(jpegwidth, sf[i]);
1348 scaledh=TJSCALED(jpegheight, sf[i]);
1349 if(scaledw<=width && scaledh<=height)
DRCf610d612013-04-26 10:33:29 +00001350 break;
DRC9b28def2011-05-21 14:37:15 +00001351 }
1352 if(scaledw>width || scaledh>height)
DRC007a42c2011-05-22 13:55:56 +00001353 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
DRC9b28def2011-05-21 14:37:15 +00001354 width=scaledw; height=scaledh;
1355 dinfo->scale_num=sf[i].num;
1356 dinfo->scale_denom=sf[i].denom;
1357
1358 jpeg_start_decompress(dinfo);
1359 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
DRCafc06922012-03-23 19:47:57 +00001360
1361 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +00001362 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
DRCafc06922012-03-23 19:47:57 +00001363 (RGB_RED!=tjRedOffset[pixelFormat] ||
1364 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1365 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1366 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1367 {
1368 rgbBuf=(unsigned char *)malloc(width*height*3);
1369 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1370 _pitch=pitch; pitch=width*3;
1371 _dstBuf=dstBuf; dstBuf=rgbBuf;
1372 }
1373 #endif
1374
DRC9b28def2011-05-21 14:37:15 +00001375 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1376 *dinfo->output_height))==NULL)
DRC007a42c2011-05-22 13:55:56 +00001377 _throw("tjDecompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001378 for(i=0; i<(int)dinfo->output_height; i++)
1379 {
DRC25b995a2011-05-21 15:34:54 +00001380 if(flags&TJFLAG_BOTTOMUP)
DRC9b28def2011-05-21 14:37:15 +00001381 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1382 else row_pointer[i]=&dstBuf[i*pitch];
1383 }
1384 while(dinfo->output_scanline<dinfo->output_height)
1385 {
1386 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1387 dinfo->output_height-dinfo->output_scanline);
1388 }
1389 jpeg_finish_decompress(dinfo);
1390
DRCafc06922012-03-23 19:47:57 +00001391 #ifndef JCS_EXTENSIONS
1392 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1393 #endif
1394
DRC9b28def2011-05-21 14:37:15 +00001395 bailout:
1396 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRCafc06922012-03-23 19:47:57 +00001397 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +00001398 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +00001399 #endif
DRC9b28def2011-05-21 14:37:15 +00001400 if(row_pointer) free(row_pointer);
1401 return retval;
1402}
1403
1404DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1405 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1406 int height, int pixelSize, int flags)
1407{
1408 if(flags&TJ_YUV)
1409 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1410 else
1411 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1412 height, getPixelFormat(pixelSize, flags), flags);
1413}
1414
1415
DRC34dca052014-02-28 09:17:14 +00001416static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
1417 int pixelFormat, int subsamp, int flags)
1418{
DRC895fd6d2014-02-28 09:35:34 +00001419 int i;
1420
DRC34dca052014-02-28 09:17:14 +00001421 dinfo->scale_num=dinfo->scale_denom=1;
1422
1423 if(subsamp==TJSAMP_GRAY)
1424 {
DRCc9014492014-03-10 09:34:04 +00001425 dinfo->num_components=dinfo->comps_in_scan=1;
DRC34dca052014-02-28 09:17:14 +00001426 dinfo->jpeg_color_space=JCS_GRAYSCALE;
1427 }
1428 else
1429 {
DRCc9014492014-03-10 09:34:04 +00001430 dinfo->num_components=dinfo->comps_in_scan=3;
DRC34dca052014-02-28 09:17:14 +00001431 dinfo->jpeg_color_space=JCS_YCbCr;
1432 }
1433
1434 dinfo->comp_info=(jpeg_component_info *)
1435 (*dinfo->mem->alloc_small)((j_common_ptr)dinfo, JPOOL_IMAGE,
DRC5de454b2014-05-18 19:04:03 +00001436 dinfo->num_components*sizeof(jpeg_component_info));
DRC34dca052014-02-28 09:17:14 +00001437
DRC2bdc0422014-03-07 03:52:57 +00001438 for(i=0; i<dinfo->num_components; i++)
DRC34dca052014-02-28 09:17:14 +00001439 {
DRC2bdc0422014-03-07 03:52:57 +00001440 jpeg_component_info *compptr=&dinfo->comp_info[i];
1441 compptr->h_samp_factor=(i==0)? tjMCUWidth[subsamp]/8:1;
1442 compptr->v_samp_factor=(i==0)? tjMCUHeight[subsamp]/8:1;
1443 compptr->component_index=i;
DRC15c08762014-03-10 20:11:56 +00001444 compptr->component_id=i+1;
DRC2bdc0422014-03-07 03:52:57 +00001445 compptr->quant_tbl_no=compptr->dc_tbl_no=compptr->ac_tbl_no=
1446 (i==0)? 0:1;
1447 dinfo->cur_comp_info[i]=compptr;
DRC34dca052014-02-28 09:17:14 +00001448 }
DRCc9014492014-03-10 09:34:04 +00001449 dinfo->data_precision=8;
1450 for(i=0; i<2; i++)
1451 {
1452 if(dinfo->quant_tbl_ptrs[i]==NULL)
1453 dinfo->quant_tbl_ptrs[i]=jpeg_alloc_quant_table((j_common_ptr)dinfo);
1454 }
DRC34dca052014-02-28 09:17:14 +00001455
1456 return 0;
1457}
1458
1459
1460int my_read_markers(j_decompress_ptr dinfo)
1461{
1462 return JPEG_REACHED_SOS;
1463}
1464
1465void my_reset_marker_reader(j_decompress_ptr dinfo)
1466{
1467}
1468
DRCaecea382014-08-11 18:05:41 +00001469DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
1470 unsigned char **srcPlanes, int *strides, int subsamp, unsigned char *dstBuf,
1471 int width, int pitch, int height, int pixelFormat, int flags)
DRC34dca052014-02-28 09:17:14 +00001472{
1473 int i, retval=0; JSAMPROW *row_pointer=NULL;
1474 JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1475 JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +00001476 int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001477 JSAMPLE *ptr;
DRC34dca052014-02-28 09:17:14 +00001478 jpeg_component_info *compptr;
1479 #ifndef JCS_EXTENSIONS
1480 unsigned char *rgbBuf=NULL;
DRC230d09d2014-04-20 09:42:49 +00001481 unsigned char *_dstBuf=NULL; int _pitch=0;
DRC34dca052014-02-28 09:17:14 +00001482 #endif
DRCbc56b752014-05-16 10:43:44 +00001483 int (*old_read_markers)(j_decompress_ptr);
1484 void (*old_reset_marker_reader)(j_decompress_ptr);
DRC34dca052014-02-28 09:17:14 +00001485
DRC41861622014-04-16 23:38:37 +00001486 getdinstance(handle);
DRC34dca052014-02-28 09:17:14 +00001487
1488 for(i=0; i<MAX_COMPONENTS; i++)
1489 {
1490 tmpbuf[i]=NULL; _tmpbuf[i]=NULL; inbuf[i]=NULL;
1491 }
1492
1493 if((this->init&DECOMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001494 _throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
DRC34dca052014-02-28 09:17:14 +00001495
DRCaecea382014-08-11 18:05:41 +00001496 if(!srcPlanes || !srcPlanes[0] || subsamp<0 || subsamp>=NUMSUBOPT
DRC34dca052014-02-28 09:17:14 +00001497 || dstBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
1498 || pixelFormat>=TJ_NUMPF)
DRCaecea382014-08-11 18:05:41 +00001499 _throw("tjDecodeYUVPlanes(): Invalid argument");
1500 if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1501 _throw("tjDecodeYUVPlanes(): Invalid argument");
DRC34dca052014-02-28 09:17:14 +00001502
1503 if(setjmp(this->jerr.setjmp_buffer))
1504 {
1505 /* If we get here, the JPEG code has signaled an error. */
1506 retval=-1;
1507 goto bailout;
1508 }
1509
1510 if(pixelFormat==TJPF_CMYK)
DRCaecea382014-08-11 18:05:41 +00001511 _throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
DRC34dca052014-02-28 09:17:14 +00001512
1513 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC34dca052014-02-28 09:17:14 +00001514 dinfo->image_width=width;
1515 dinfo->image_height=height;
1516
1517 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1518 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1519 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1520
DRC34dca052014-02-28 09:17:14 +00001521 if(setDecodeDefaults(dinfo, pixelFormat, subsamp, flags)==-1)
1522 {
1523 retval=-1; goto bailout;
1524 }
1525 old_read_markers=dinfo->marker->read_markers;
1526 dinfo->marker->read_markers=my_read_markers;
1527 old_reset_marker_reader=dinfo->marker->reset_marker_reader;
1528 dinfo->marker->reset_marker_reader=my_reset_marker_reader;
1529 jpeg_read_header(dinfo, TRUE);
1530 dinfo->marker->read_markers=old_read_markers;
1531 dinfo->marker->reset_marker_reader=old_reset_marker_reader;
1532
1533 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
1534 {
1535 retval=-1; goto bailout;
1536 }
DRC7d9f7582014-03-10 20:14:53 +00001537 dinfo->do_fancy_upsampling=FALSE;
DRC2bdc0422014-03-07 03:52:57 +00001538 jinit_master_decompress(dinfo);
DRC34dca052014-02-28 09:17:14 +00001539 (*dinfo->upsample->start_pass)(dinfo);
1540
DRC40dd3142014-08-17 12:23:49 +00001541 pw0=PAD(width, dinfo->max_h_samp_factor);
1542 ph0=PAD(height, dinfo->max_v_samp_factor);
DRC34dca052014-02-28 09:17:14 +00001543
1544 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
1545
DRC230d09d2014-04-20 09:42:49 +00001546 #ifndef JCS_EXTENSIONS
1547 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
1548 (RGB_RED!=tjRedOffset[pixelFormat] ||
1549 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1550 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1551 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1552 {
1553 rgbBuf=(unsigned char *)malloc(width*height*3);
DRCaecea382014-08-11 18:05:41 +00001554 if(!rgbBuf) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC230d09d2014-04-20 09:42:49 +00001555 _pitch=pitch; pitch=width*3;
1556 _dstBuf=dstBuf; dstBuf=rgbBuf;
1557 }
1558 #endif
1559
DRC40dd3142014-08-17 12:23:49 +00001560 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
DRCaecea382014-08-11 18:05:41 +00001561 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001562 for(i=0; i<height; i++)
1563 {
1564 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*pitch];
1565 else row_pointer[i]=&dstBuf[i*pitch];
1566 }
DRC40dd3142014-08-17 12:23:49 +00001567 if(height<ph0)
1568 for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
DRC34dca052014-02-28 09:17:14 +00001569
1570 for(i=0; i<dinfo->num_components; i++)
1571 {
1572 compptr=&dinfo->comp_info[i];
1573 _tmpbuf[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
1574 * compptr->v_samp_factor + 16);
DRCaecea382014-08-11 18:05:41 +00001575 if(!_tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001576 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCaecea382014-08-11 18:05:41 +00001577 if(!tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001578 for(row=0; row<compptr->v_samp_factor; row++)
1579 {
1580 unsigned char *_tmpbuf_aligned=
1581 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
1582 tmpbuf[i][row]=&_tmpbuf_aligned[
1583 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
1584 }
DRC40dd3142014-08-17 12:23:49 +00001585 pw[i]=pw0*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1586 ph[i]=ph0*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1587 inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
DRCaecea382014-08-11 18:05:41 +00001588 if(!inbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1589 ptr=srcPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001590 for(row=0; row<ph[i]; row++)
DRC34dca052014-02-28 09:17:14 +00001591 {
1592 inbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001593 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC34dca052014-02-28 09:17:14 +00001594 }
1595 }
1596
DRC40dd3142014-08-17 12:23:49 +00001597 for(row=0; row<ph0; row+=dinfo->max_v_samp_factor)
DRC34dca052014-02-28 09:17:14 +00001598 {
1599 JDIMENSION inrow=0, outrow=0;
1600 for(i=0, compptr=dinfo->comp_info; i<dinfo->num_components; i++, compptr++)
1601 jcopy_sample_rows(inbuf[i],
1602 row*compptr->v_samp_factor/dinfo->max_v_samp_factor, tmpbuf[i], 0,
DRC40dd3142014-08-17 12:23:49 +00001603 compptr->v_samp_factor, pw[i]);
DRC34dca052014-02-28 09:17:14 +00001604 (dinfo->upsample->upsample)(dinfo, tmpbuf, &inrow,
1605 dinfo->max_v_samp_factor, &row_pointer[row], &outrow,
1606 dinfo->max_v_samp_factor);
1607 }
1608 jpeg_abort_decompress(dinfo);
1609
DRC230d09d2014-04-20 09:42:49 +00001610 #ifndef JCS_EXTENSIONS
1611 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1612 #endif
1613
DRC34dca052014-02-28 09:17:14 +00001614 bailout:
1615 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1616 #ifndef JCS_EXTENSIONS
1617 if(rgbBuf) free(rgbBuf);
1618 #endif
1619 if(row_pointer) free(row_pointer);
1620 for(i=0; i<MAX_COMPONENTS; i++)
1621 {
1622 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
1623 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
1624 if(inbuf[i]!=NULL) free(inbuf[i]);
1625 }
1626 return retval;
1627}
1628
DRCaecea382014-08-11 18:05:41 +00001629DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, unsigned char *srcBuf,
1630 int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
1631 int height, int pixelFormat, int flags)
1632{
1633 unsigned char *srcPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001634 int pw0, ph0, strides[3], retval=-1;
DRC34dca052014-02-28 09:17:14 +00001635
DRCaecea382014-08-11 18:05:41 +00001636 if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT
1637 || width<=0 || height<=0)
1638 _throw("tjDecodeYUV(): Invalid argument");
1639
DRC40dd3142014-08-17 12:23:49 +00001640 pw0=tjPlaneWidth(0, width, subsamp);
1641 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +00001642 srcPlanes[0]=srcBuf;
DRC40dd3142014-08-17 12:23:49 +00001643 strides[0]=PAD(pw0, pad);
1644 if(subsamp==TJSAMP_GRAY)
1645 {
1646 strides[1]=strides[2]=0;
1647 srcPlanes[1]=srcPlanes[2]=NULL;
1648 }
1649 else
1650 {
1651 int pw1=tjPlaneWidth(1, width, subsamp);
1652 int ph1=tjPlaneHeight(1, height, subsamp);
1653 strides[1]=strides[2]=PAD(pw1, pad);
1654 srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1655 srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1656 }
DRCaecea382014-08-11 18:05:41 +00001657
1658 return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1659 pitch, height, pixelFormat, flags);
1660
1661 bailout:
1662 return retval;
1663}
1664
1665DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle,
1666 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char **dstPlanes,
1667 int width, int *strides, int height, int flags)
DRC9b28def2011-05-21 14:37:15 +00001668{
DRCf610d612013-04-26 10:33:29 +00001669 int i, sfi, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001670 int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
DRC40dd3142014-08-17 12:23:49 +00001671 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
DRC9b28def2011-05-21 14:37:15 +00001672 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001673 JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001674 int dctsize;
DRC9b28def2011-05-21 14:37:15 +00001675
DRC41861622014-04-16 23:38:37 +00001676 getdinstance(handle);
DRCb51ee892013-10-31 05:00:19 +00001677
DRCf9cf5c72010-12-10 10:58:49 +00001678 for(i=0; i<MAX_COMPONENTS; i++)
1679 {
1680 tmpbuf[i]=NULL; outbuf[i]=NULL;
1681 }
DRC9e17f7d2010-12-10 04:59:13 +00001682
DRCe2f8e692013-10-30 22:21:06 +00001683 if((this->init&DECOMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001684 _throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
DRCe2f8e692013-10-30 22:21:06 +00001685
DRCaecea382014-08-11 18:05:41 +00001686 if(jpegBuf==NULL || jpegSize<=0 || !dstPlanes || !dstPlanes[0] || width<0
1687 || height<0)
1688 _throw("tjDecompressToYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001689
DRC25b995a2011-05-21 15:34:54 +00001690 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1691 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1692 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +00001693
DRC9b28def2011-05-21 14:37:15 +00001694 if(setjmp(this->jerr.setjmp_buffer))
1695 {
1696 /* If we get here, the JPEG code has signaled an error. */
DRC91e86ba2011-02-15 05:24:08 +00001697 retval=-1;
1698 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +00001699 }
DRC2e7b76b2009-04-03 12:04:24 +00001700
DRCaecea382014-08-11 18:05:41 +00001701 if(!this->headerRead)
1702 {
1703 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1704 jpeg_read_header(dinfo, TRUE);
1705 }
1706 this->headerRead=0;
DRC418fe282013-05-07 21:17:35 +00001707 jpegSubsamp=getSubsamp(dinfo);
1708 if(jpegSubsamp<0)
DRCaecea382014-08-11 18:05:41 +00001709 _throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1710
1711 if(jpegSubsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1712 _throw("tjDecompressToYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001713
DRCf610d612013-04-26 10:33:29 +00001714 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1715 if(width==0) width=jpegwidth;
1716 if(height==0) height=jpegheight;
1717 for(i=0; i<NUMSF; i++)
1718 {
1719 scaledw=TJSCALED(jpegwidth, sf[i]);
1720 scaledh=TJSCALED(jpegheight, sf[i]);
1721 if(scaledw<=width && scaledh<=height)
1722 break;
1723 }
1724 if(scaledw>width || scaledh>height)
DRCaecea382014-08-11 18:05:41 +00001725 _throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
DRCcd7c3e62013-08-23 02:49:25 +00001726 if(dinfo->num_components>3)
DRCaecea382014-08-11 18:05:41 +00001727 _throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
DRCcd7c3e62013-08-23 02:49:25 +00001728
DRCf610d612013-04-26 10:33:29 +00001729 width=scaledw; height=scaledh;
1730 dinfo->scale_num=sf[i].num;
1731 dinfo->scale_denom=sf[i].denom;
1732 sfi=i;
1733 jpeg_calc_output_dimensions(dinfo);
1734
DRC418fe282013-05-07 21:17:35 +00001735 dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
1736
DRC9b28def2011-05-21 14:37:15 +00001737 for(i=0; i<dinfo->num_components; i++)
DRC2e7b76b2009-04-03 12:04:24 +00001738 {
DRC9b28def2011-05-21 14:37:15 +00001739 jpeg_component_info *compptr=&dinfo->comp_info[i];
1740 int ih;
DRC418fe282013-05-07 21:17:35 +00001741 iw[i]=compptr->width_in_blocks*dctsize;
1742 ih=compptr->height_in_blocks*dctsize;
DRC40dd3142014-08-17 12:23:49 +00001743 pw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001744 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001745 ph[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001746 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001747 if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
DRC418fe282013-05-07 21:17:35 +00001748 th[i]=compptr->v_samp_factor*dctsize;
DRC9b28def2011-05-21 14:37:15 +00001749 tmpbufsize+=iw[i]*th[i];
DRC40dd3142014-08-17 12:23:49 +00001750 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001751 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1752 ptr=dstPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001753 for(row=0; row<ph[i]; row++)
DRC9b28def2011-05-21 14:37:15 +00001754 {
1755 outbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001756 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC9b28def2011-05-21 14:37:15 +00001757 }
1758 }
1759 if(usetmpbuf)
1760 {
1761 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRCaecea382014-08-11 18:05:41 +00001762 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001763 ptr=_tmpbuf;
1764 for(i=0; i<dinfo->num_components; i++)
1765 {
1766 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001767 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001768 for(row=0; row<th[i]; row++)
1769 {
1770 tmpbuf[i][row]=ptr;
1771 ptr+=iw[i];
1772 }
1773 }
1774 }
DRC9e17f7d2010-12-10 04:59:13 +00001775
DRC25b995a2011-05-21 15:34:54 +00001776 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRCe0419b52012-07-03 20:01:31 +00001777 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
DRC9b28def2011-05-21 14:37:15 +00001778 dinfo->raw_data_out=TRUE;
1779
1780 jpeg_start_decompress(dinfo);
1781 for(row=0; row<(int)dinfo->output_height;
DRC418fe282013-05-07 21:17:35 +00001782 row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
DRC9b28def2011-05-21 14:37:15 +00001783 {
1784 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1785 int crow[MAX_COMPONENTS];
DRC9e17f7d2010-12-10 04:59:13 +00001786 for(i=0; i<dinfo->num_components; i++)
1787 {
1788 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRC418fe282013-05-07 21:17:35 +00001789 if(jpegSubsamp==TJ_420)
1790 {
1791 /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1792 to be clever and use the IDCT to perform upsampling on the U and V
1793 planes. For instance, if the output image is to be scaled by 1/2
1794 relative to the JPEG image, then the scaling factor and upsampling
1795 effectively cancel each other, so a normal 8x8 IDCT can be used.
1796 However, this is not desirable when using the decompress-to-YUV
1797 functionality in TurboJPEG, since we want to output the U and V
1798 planes in their subsampled form. Thus, we have to override some
1799 internal libjpeg parameters to force it to use the "scaled" IDCT
1800 functions on the U and V planes. */
1801 compptr->_DCT_scaled_size=dctsize;
1802 compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
1803 sf[sfi].num/sf[sfi].denom*
1804 compptr->v_samp_factor/dinfo->max_v_samp_factor;
1805 dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1806 }
DRC9b28def2011-05-21 14:37:15 +00001807 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1808 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1809 else yuvptr[i]=&outbuf[i][crow[i]];
DRCf9cf5c72010-12-10 10:58:49 +00001810 }
DRCf610d612013-04-26 10:33:29 +00001811 jpeg_read_raw_data(dinfo, yuvptr,
DRC418fe282013-05-07 21:17:35 +00001812 dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
DRCf9cf5c72010-12-10 10:58:49 +00001813 if(usetmpbuf)
1814 {
DRC9b28def2011-05-21 14:37:15 +00001815 int j;
DRCf9cf5c72010-12-10 10:58:49 +00001816 for(i=0; i<dinfo->num_components; i++)
1817 {
DRC40dd3142014-08-17 12:23:49 +00001818 for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +00001819 {
DRC40dd3142014-08-17 12:23:49 +00001820 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], pw[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001821 }
DRC9e17f7d2010-12-10 04:59:13 +00001822 }
1823 }
1824 }
DRC9b28def2011-05-21 14:37:15 +00001825 jpeg_finish_decompress(dinfo);
DRC2e7b76b2009-04-03 12:04:24 +00001826
DRC91e86ba2011-02-15 05:24:08 +00001827 bailout:
DRC9b28def2011-05-21 14:37:15 +00001828 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC9e17f7d2010-12-10 04:59:13 +00001829 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +00001830 {
1831 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +00001832 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001833 }
1834 if(_tmpbuf) free(_tmpbuf);
DRC91e86ba2011-02-15 05:24:08 +00001835 return retval;
DRC2e7b76b2009-04-03 12:04:24 +00001836}
1837
DRCaecea382014-08-11 18:05:41 +00001838DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
1839 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1840 int width, int pad, int height, int flags)
1841{
1842 unsigned char *dstPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001843 int pw0, ph0, strides[3], retval=-1, jpegSubsamp=-1;
DRCaecea382014-08-11 18:05:41 +00001844 int i, jpegwidth, jpegheight, scaledw, scaledh;
1845
1846 getdinstance(handle);
1847
1848 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
1849 || !isPow2(pad) || height<0)
1850 _throw("tjDecompressToYUV2(): Invalid argument");
1851
1852 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1853 jpeg_read_header(dinfo, TRUE);
1854 jpegSubsamp=getSubsamp(dinfo);
1855 if(jpegSubsamp<0)
1856 _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1857
1858 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1859 if(width==0) width=jpegwidth;
1860 if(height==0) height=jpegheight;
1861
1862 for(i=0; i<NUMSF; i++)
1863 {
1864 scaledw=TJSCALED(jpegwidth, sf[i]);
1865 scaledh=TJSCALED(jpegheight, sf[i]);
1866 if(scaledw<=width && scaledh<=height)
1867 break;
1868 }
1869 if(scaledw>width || scaledh>height)
1870 _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1871
DRC40dd3142014-08-17 12:23:49 +00001872 pw0=tjPlaneWidth(0, width, jpegSubsamp);
1873 ph0=tjPlaneHeight(0, height, jpegSubsamp);
DRCaecea382014-08-11 18:05:41 +00001874 dstPlanes[0]=dstBuf;
DRC40dd3142014-08-17 12:23:49 +00001875 strides[0]=PAD(pw0, pad);
1876 if(jpegSubsamp==TJSAMP_GRAY)
1877 {
1878 strides[1]=strides[2]=0;
1879 dstPlanes[1]=dstPlanes[2]=NULL;
1880 }
1881 else
1882 {
1883 int pw1=tjPlaneWidth(1, width, jpegSubsamp);
1884 int ph1=tjPlaneHeight(1, height, jpegSubsamp);
1885 strides[1]=strides[2]=PAD(pw1, pad);
1886 dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1887 dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1888 }
DRCaecea382014-08-11 18:05:41 +00001889
1890 this->headerRead=1;
1891 return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1892 strides, height, flags);
1893
1894 bailout:
1895 return retval;
1896
1897}
1898
DRCf610d612013-04-26 10:33:29 +00001899DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1900 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1901 int flags)
1902{
1903 return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1904}
1905
DRC2e7b76b2009-04-03 12:04:24 +00001906
DRC9b28def2011-05-21 14:37:15 +00001907/* Transformer */
DRC890f1e02011-02-26 22:02:37 +00001908
1909DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1910{
DRC9b28def2011-05-21 14:37:15 +00001911 tjinstance *this=NULL; tjhandle handle=NULL;
1912 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00001913 {
DRC007a42c2011-05-22 13:55:56 +00001914 snprintf(errStr, JMSG_LENGTH_MAX,
1915 "tjInitTransform(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00001916 return NULL;
1917 }
DRC007a42c2011-05-22 13:55:56 +00001918 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +00001919 handle=_tjInitCompress(this);
1920 if(!handle) return NULL;
1921 handle=_tjInitDecompress(this);
1922 return handle;
DRC890f1e02011-02-26 22:02:37 +00001923}
1924
1925
DRC9b28def2011-05-21 14:37:15 +00001926DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1927 unsigned long jpegSize, int n, unsigned char **dstBufs,
1928 unsigned long *dstSizes, tjtransform *t, int flags)
DRC890f1e02011-02-26 22:02:37 +00001929{
DRC0a325192011-03-02 09:22:41 +00001930 jpeg_transform_info *xinfo=NULL;
DRC890f1e02011-02-26 22:02:37 +00001931 jvirt_barray_ptr *srccoefs, *dstcoefs;
DRC9b49f0e2011-07-12 03:17:23 +00001932 int retval=0, i, jpegSubsamp;
DRC890f1e02011-02-26 22:02:37 +00001933
DRC9b28def2011-05-21 14:37:15 +00001934 getinstance(handle);
1935 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001936 _throw("tjTransform(): Instance has not been initialized for transformation");
DRC890f1e02011-02-26 22:02:37 +00001937
DRC9b28def2011-05-21 14:37:15 +00001938 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1939 || t==NULL || flags<0)
1940 _throw("tjTransform(): Invalid argument");
1941
DRC25b995a2011-05-21 15:34:54 +00001942 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1943 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1944 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC890f1e02011-02-26 22:02:37 +00001945
DRC9b28def2011-05-21 14:37:15 +00001946 if(setjmp(this->jerr.setjmp_buffer))
1947 {
1948 /* If we get here, the JPEG code has signaled an error. */
DRC890f1e02011-02-26 22:02:37 +00001949 retval=-1;
1950 goto bailout;
1951 }
1952
DRC9b28def2011-05-21 14:37:15 +00001953 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
DRC890f1e02011-02-26 22:02:37 +00001954
DRC0a325192011-03-02 09:22:41 +00001955 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1956 ==NULL)
DRC007a42c2011-05-22 13:55:56 +00001957 _throw("tjTransform(): Memory allocation failure");
1958 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
DRC890f1e02011-02-26 22:02:37 +00001959
DRC0a325192011-03-02 09:22:41 +00001960 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001961 {
DRC0a325192011-03-02 09:22:41 +00001962 xinfo[i].transform=xformtypes[t[i].op];
DRC25b995a2011-05-21 15:34:54 +00001963 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1964 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1965 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1966 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1967 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
DRCba5ea512011-03-04 03:20:34 +00001968 else xinfo[i].slow_hflip=0;
DRC0a325192011-03-02 09:22:41 +00001969
1970 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001971 {
DRC0a325192011-03-02 09:22:41 +00001972 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
1973 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
1974 if(t[i].r.w!=0)
1975 {
1976 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
1977 }
DRCd932e582011-03-15 20:09:47 +00001978 else xinfo[i].crop_width=JCROP_UNSET;
DRC0a325192011-03-02 09:22:41 +00001979 if(t[i].r.h!=0)
1980 {
1981 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
1982 }
DRCd932e582011-03-15 20:09:47 +00001983 else xinfo[i].crop_height=JCROP_UNSET;
DRC890f1e02011-02-26 22:02:37 +00001984 }
1985 }
1986
DRC9b28def2011-05-21 14:37:15 +00001987 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1988 jpeg_read_header(dinfo, TRUE);
DRC9b49f0e2011-07-12 03:17:23 +00001989 jpegSubsamp=getSubsamp(dinfo);
1990 if(jpegSubsamp<0)
1991 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC890f1e02011-02-26 22:02:37 +00001992
DRC0a325192011-03-02 09:22:41 +00001993 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001994 {
DRC9b28def2011-05-21 14:37:15 +00001995 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
DRC007a42c2011-05-22 13:55:56 +00001996 _throw("tjTransform(): Transform is not perfect");
DRC890f1e02011-02-26 22:02:37 +00001997
DRC0a325192011-03-02 09:22:41 +00001998 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001999 {
DRC0a325192011-03-02 09:22:41 +00002000 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
2001 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
2002 {
DRC9b28def2011-05-21 14:37:15 +00002003 snprintf(errStr, JMSG_LENGTH_MAX,
DRC0a325192011-03-02 09:22:41 +00002004 "To crop this JPEG image, x must be a multiple of %d\n"
2005 "and y must be a multiple of %d.\n",
2006 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
2007 retval=-1; goto bailout;
2008 }
DRC890f1e02011-02-26 22:02:37 +00002009 }
2010 }
2011
DRC9b28def2011-05-21 14:37:15 +00002012 srccoefs=jpeg_read_coefficients(dinfo);
DRC890f1e02011-02-26 22:02:37 +00002013
DRC0a325192011-03-02 09:22:41 +00002014 for(i=0; i<n; i++)
2015 {
DRCff78e372011-05-24 10:17:32 +00002016 int w, h, alloc=1;
DRC0a325192011-03-02 09:22:41 +00002017 if(!xinfo[i].crop)
2018 {
DRC9b28def2011-05-21 14:37:15 +00002019 w=dinfo->image_width; h=dinfo->image_height;
DRC0a325192011-03-02 09:22:41 +00002020 }
2021 else
2022 {
2023 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
2024 }
DRCff78e372011-05-24 10:17:32 +00002025 if(flags&TJFLAG_NOREALLOC)
2026 {
DRC9b49f0e2011-07-12 03:17:23 +00002027 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +00002028 }
DRC7bf04d32011-09-17 00:18:31 +00002029 if(!(t[i].options&TJXOPT_NOOUTPUT))
2030 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
DRC9b28def2011-05-21 14:37:15 +00002031 jpeg_copy_critical_parameters(dinfo, cinfo);
2032 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00002033 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00002034 if(!(t[i].options&TJXOPT_NOOUTPUT))
2035 {
2036 jpeg_write_coefficients(cinfo, dstcoefs);
2037 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
2038 }
2039 else jinit_c_master_control(cinfo, TRUE);
DRC9b28def2011-05-21 14:37:15 +00002040 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00002041 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00002042 if(t[i].customFilter)
2043 {
DRCefe28ce2012-01-17 11:48:38 +00002044 int ci, y; JDIMENSION by;
DRC7bf04d32011-09-17 00:18:31 +00002045 for(ci=0; ci<cinfo->num_components; ci++)
2046 {
2047 jpeg_component_info *compptr=&cinfo->comp_info[ci];
2048 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2049 DCTSIZE};
2050 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2051 compptr->height_in_blocks*DCTSIZE};
2052 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
2053 {
2054 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
2055 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
2056 TRUE);
2057 for(y=0; y<compptr->v_samp_factor; y++)
2058 {
2059 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
DRCf5467112011-09-20 05:02:19 +00002060 ci, i, &t[i])==-1)
DRC7bf04d32011-09-17 00:18:31 +00002061 _throw("tjTransform(): Error in custom filter");
2062 arrayRegion.y+=DCTSIZE;
2063 }
2064 }
2065 }
2066 }
2067 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
DRC0a325192011-03-02 09:22:41 +00002068 }
2069
DRC9b28def2011-05-21 14:37:15 +00002070 jpeg_finish_decompress(dinfo);
DRC890f1e02011-02-26 22:02:37 +00002071
DRC890f1e02011-02-26 22:02:37 +00002072 bailout:
DRC9b28def2011-05-21 14:37:15 +00002073 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
2074 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC0a325192011-03-02 09:22:41 +00002075 if(xinfo) free(xinfo);
DRC890f1e02011-02-26 22:02:37 +00002076 return retval;
2077}