blob: bc153da96843837b098b25062f26bd83a405f105 [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;
DRCea1eea42014-11-19 00:55:28 +0000319
320 /* The sampling factors actually have no meaning with grayscale JPEG files,
321 and in fact it's possible to generate grayscale JPEGs with sampling
322 factors > 1 (even though those sampling factors are ignored by the
323 decompressor.) Thus, we need to treat grayscale as a special case. */
324 if(dinfo->num_components==1 && dinfo->jpeg_color_space==JCS_GRAYSCALE)
325 return TJSAMP_GRAY;
326
DRC9b49f0e2011-07-12 03:17:23 +0000327 for(i=0; i<NUMSUBOPT; i++)
328 {
DRCcd7c3e62013-08-23 02:49:25 +0000329 if(dinfo->num_components==pixelsize[i]
330 || ((dinfo->jpeg_color_space==JCS_YCCK
331 || dinfo->jpeg_color_space==JCS_CMYK)
332 && pixelsize[i]==3 && dinfo->num_components==4))
DRC9b49f0e2011-07-12 03:17:23 +0000333 {
334 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
335 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
336 {
337 int match=0;
338 for(k=1; k<dinfo->num_components; k++)
339 {
DRCcd7c3e62013-08-23 02:49:25 +0000340 int href=1, vref=1;
341 if(dinfo->jpeg_color_space==JCS_YCCK && k==3)
342 {
343 href=tjMCUWidth[i]/8; vref=tjMCUHeight[i]/8;
344 }
345 if(dinfo->comp_info[k].h_samp_factor==href
346 && dinfo->comp_info[k].v_samp_factor==vref)
DRC9b49f0e2011-07-12 03:17:23 +0000347 match++;
348 }
349 if(match==dinfo->num_components-1)
350 {
351 retval=i; break;
352 }
353 }
354 }
355 }
356 return retval;
357}
358
359
DRCafc06922012-03-23 19:47:57 +0000360#ifndef JCS_EXTENSIONS
361
362/* Conversion functions to emulate the colorspace extensions. This allows the
363 TurboJPEG wrapper to be used with libjpeg */
364
365#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
366 int rowPad=pitch-width*PS; \
367 while(height--) \
368 { \
369 unsigned char *endOfRow=src+width*PS; \
370 while(src<endOfRow) \
371 { \
372 dst[RGB_RED]=src[ROFFSET]; \
373 dst[RGB_GREEN]=src[GOFFSET]; \
374 dst[RGB_BLUE]=src[BOFFSET]; \
375 dst+=RGB_PIXELSIZE; src+=PS; \
376 } \
377 src+=rowPad; \
378 } \
379}
380
381static unsigned char *toRGB(unsigned char *src, int width, int pitch,
382 int height, int pixelFormat, unsigned char *dst)
383{
384 unsigned char *retval=src;
385 switch(pixelFormat)
386 {
387 case TJPF_RGB:
388 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
389 retval=dst; TORGB(3, 0, 1, 2);
390 #endif
391 break;
392 case TJPF_BGR:
393 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
394 retval=dst; TORGB(3, 2, 1, 0);
395 #endif
396 break;
397 case TJPF_RGBX:
398 case TJPF_RGBA:
399 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
400 retval=dst; TORGB(4, 0, 1, 2);
401 #endif
402 break;
403 case TJPF_BGRX:
404 case TJPF_BGRA:
405 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
406 retval=dst; TORGB(4, 2, 1, 0);
407 #endif
408 break;
409 case TJPF_XRGB:
410 case TJPF_ARGB:
411 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
412 retval=dst; TORGB(4, 1, 2, 3);
413 #endif
414 break;
415 case TJPF_XBGR:
416 case TJPF_ABGR:
417 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
418 retval=dst; TORGB(4, 3, 2, 1);
419 #endif
420 break;
421 }
422 return retval;
423}
424
425#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
426 int rowPad=pitch-width*PS; \
427 while(height--) \
428 { \
429 unsigned char *endOfRow=dst+width*PS; \
430 while(dst<endOfRow) \
431 { \
432 dst[ROFFSET]=src[RGB_RED]; \
433 dst[GOFFSET]=src[RGB_GREEN]; \
434 dst[BOFFSET]=src[RGB_BLUE]; \
435 SETALPHA \
436 dst+=PS; src+=RGB_PIXELSIZE; \
437 } \
438 dst+=rowPad; \
439 } \
440}
441
442static void fromRGB(unsigned char *src, unsigned char *dst, int width,
443 int pitch, int height, int pixelFormat)
444{
445 switch(pixelFormat)
446 {
447 case TJPF_RGB:
448 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
449 FROMRGB(3, 0, 1, 2,);
450 #endif
451 break;
452 case TJPF_BGR:
453 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
454 FROMRGB(3, 2, 1, 0,);
455 #endif
456 break;
457 case TJPF_RGBX:
458 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
459 FROMRGB(4, 0, 1, 2,);
460 #endif
461 break;
462 case TJPF_RGBA:
463 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
464 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
465 #endif
466 break;
467 case TJPF_BGRX:
468 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
469 FROMRGB(4, 2, 1, 0,);
470 #endif
471 break;
472 case TJPF_BGRA:
473 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
474 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
475 #endif
476 break;
477 case TJPF_XRGB:
478 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
479 FROMRGB(4, 1, 2, 3,); return;
480 #endif
481 break;
482 case TJPF_ARGB:
483 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
484 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
485 #endif
486 break;
487 case TJPF_XBGR:
488 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
489 FROMRGB(4, 3, 2, 1,); return;
490 #endif
491 break;
492 case TJPF_ABGR:
493 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
494 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
495 #endif
496 break;
497 }
498}
499
500#endif
501
502
DRC9b28def2011-05-21 14:37:15 +0000503/* General API functions */
504
505DLLEXPORT char* DLLCALL tjGetErrorStr(void)
506{
507 return errStr;
508}
509
510
511DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
512{
513 getinstance(handle);
514 if(setjmp(this->jerr.setjmp_buffer)) return -1;
515 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
516 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
517 free(this);
518 return 0;
519}
520
521
DRC6b76f752011-05-24 16:52:47 +0000522/* These are exposed mainly because Windows can't malloc() and free() across
523 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
524 with turbojpeg.dll for compatibility reasons. However, these functions
525 can potentially be used for other purposes by different implementations. */
526
527DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
528{
529 if(buf) free(buf);
530}
531
532
533DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
534{
535 return (unsigned char *)malloc(bytes);
536}
537
538
DRC9b28def2011-05-21 14:37:15 +0000539/* Compressor */
540
541static tjhandle _tjInitCompress(tjinstance *this)
542{
543 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
544
545 /* This is also straight out of example.c */
546 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
547 this->jerr.pub.error_exit=my_error_exit;
548 this->jerr.pub.output_message=my_output_message;
549
550 if(setjmp(this->jerr.setjmp_buffer))
551 {
552 /* If we get here, the JPEG code has signaled an error. */
553 if(this) free(this); return NULL;
554 }
555
556 jpeg_create_compress(&this->cinfo);
557 /* Make an initial call so it will create the destination manager */
558 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
559
DRC007a42c2011-05-22 13:55:56 +0000560 this->init|=COMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000561 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000562}
563
DRC890f1e02011-02-26 22:02:37 +0000564DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
565{
DRC9b28def2011-05-21 14:37:15 +0000566 tjinstance *this=NULL;
567 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000568 {
DRC007a42c2011-05-22 13:55:56 +0000569 snprintf(errStr, JMSG_LENGTH_MAX,
570 "tjInitCompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000571 return NULL;
572 }
DRC007a42c2011-05-22 13:55:56 +0000573 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000574 return _tjInitCompress(this);
DRC890f1e02011-02-26 22:02:37 +0000575}
576
DRC84241602011-02-25 02:08:23 +0000577
DRC9b49f0e2011-07-12 03:17:23 +0000578DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
579 int jpegSubsamp)
580{
581 unsigned long retval=0; int mcuw, mcuh, chromasf;
582 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
583 _throw("tjBufSize(): Invalid argument");
584
DRC006bc582014-02-27 21:22:54 +0000585 /* This allows for rare corner cases in which a JPEG image can actually be
586 larger than the uncompressed input (we wouldn't mention it if it hadn't
587 happened before.) */
DRC9b49f0e2011-07-12 03:17:23 +0000588 mcuw=tjMCUWidth[jpegSubsamp];
589 mcuh=tjMCUHeight[jpegSubsamp];
590 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
591 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
592
593 bailout:
594 return retval;
595}
596
DRC2e7b76b2009-04-03 12:04:24 +0000597DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
598{
DRCf3cf9732011-02-22 00:16:14 +0000599 unsigned long retval=0;
600 if(width<1 || height<1)
DRC007a42c2011-05-22 13:55:56 +0000601 _throw("TJBUFSIZE(): Invalid argument");
DRCf3cf9732011-02-22 00:16:14 +0000602
DRC006bc582014-02-27 21:22:54 +0000603 /* This allows for rare corner cases in which a JPEG image can actually be
604 larger than the uncompressed input (we wouldn't mention it if it hadn't
605 happened before.) */
DRC007a42c2011-05-22 13:55:56 +0000606 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
DRCf3cf9732011-02-22 00:16:14 +0000607
608 bailout:
609 return retval;
610}
611
DRC84241602011-02-25 02:08:23 +0000612
DRCf610d612013-04-26 10:33:29 +0000613DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
DRCf3cf9732011-02-22 00:16:14 +0000614 int subsamp)
615{
DRC40dd3142014-08-17 12:23:49 +0000616 int retval=0, nc, i;
617
618 if(subsamp<0 || subsamp>=NUMSUBOPT)
DRCf610d612013-04-26 10:33:29 +0000619 _throw("tjBufSizeYUV2(): Invalid argument");
DRC40dd3142014-08-17 12:23:49 +0000620
621 nc=(subsamp==TJSAMP_GRAY? 1:3);
622 for(i=0; i<nc; i++)
623 {
DRC55620c62014-10-23 19:08:14 +0000624 int pw=tjPlaneWidth(i, width, subsamp);
625 int stride=PAD(pw, pad);
DRC40dd3142014-08-17 12:23:49 +0000626 int ph=tjPlaneHeight(i, height, subsamp);
DRC55620c62014-10-23 19:08:14 +0000627 if(pw<0 || ph<0) return -1;
DRC40dd3142014-08-17 12:23:49 +0000628 else retval+=stride*ph;
629 }
DRCf3cf9732011-02-22 00:16:14 +0000630
631 bailout:
632 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000633}
634
DRCf610d612013-04-26 10:33:29 +0000635DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
636 int subsamp)
637{
638 return tjBufSizeYUV2(width, 4, height, subsamp);
639}
DRC84241602011-02-25 02:08:23 +0000640
DRC9b49f0e2011-07-12 03:17:23 +0000641DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
642 int subsamp)
643{
644 return tjBufSizeYUV(width, height, subsamp);
645}
646
647
DRC40dd3142014-08-17 12:23:49 +0000648DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
649{
650 int pw, nc, retval=0;
651
652 if(width<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
653 _throw("tjPlaneWidth(): Invalid argument");
654 nc=(subsamp==TJSAMP_GRAY? 1:3);
655 if(componentID<0 || componentID>=nc)
656 _throw("tjPlaneWidth(): Invalid argument");
657
658 pw=PAD(width, tjMCUWidth[subsamp]/8);
659 if(componentID==0)
660 retval=pw;
661 else
662 retval=pw*8/tjMCUWidth[subsamp];
663
664 bailout:
665 return retval;
666}
667
668
669DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
670{
671 int ph, nc, retval=0;
672
673 if(height<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
674 _throw("tjPlaneHeight(): Invalid argument");
675 nc=(subsamp==TJSAMP_GRAY? 1:3);
676 if(componentID<0 || componentID>=nc)
677 _throw("tjPlaneHeight(): Invalid argument");
678
679 ph=PAD(height, tjMCUHeight[subsamp]/8);
680 if(componentID==0)
681 retval=ph;
682 else
683 retval=ph*8/tjMCUHeight[subsamp];
684
685 bailout:
686 return retval;
687}
688
689
690DLLEXPORT unsigned long DLLCALL tjPlaneSizeYUV(int componentID, int width,
691 int stride, int height, int subsamp)
692{
693 unsigned long retval=0;
694 int pw, ph;
695
696 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
697 _throw("tjPlaneSizeYUV(): Invalid argument");
698
699 pw=tjPlaneWidth(componentID, width, subsamp);
700 ph=tjPlaneHeight(componentID, height, subsamp);
DRC22409742014-10-23 18:54:42 +0000701 if(pw<0 || ph<0) return -1;
DRC40dd3142014-08-17 12:23:49 +0000702
703 if(stride==0) stride=pw;
704 else stride=abs(stride);
705
706 retval=stride*(ph-1)+pw;
707
708 bailout:
709 return retval;
710}
711
712
DRC9b28def2011-05-21 14:37:15 +0000713DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
714 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
715 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
716{
DRCff78e372011-05-24 10:17:32 +0000717 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
DRCafc06922012-03-23 19:47:57 +0000718 #ifndef JCS_EXTENSIONS
719 unsigned char *rgbBuf=NULL;
720 #endif
DRC9b28def2011-05-21 14:37:15 +0000721
DRC41861622014-04-16 23:38:37 +0000722 getcinstance(handle)
DRC9b28def2011-05-21 14:37:15 +0000723 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000724 _throw("tjCompress2(): Instance has not been initialized for compression");
DRC9b28def2011-05-21 14:37:15 +0000725
726 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
727 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
728 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
DRC007a42c2011-05-22 13:55:56 +0000729 _throw("tjCompress2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000730
731 if(setjmp(this->jerr.setjmp_buffer))
732 {
733 /* If we get here, the JPEG code has signaled an error. */
734 retval=-1;
735 goto bailout;
736 }
737
738 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
739
DRCafc06922012-03-23 19:47:57 +0000740 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +0000741 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
DRCafc06922012-03-23 19:47:57 +0000742 {
743 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
744 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
745 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
746 pitch=width*RGB_PIXELSIZE;
747 }
748 #endif
749
DRC9b28def2011-05-21 14:37:15 +0000750 cinfo->image_width=width;
751 cinfo->image_height=height;
752
DRC25b995a2011-05-21 15:34:54 +0000753 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
754 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
755 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000756
DRCff78e372011-05-24 10:17:32 +0000757 if(flags&TJFLAG_NOREALLOC)
758 {
DRC9b49f0e2011-07-12 03:17:23 +0000759 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +0000760 }
761 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
DRC73d74c12012-06-29 23:46:38 +0000762 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
DRCf12bb302011-09-07 05:03:18 +0000763 return -1;
DRC9b28def2011-05-21 14:37:15 +0000764
765 jpeg_start_compress(cinfo, TRUE);
766 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000767 _throw("tjCompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000768 for(i=0; i<height; i++)
769 {
DRC25b995a2011-05-21 15:34:54 +0000770 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000771 else row_pointer[i]=&srcBuf[i*pitch];
772 }
773 while(cinfo->next_scanline<cinfo->image_height)
774 {
775 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
776 cinfo->image_height-cinfo->next_scanline);
777 }
778 jpeg_finish_compress(cinfo);
779
780 bailout:
781 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000782 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000783 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000784 #endif
DRC9b28def2011-05-21 14:37:15 +0000785 if(row_pointer) free(row_pointer);
786 return retval;
787}
788
789DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
790 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
791 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
792{
793 int retval=0; unsigned long size;
794 if(flags&TJ_YUV)
795 {
DRC9b49f0e2011-07-12 03:17:23 +0000796 size=tjBufSizeYUV(width, height, jpegSubsamp);
DRC9b28def2011-05-21 14:37:15 +0000797 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
798 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
799 }
800 else
801 {
DRC9b28def2011-05-21 14:37:15 +0000802 retval=tjCompress2(handle, srcBuf, width, pitch, height,
803 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
DRC25b995a2011-05-21 15:34:54 +0000804 flags|TJFLAG_NOREALLOC);
DRC9b28def2011-05-21 14:37:15 +0000805 }
806 *jpegSize=size;
807 return retval;
808}
809
810
DRCaecea382014-08-11 18:05:41 +0000811DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle, unsigned char *srcBuf,
812 int width, int pitch, int height, int pixelFormat, unsigned char **dstPlanes,
813 int *strides, int subsamp, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000814{
DRC91e86ba2011-02-15 05:24:08 +0000815 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000816 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
817 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
818 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +0000819 int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +0000820 JSAMPLE *ptr;
DRC9b28def2011-05-21 14:37:15 +0000821 jpeg_component_info *compptr;
DRCafc06922012-03-23 19:47:57 +0000822 #ifndef JCS_EXTENSIONS
823 unsigned char *rgbBuf=NULL;
824 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000825
DRC41861622014-04-16 23:38:37 +0000826 getcinstance(handle);
DRCb51ee892013-10-31 05:00:19 +0000827
DRCfbb67472010-11-24 04:02:37 +0000828 for(i=0; i<MAX_COMPONENTS; i++)
829 {
830 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
831 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
832 }
833
DRCe2f8e692013-10-30 22:21:06 +0000834 if((this->init&COMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +0000835 _throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
DRCe2f8e692013-10-30 22:21:06 +0000836
DRC9b28def2011-05-21 14:37:15 +0000837 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
DRCaecea382014-08-11 18:05:41 +0000838 || pixelFormat>=TJ_NUMPF || !dstPlanes || !dstPlanes[0] || subsamp<0
839 || subsamp>=NUMSUBOPT)
840 _throw("tjEncodeYUVPlanes(): Invalid argument");
841 if(subsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
842 _throw("tjEncodeYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000843
DRC9b28def2011-05-21 14:37:15 +0000844 if(setjmp(this->jerr.setjmp_buffer))
845 {
846 /* If we get here, the JPEG code has signaled an error. */
847 retval=-1;
848 goto bailout;
849 }
DRC2e7b76b2009-04-03 12:04:24 +0000850
DRCcd7c3e62013-08-23 02:49:25 +0000851 if(pixelFormat==TJPF_CMYK)
DRCaecea382014-08-11 18:05:41 +0000852 _throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
DRCcd7c3e62013-08-23 02:49:25 +0000853
DRC9b28def2011-05-21 14:37:15 +0000854 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC2e7b76b2009-04-03 12:04:24 +0000855
DRCafc06922012-03-23 19:47:57 +0000856 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +0000857 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
DRCafc06922012-03-23 19:47:57 +0000858 {
859 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
DRCaecea382014-08-11 18:05:41 +0000860 if(!rgbBuf) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRCafc06922012-03-23 19:47:57 +0000861 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
862 pitch=width*RGB_PIXELSIZE;
863 }
864 #endif
865
DRC9b28def2011-05-21 14:37:15 +0000866 cinfo->image_width=width;
867 cinfo->image_height=height;
DRC2e7b76b2009-04-03 12:04:24 +0000868
DRC25b995a2011-05-21 15:34:54 +0000869 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
870 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
871 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000872
DRC73d74c12012-06-29 23:46:38 +0000873 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000874
DRC38c99702014-02-11 09:45:18 +0000875 /* Execute only the parts of jpeg_start_compress() that we need. If we
876 were to call the whole jpeg_start_compress() function, then it would try
877 to write the file headers, which could overflow the output buffer if the
878 YUV image were very small. */
879 if(cinfo->global_state!=CSTATE_START)
DRCaecea382014-08-11 18:05:41 +0000880 _throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
DRC38c99702014-02-11 09:45:18 +0000881 (*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
DRC38c99702014-02-11 09:45:18 +0000882 jinit_c_master_control(cinfo, FALSE);
883 jinit_color_converter(cinfo);
884 jinit_downsampler(cinfo);
DRC50cfc462014-03-06 20:03:37 +0000885 (*cinfo->cconvert->start_pass)(cinfo);
DRC38c99702014-02-11 09:45:18 +0000886
DRC40dd3142014-08-17 12:23:49 +0000887 pw0=PAD(width, cinfo->max_h_samp_factor);
888 ph0=PAD(height, cinfo->max_v_samp_factor);
DRC2e7b76b2009-04-03 12:04:24 +0000889
DRC40dd3142014-08-17 12:23:49 +0000890 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
DRCaecea382014-08-11 18:05:41 +0000891 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000892 for(i=0; i<height; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000893 {
DRC25b995a2011-05-21 15:34:54 +0000894 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
DRC9b28def2011-05-21 14:37:15 +0000895 else row_pointer[i]=&srcBuf[i*pitch];
896 }
DRC40dd3142014-08-17 12:23:49 +0000897 if(height<ph0)
898 for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
DRCfbb67472010-11-24 04:02:37 +0000899
DRC9b28def2011-05-21 14:37:15 +0000900 for(i=0; i<cinfo->num_components; i++)
901 {
902 compptr=&cinfo->comp_info[i];
903 _tmpbuf[i]=(JSAMPLE *)malloc(
904 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
905 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRCaecea382014-08-11 18:05:41 +0000906 if(!_tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000907 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRCaecea382014-08-11 18:05:41 +0000908 if(!tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000909 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRCfbb67472010-11-24 04:02:37 +0000910 {
DRC9b28def2011-05-21 14:37:15 +0000911 unsigned char *_tmpbuf_aligned=
912 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
913 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000914 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC9b28def2011-05-21 14:37:15 +0000915 /compptr->h_samp_factor, 16) * row];
DRCfbb67472010-11-24 04:02:37 +0000916 }
DRC9b28def2011-05-21 14:37:15 +0000917 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
918 * compptr->v_samp_factor + 16);
DRCaecea382014-08-11 18:05:41 +0000919 if(!_tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000920 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCaecea382014-08-11 18:05:41 +0000921 if(!tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000922 for(row=0; row<compptr->v_samp_factor; row++)
923 {
924 unsigned char *_tmpbuf2_aligned=
925 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
926 tmpbuf2[i][row]=&_tmpbuf2_aligned[
927 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
928 }
DRC40dd3142014-08-17 12:23:49 +0000929 pw[i]=pw0*compptr->h_samp_factor/cinfo->max_h_samp_factor;
930 ph[i]=ph0*compptr->v_samp_factor/cinfo->max_v_samp_factor;
931 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
DRCaecea382014-08-11 18:05:41 +0000932 if(!outbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
933 ptr=dstPlanes[i];
DRC40dd3142014-08-17 12:23:49 +0000934 for(row=0; row<ph[i]; row++)
DRC9b28def2011-05-21 14:37:15 +0000935 {
936 outbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +0000937 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC9b28def2011-05-21 14:37:15 +0000938 }
939 }
DRCfbb67472010-11-24 04:02:37 +0000940
DRC40dd3142014-08-17 12:23:49 +0000941 for(row=0; row<ph0; row+=cinfo->max_v_samp_factor)
DRCfbb67472010-11-24 04:02:37 +0000942 {
DRC9b28def2011-05-21 14:37:15 +0000943 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
944 cinfo->max_v_samp_factor);
945 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
946 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
947 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
948 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
DRC40dd3142014-08-17 12:23:49 +0000949 compptr->v_samp_factor, pw[i]);
DRC6ee54592011-03-01 08:18:30 +0000950 }
DRC9b28def2011-05-21 14:37:15 +0000951 cinfo->next_scanline+=height;
952 jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000953
DRC91e86ba2011-02-15 05:24:08 +0000954 bailout:
DRC9b28def2011-05-21 14:37:15 +0000955 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000956 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000957 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000958 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000959 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000960 for(i=0; i<MAX_COMPONENTS; i++)
961 {
962 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000963 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000964 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000965 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000966 if(outbuf[i]!=NULL) free(outbuf[i]);
967 }
DRC91e86ba2011-02-15 05:24:08 +0000968 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000969}
970
DRCaecea382014-08-11 18:05:41 +0000971DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle, unsigned char *srcBuf,
972 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
973 int pad, int subsamp, int flags)
974{
975 unsigned char *dstPlanes[3];
DRC40dd3142014-08-17 12:23:49 +0000976 int pw0, ph0, strides[3], retval=-1;
DRCaecea382014-08-11 18:05:41 +0000977
978 if(width<=0 || height<=0 || dstBuf==NULL || pad<0 || !isPow2(pad)
979 || subsamp<0 || subsamp>=NUMSUBOPT)
980 _throw("tjEncodeYUV3(): Invalid argument");
981
DRC40dd3142014-08-17 12:23:49 +0000982 pw0=tjPlaneWidth(0, width, subsamp);
983 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +0000984 dstPlanes[0]=dstBuf;
DRC40dd3142014-08-17 12:23:49 +0000985 strides[0]=PAD(pw0, pad);
986 if(subsamp==TJSAMP_GRAY)
987 {
988 strides[1]=strides[2]=0;
989 dstPlanes[1]=dstPlanes[2]=NULL;
990 }
991 else
992 {
993 int pw1=tjPlaneWidth(1, width, subsamp);
994 int ph1=tjPlaneHeight(1, height, subsamp);
995 strides[1]=strides[2]=PAD(pw1, pad);
996 dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
997 dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
998 }
DRCaecea382014-08-11 18:05:41 +0000999
1000 return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
1001 dstPlanes, strides, subsamp, flags);
1002
1003 bailout:
1004 return retval;
1005}
1006
DRCf610d612013-04-26 10:33:29 +00001007DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
1008 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
1009 int subsamp, int flags)
1010{
1011 return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
1012 dstBuf, 4, subsamp, flags);
1013}
1014
DRC9b28def2011-05-21 14:37:15 +00001015DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
1016 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
1017 int subsamp, int flags)
DRC84241602011-02-25 02:08:23 +00001018{
DRC9b28def2011-05-21 14:37:15 +00001019 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1020 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
DRC84241602011-02-25 02:08:23 +00001021}
1022
1023
DRCaecea382014-08-11 18:05:41 +00001024DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle,
1025 unsigned char **srcPlanes, int width, int *strides, int height, int subsamp,
1026 unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)
DRC910a3572013-10-30 23:02:57 +00001027{
1028 int i, row, retval=0, alloc=1; JSAMPROW *inbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +00001029 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
DRC910a3572013-10-30 23:02:57 +00001030 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001031 JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC910a3572013-10-30 23:02:57 +00001032
DRC41861622014-04-16 23:38:37 +00001033 getcinstance(handle)
DRCb51ee892013-10-31 05:00:19 +00001034
DRC910a3572013-10-30 23:02:57 +00001035 for(i=0; i<MAX_COMPONENTS; i++)
1036 {
1037 tmpbuf[i]=NULL; inbuf[i]=NULL;
1038 }
1039
DRC910a3572013-10-30 23:02:57 +00001040 if((this->init&COMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001041 _throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
DRC910a3572013-10-30 23:02:57 +00001042
DRCaecea382014-08-11 18:05:41 +00001043 if(!srcPlanes || !srcPlanes[0] || width<=0 || height<=0 || subsamp<0
DRC910a3572013-10-30 23:02:57 +00001044 || subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0
1045 || jpegQual>100)
DRCaecea382014-08-11 18:05:41 +00001046 _throw("tjCompressFromYUVPlanes(): Invalid argument");
1047 if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1048 _throw("tjCompressFromYUVPlanes(): Invalid argument");
DRC910a3572013-10-30 23:02:57 +00001049
1050 if(setjmp(this->jerr.setjmp_buffer))
1051 {
1052 /* If we get here, the JPEG code has signaled an error. */
1053 retval=-1;
1054 goto bailout;
1055 }
1056
1057 cinfo->image_width=width;
1058 cinfo->image_height=height;
1059
1060 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1061 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1062 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1063
1064 if(flags&TJFLAG_NOREALLOC)
1065 {
1066 alloc=0; *jpegSize=tjBufSize(width, height, subsamp);
1067 }
1068 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1069 if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1)
1070 return -1;
1071 cinfo->raw_data_in=TRUE;
1072
1073 jpeg_start_compress(cinfo, TRUE);
1074 for(i=0; i<cinfo->num_components; i++)
1075 {
1076 jpeg_component_info *compptr=&cinfo->comp_info[i];
1077 int ih;
1078 iw[i]=compptr->width_in_blocks*DCTSIZE;
1079 ih=compptr->height_in_blocks*DCTSIZE;
DRC40dd3142014-08-17 12:23:49 +00001080 pw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor)
DRC910a3572013-10-30 23:02:57 +00001081 *compptr->h_samp_factor/cinfo->max_h_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001082 ph[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor)
DRC910a3572013-10-30 23:02:57 +00001083 *compptr->v_samp_factor/cinfo->max_v_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001084 if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
DRC910a3572013-10-30 23:02:57 +00001085 th[i]=compptr->v_samp_factor*DCTSIZE;
1086 tmpbufsize+=iw[i]*th[i];
DRC40dd3142014-08-17 12:23:49 +00001087 if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001088 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1089 ptr=srcPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001090 for(row=0; row<ph[i]; row++)
DRC910a3572013-10-30 23:02:57 +00001091 {
1092 inbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001093 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC910a3572013-10-30 23:02:57 +00001094 }
1095 }
1096 if(usetmpbuf)
1097 {
1098 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRCaecea382014-08-11 18:05:41 +00001099 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
DRC910a3572013-10-30 23:02:57 +00001100 ptr=_tmpbuf;
1101 for(i=0; i<cinfo->num_components; i++)
1102 {
1103 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001104 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
DRC910a3572013-10-30 23:02:57 +00001105 for(row=0; row<th[i]; row++)
1106 {
1107 tmpbuf[i][row]=ptr;
1108 ptr+=iw[i];
1109 }
1110 }
1111 }
1112
1113 for(row=0; row<(int)cinfo->image_height;
1114 row+=cinfo->max_v_samp_factor*DCTSIZE)
1115 {
1116 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1117 int crow[MAX_COMPONENTS];
1118 for(i=0; i<cinfo->num_components; i++)
1119 {
1120 jpeg_component_info *compptr=&cinfo->comp_info[i];
1121 crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor;
1122 if(usetmpbuf)
1123 {
1124 int j, k;
DRC40dd3142014-08-17 12:23:49 +00001125 for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
DRC910a3572013-10-30 23:02:57 +00001126 {
DRC40dd3142014-08-17 12:23:49 +00001127 memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], pw[i]);
DRC006bc582014-02-27 21:22:54 +00001128 /* Duplicate last sample in row to fill out MCU */
DRC40dd3142014-08-17 12:23:49 +00001129 for(k=pw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][pw[i]-1];
DRC910a3572013-10-30 23:02:57 +00001130 }
DRC006bc582014-02-27 21:22:54 +00001131 /* Duplicate last row to fill out MCU */
DRC40dd3142014-08-17 12:23:49 +00001132 for(j=ph[i]-crow[i]; j<th[i]; j++)
1133 memcpy(tmpbuf[i][j], tmpbuf[i][ph[i]-crow[i]-1], iw[i]);
DRC910a3572013-10-30 23:02:57 +00001134 yuvptr[i]=tmpbuf[i];
1135 }
1136 else
1137 yuvptr[i]=&inbuf[i][crow[i]];
1138 }
1139 jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE);
1140 }
1141 jpeg_finish_compress(cinfo);
1142
1143 bailout:
1144 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1145 for(i=0; i<MAX_COMPONENTS; i++)
1146 {
1147 if(tmpbuf[i]) free(tmpbuf[i]);
1148 if(inbuf[i]) free(inbuf[i]);
1149 }
1150 if(_tmpbuf) free(_tmpbuf);
1151 return retval;
1152}
1153
DRCaecea382014-08-11 18:05:41 +00001154DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle, unsigned char *srcBuf,
1155 int width, int pad, int height, int subsamp, unsigned char **jpegBuf,
1156 unsigned long *jpegSize, int jpegQual, int flags)
1157{
1158 unsigned char *srcPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001159 int pw0, ph0, strides[3], retval=-1;
DRCaecea382014-08-11 18:05:41 +00001160
1161 if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
1162 || subsamp>=NUMSUBOPT)
1163 _throw("tjCompressFromYUV(): Invalid argument");
1164
DRC40dd3142014-08-17 12:23:49 +00001165 pw0=tjPlaneWidth(0, width, subsamp);
1166 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +00001167 srcPlanes[0]=srcBuf;
DRC40dd3142014-08-17 12:23:49 +00001168 strides[0]=PAD(pw0, pad);
1169 if(subsamp==TJSAMP_GRAY)
1170 {
1171 strides[1]=strides[2]=0;
1172 srcPlanes[1]=srcPlanes[2]=NULL;
1173 }
1174 else
1175 {
1176 int pw1=tjPlaneWidth(1, width, subsamp);
1177 int ph1=tjPlaneHeight(1, height, subsamp);
1178 strides[1]=strides[2]=PAD(pw1, pad);
1179 srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1180 srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1181 }
DRCaecea382014-08-11 18:05:41 +00001182
1183 return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1184 subsamp, jpegBuf, jpegSize, jpegQual, flags);
1185
1186 bailout:
1187 return retval;
1188}
1189
DRC910a3572013-10-30 23:02:57 +00001190
DRC9b28def2011-05-21 14:37:15 +00001191/* Decompressor */
DRC2e7b76b2009-04-03 12:04:24 +00001192
DRC9b28def2011-05-21 14:37:15 +00001193static tjhandle _tjInitDecompress(tjinstance *this)
DRC2e7b76b2009-04-03 12:04:24 +00001194{
DRC9b28def2011-05-21 14:37:15 +00001195 unsigned char buffer[1];
DRC2e7b76b2009-04-03 12:04:24 +00001196
DRC9b28def2011-05-21 14:37:15 +00001197 /* This is also straight out of example.c */
1198 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
1199 this->jerr.pub.error_exit=my_error_exit;
1200 this->jerr.pub.output_message=my_output_message;
DRC2e7b76b2009-04-03 12:04:24 +00001201
DRC9b28def2011-05-21 14:37:15 +00001202 if(setjmp(this->jerr.setjmp_buffer))
1203 {
1204 /* If we get here, the JPEG code has signaled an error. */
1205 if(this) free(this); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +00001206 }
DRC2e7b76b2009-04-03 12:04:24 +00001207
DRC9b28def2011-05-21 14:37:15 +00001208 jpeg_create_decompress(&this->dinfo);
1209 /* Make an initial call so it will create the source manager */
1210 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +00001211
DRC007a42c2011-05-22 13:55:56 +00001212 this->init|=DECOMPRESS;
DRC9b28def2011-05-21 14:37:15 +00001213 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +00001214}
1215
DRC890f1e02011-02-26 22:02:37 +00001216DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
1217{
DRC9b28def2011-05-21 14:37:15 +00001218 tjinstance *this;
1219 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00001220 {
DRC007a42c2011-05-22 13:55:56 +00001221 snprintf(errStr, JMSG_LENGTH_MAX,
1222 "tjInitDecompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00001223 return NULL;
1224 }
DRC007a42c2011-05-22 13:55:56 +00001225 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +00001226 return _tjInitDecompress(this);
DRC890f1e02011-02-26 22:02:37 +00001227}
1228
DRC2e7b76b2009-04-03 12:04:24 +00001229
DRCcd7c3e62013-08-23 02:49:25 +00001230DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
DRC9b28def2011-05-21 14:37:15 +00001231 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
DRCcd7c3e62013-08-23 02:49:25 +00001232 int *jpegSubsamp, int *jpegColorspace)
DRC1fe80f82010-12-14 01:21:29 +00001233{
DRC9b49f0e2011-07-12 03:17:23 +00001234 int retval=0;
DRC1fe80f82010-12-14 01:21:29 +00001235
DRC41861622014-04-16 23:38:37 +00001236 getdinstance(handle);
DRC9b28def2011-05-21 14:37:15 +00001237 if((this->init&DECOMPRESS)==0)
DRCcd7c3e62013-08-23 02:49:25 +00001238 _throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
DRC1fe80f82010-12-14 01:21:29 +00001239
DRC9b28def2011-05-21 14:37:15 +00001240 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
DRCcd7c3e62013-08-23 02:49:25 +00001241 || jpegSubsamp==NULL || jpegColorspace==NULL)
1242 _throw("tjDecompressHeader3(): Invalid argument");
DRC1fe80f82010-12-14 01:21:29 +00001243
DRC9b28def2011-05-21 14:37:15 +00001244 if(setjmp(this->jerr.setjmp_buffer))
1245 {
1246 /* If we get here, the JPEG code has signaled an error. */
DRC1fe80f82010-12-14 01:21:29 +00001247 return -1;
1248 }
1249
DRC9b28def2011-05-21 14:37:15 +00001250 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1251 jpeg_read_header(dinfo, TRUE);
DRC1fe80f82010-12-14 01:21:29 +00001252
DRC9b28def2011-05-21 14:37:15 +00001253 *width=dinfo->image_width;
1254 *height=dinfo->image_height;
DRC9b49f0e2011-07-12 03:17:23 +00001255 *jpegSubsamp=getSubsamp(dinfo);
DRCcd7c3e62013-08-23 02:49:25 +00001256 switch(dinfo->jpeg_color_space)
1257 {
1258 case JCS_GRAYSCALE: *jpegColorspace=TJCS_GRAY; break;
1259 case JCS_RGB: *jpegColorspace=TJCS_RGB; break;
1260 case JCS_YCbCr: *jpegColorspace=TJCS_YCbCr; break;
1261 case JCS_CMYK: *jpegColorspace=TJCS_CMYK; break;
1262 case JCS_YCCK: *jpegColorspace=TJCS_YCCK; break;
1263 default: *jpegColorspace=-1; break;
1264 }
DRC1fe80f82010-12-14 01:21:29 +00001265
DRC9b28def2011-05-21 14:37:15 +00001266 jpeg_abort_decompress(dinfo);
DRC1fe80f82010-12-14 01:21:29 +00001267
DRC9b28def2011-05-21 14:37:15 +00001268 if(*jpegSubsamp<0)
DRCcd7c3e62013-08-23 02:49:25 +00001269 _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1270 if(*jpegColorspace<0)
1271 _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
DRC007a42c2011-05-22 13:55:56 +00001272 if(*width<1 || *height<1)
DRCcd7c3e62013-08-23 02:49:25 +00001273 _throw("tjDecompressHeader3(): Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +00001274
1275 bailout:
1276 return retval;
1277}
1278
DRCcd7c3e62013-08-23 02:49:25 +00001279DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
1280 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
1281 int *jpegSubsamp)
1282{
1283 int jpegColorspace;
1284 return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1285 jpegSubsamp, &jpegColorspace);
1286}
1287
DRC9b28def2011-05-21 14:37:15 +00001288DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
1289 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
DRC91e86ba2011-02-15 05:24:08 +00001290{
DRC9b28def2011-05-21 14:37:15 +00001291 int jpegSubsamp;
1292 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1293 &jpegSubsamp);
DRC1fe80f82010-12-14 01:21:29 +00001294}
1295
1296
DRC109a5782011-03-01 09:53:07 +00001297DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +00001298{
DRC109a5782011-03-01 09:53:07 +00001299 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +00001300 {
DRC9b28def2011-05-21 14:37:15 +00001301 snprintf(errStr, JMSG_LENGTH_MAX,
DRC007a42c2011-05-22 13:55:56 +00001302 "tjGetScalingFactors(): Invalid argument");
DRC109a5782011-03-01 09:53:07 +00001303 return NULL;
DRCb28fc572011-02-22 06:41:29 +00001304 }
1305
DRC109a5782011-03-01 09:53:07 +00001306 *numscalingfactors=NUMSF;
1307 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +00001308}
1309
1310
DRC9b28def2011-05-21 14:37:15 +00001311DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
1312 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1313 int height, int pixelFormat, int flags)
DRC2e7b76b2009-04-03 12:04:24 +00001314{
DRC9b28def2011-05-21 14:37:15 +00001315 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRC109a5782011-03-01 09:53:07 +00001316 int jpegwidth, jpegheight, scaledw, scaledh;
DRCafc06922012-03-23 19:47:57 +00001317 #ifndef JCS_EXTENSIONS
1318 unsigned char *rgbBuf=NULL;
1319 unsigned char *_dstBuf=NULL; int _pitch=0;
1320 #endif
DRC2e7b76b2009-04-03 12:04:24 +00001321
DRC41861622014-04-16 23:38:37 +00001322 getdinstance(handle);
DRC9b28def2011-05-21 14:37:15 +00001323 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001324 _throw("tjDecompress2(): Instance has not been initialized for decompression");
DRC9b28def2011-05-21 14:37:15 +00001325
1326 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
1327 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
1328 _throw("tjDecompress2(): Invalid argument");
1329
DRC25b995a2011-05-21 15:34:54 +00001330 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1331 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1332 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +00001333
1334 if(setjmp(this->jerr.setjmp_buffer))
1335 {
1336 /* If we get here, the JPEG code has signaled an error. */
1337 retval=-1;
1338 goto bailout;
1339 }
1340
1341 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1342 jpeg_read_header(dinfo, TRUE);
DRC73d74c12012-06-29 23:46:38 +00001343 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
DRC2eda8212012-03-23 19:32:38 +00001344 {
1345 retval=-1; goto bailout;
1346 }
DRC9b28def2011-05-21 14:37:15 +00001347
DRC25b995a2011-05-21 15:34:54 +00001348 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +00001349
1350 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1351 if(width==0) width=jpegwidth;
1352 if(height==0) height=jpegheight;
1353 for(i=0; i<NUMSF; i++)
1354 {
1355 scaledw=TJSCALED(jpegwidth, sf[i]);
1356 scaledh=TJSCALED(jpegheight, sf[i]);
1357 if(scaledw<=width && scaledh<=height)
DRCf610d612013-04-26 10:33:29 +00001358 break;
DRC9b28def2011-05-21 14:37:15 +00001359 }
1360 if(scaledw>width || scaledh>height)
DRC007a42c2011-05-22 13:55:56 +00001361 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
DRC9b28def2011-05-21 14:37:15 +00001362 width=scaledw; height=scaledh;
1363 dinfo->scale_num=sf[i].num;
1364 dinfo->scale_denom=sf[i].denom;
1365
1366 jpeg_start_decompress(dinfo);
1367 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
DRCafc06922012-03-23 19:47:57 +00001368
1369 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +00001370 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
DRCafc06922012-03-23 19:47:57 +00001371 (RGB_RED!=tjRedOffset[pixelFormat] ||
1372 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1373 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1374 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1375 {
1376 rgbBuf=(unsigned char *)malloc(width*height*3);
1377 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1378 _pitch=pitch; pitch=width*3;
1379 _dstBuf=dstBuf; dstBuf=rgbBuf;
1380 }
1381 #endif
1382
DRC9b28def2011-05-21 14:37:15 +00001383 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1384 *dinfo->output_height))==NULL)
DRC007a42c2011-05-22 13:55:56 +00001385 _throw("tjDecompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001386 for(i=0; i<(int)dinfo->output_height; i++)
1387 {
DRC25b995a2011-05-21 15:34:54 +00001388 if(flags&TJFLAG_BOTTOMUP)
DRC9b28def2011-05-21 14:37:15 +00001389 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1390 else row_pointer[i]=&dstBuf[i*pitch];
1391 }
1392 while(dinfo->output_scanline<dinfo->output_height)
1393 {
1394 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1395 dinfo->output_height-dinfo->output_scanline);
1396 }
1397 jpeg_finish_decompress(dinfo);
1398
DRCafc06922012-03-23 19:47:57 +00001399 #ifndef JCS_EXTENSIONS
1400 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1401 #endif
1402
DRC9b28def2011-05-21 14:37:15 +00001403 bailout:
1404 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRCafc06922012-03-23 19:47:57 +00001405 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +00001406 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +00001407 #endif
DRC9b28def2011-05-21 14:37:15 +00001408 if(row_pointer) free(row_pointer);
1409 return retval;
1410}
1411
1412DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1413 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1414 int height, int pixelSize, int flags)
1415{
1416 if(flags&TJ_YUV)
1417 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1418 else
1419 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1420 height, getPixelFormat(pixelSize, flags), flags);
1421}
1422
1423
DRC34dca052014-02-28 09:17:14 +00001424static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
1425 int pixelFormat, int subsamp, int flags)
1426{
DRC895fd6d2014-02-28 09:35:34 +00001427 int i;
1428
DRC34dca052014-02-28 09:17:14 +00001429 dinfo->scale_num=dinfo->scale_denom=1;
1430
1431 if(subsamp==TJSAMP_GRAY)
1432 {
DRCc9014492014-03-10 09:34:04 +00001433 dinfo->num_components=dinfo->comps_in_scan=1;
DRC34dca052014-02-28 09:17:14 +00001434 dinfo->jpeg_color_space=JCS_GRAYSCALE;
1435 }
1436 else
1437 {
DRCc9014492014-03-10 09:34:04 +00001438 dinfo->num_components=dinfo->comps_in_scan=3;
DRC34dca052014-02-28 09:17:14 +00001439 dinfo->jpeg_color_space=JCS_YCbCr;
1440 }
1441
1442 dinfo->comp_info=(jpeg_component_info *)
1443 (*dinfo->mem->alloc_small)((j_common_ptr)dinfo, JPOOL_IMAGE,
DRC5de454b2014-05-18 19:04:03 +00001444 dinfo->num_components*sizeof(jpeg_component_info));
DRC34dca052014-02-28 09:17:14 +00001445
DRC2bdc0422014-03-07 03:52:57 +00001446 for(i=0; i<dinfo->num_components; i++)
DRC34dca052014-02-28 09:17:14 +00001447 {
DRC2bdc0422014-03-07 03:52:57 +00001448 jpeg_component_info *compptr=&dinfo->comp_info[i];
1449 compptr->h_samp_factor=(i==0)? tjMCUWidth[subsamp]/8:1;
1450 compptr->v_samp_factor=(i==0)? tjMCUHeight[subsamp]/8:1;
1451 compptr->component_index=i;
DRC15c08762014-03-10 20:11:56 +00001452 compptr->component_id=i+1;
DRC2bdc0422014-03-07 03:52:57 +00001453 compptr->quant_tbl_no=compptr->dc_tbl_no=compptr->ac_tbl_no=
1454 (i==0)? 0:1;
1455 dinfo->cur_comp_info[i]=compptr;
DRC34dca052014-02-28 09:17:14 +00001456 }
DRCc9014492014-03-10 09:34:04 +00001457 dinfo->data_precision=8;
1458 for(i=0; i<2; i++)
1459 {
1460 if(dinfo->quant_tbl_ptrs[i]==NULL)
1461 dinfo->quant_tbl_ptrs[i]=jpeg_alloc_quant_table((j_common_ptr)dinfo);
1462 }
DRC34dca052014-02-28 09:17:14 +00001463
1464 return 0;
1465}
1466
1467
1468int my_read_markers(j_decompress_ptr dinfo)
1469{
1470 return JPEG_REACHED_SOS;
1471}
1472
1473void my_reset_marker_reader(j_decompress_ptr dinfo)
1474{
1475}
1476
DRCaecea382014-08-11 18:05:41 +00001477DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
1478 unsigned char **srcPlanes, int *strides, int subsamp, unsigned char *dstBuf,
1479 int width, int pitch, int height, int pixelFormat, int flags)
DRC34dca052014-02-28 09:17:14 +00001480{
1481 int i, retval=0; JSAMPROW *row_pointer=NULL;
1482 JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1483 JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +00001484 int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001485 JSAMPLE *ptr;
DRC34dca052014-02-28 09:17:14 +00001486 jpeg_component_info *compptr;
1487 #ifndef JCS_EXTENSIONS
1488 unsigned char *rgbBuf=NULL;
DRC230d09d2014-04-20 09:42:49 +00001489 unsigned char *_dstBuf=NULL; int _pitch=0;
DRC34dca052014-02-28 09:17:14 +00001490 #endif
DRCbc56b752014-05-16 10:43:44 +00001491 int (*old_read_markers)(j_decompress_ptr);
1492 void (*old_reset_marker_reader)(j_decompress_ptr);
DRC34dca052014-02-28 09:17:14 +00001493
DRC41861622014-04-16 23:38:37 +00001494 getdinstance(handle);
DRC34dca052014-02-28 09:17:14 +00001495
1496 for(i=0; i<MAX_COMPONENTS; i++)
1497 {
1498 tmpbuf[i]=NULL; _tmpbuf[i]=NULL; inbuf[i]=NULL;
1499 }
1500
1501 if((this->init&DECOMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001502 _throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
DRC34dca052014-02-28 09:17:14 +00001503
DRCaecea382014-08-11 18:05:41 +00001504 if(!srcPlanes || !srcPlanes[0] || subsamp<0 || subsamp>=NUMSUBOPT
DRC34dca052014-02-28 09:17:14 +00001505 || dstBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
1506 || pixelFormat>=TJ_NUMPF)
DRCaecea382014-08-11 18:05:41 +00001507 _throw("tjDecodeYUVPlanes(): Invalid argument");
1508 if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1509 _throw("tjDecodeYUVPlanes(): Invalid argument");
DRC34dca052014-02-28 09:17:14 +00001510
1511 if(setjmp(this->jerr.setjmp_buffer))
1512 {
1513 /* If we get here, the JPEG code has signaled an error. */
1514 retval=-1;
1515 goto bailout;
1516 }
1517
1518 if(pixelFormat==TJPF_CMYK)
DRCaecea382014-08-11 18:05:41 +00001519 _throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
DRC34dca052014-02-28 09:17:14 +00001520
1521 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC34dca052014-02-28 09:17:14 +00001522 dinfo->image_width=width;
1523 dinfo->image_height=height;
1524
1525 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1526 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1527 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1528
DRC34dca052014-02-28 09:17:14 +00001529 if(setDecodeDefaults(dinfo, pixelFormat, subsamp, flags)==-1)
1530 {
1531 retval=-1; goto bailout;
1532 }
1533 old_read_markers=dinfo->marker->read_markers;
1534 dinfo->marker->read_markers=my_read_markers;
1535 old_reset_marker_reader=dinfo->marker->reset_marker_reader;
1536 dinfo->marker->reset_marker_reader=my_reset_marker_reader;
1537 jpeg_read_header(dinfo, TRUE);
1538 dinfo->marker->read_markers=old_read_markers;
1539 dinfo->marker->reset_marker_reader=old_reset_marker_reader;
1540
1541 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
1542 {
1543 retval=-1; goto bailout;
1544 }
DRC7d9f7582014-03-10 20:14:53 +00001545 dinfo->do_fancy_upsampling=FALSE;
DRC2bdc0422014-03-07 03:52:57 +00001546 jinit_master_decompress(dinfo);
DRC34dca052014-02-28 09:17:14 +00001547 (*dinfo->upsample->start_pass)(dinfo);
1548
DRC40dd3142014-08-17 12:23:49 +00001549 pw0=PAD(width, dinfo->max_h_samp_factor);
1550 ph0=PAD(height, dinfo->max_v_samp_factor);
DRC34dca052014-02-28 09:17:14 +00001551
1552 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
1553
DRC230d09d2014-04-20 09:42:49 +00001554 #ifndef JCS_EXTENSIONS
1555 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
1556 (RGB_RED!=tjRedOffset[pixelFormat] ||
1557 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1558 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1559 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1560 {
1561 rgbBuf=(unsigned char *)malloc(width*height*3);
DRCaecea382014-08-11 18:05:41 +00001562 if(!rgbBuf) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC230d09d2014-04-20 09:42:49 +00001563 _pitch=pitch; pitch=width*3;
1564 _dstBuf=dstBuf; dstBuf=rgbBuf;
1565 }
1566 #endif
1567
DRC40dd3142014-08-17 12:23:49 +00001568 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
DRCaecea382014-08-11 18:05:41 +00001569 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001570 for(i=0; i<height; i++)
1571 {
1572 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*pitch];
1573 else row_pointer[i]=&dstBuf[i*pitch];
1574 }
DRC40dd3142014-08-17 12:23:49 +00001575 if(height<ph0)
1576 for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
DRC34dca052014-02-28 09:17:14 +00001577
1578 for(i=0; i<dinfo->num_components; i++)
1579 {
1580 compptr=&dinfo->comp_info[i];
1581 _tmpbuf[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
1582 * compptr->v_samp_factor + 16);
DRCaecea382014-08-11 18:05:41 +00001583 if(!_tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001584 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCaecea382014-08-11 18:05:41 +00001585 if(!tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001586 for(row=0; row<compptr->v_samp_factor; row++)
1587 {
1588 unsigned char *_tmpbuf_aligned=
1589 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
1590 tmpbuf[i][row]=&_tmpbuf_aligned[
1591 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
1592 }
DRC40dd3142014-08-17 12:23:49 +00001593 pw[i]=pw0*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1594 ph[i]=ph0*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1595 inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
DRCaecea382014-08-11 18:05:41 +00001596 if(!inbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1597 ptr=srcPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001598 for(row=0; row<ph[i]; row++)
DRC34dca052014-02-28 09:17:14 +00001599 {
1600 inbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001601 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC34dca052014-02-28 09:17:14 +00001602 }
1603 }
1604
DRC40dd3142014-08-17 12:23:49 +00001605 for(row=0; row<ph0; row+=dinfo->max_v_samp_factor)
DRC34dca052014-02-28 09:17:14 +00001606 {
1607 JDIMENSION inrow=0, outrow=0;
1608 for(i=0, compptr=dinfo->comp_info; i<dinfo->num_components; i++, compptr++)
1609 jcopy_sample_rows(inbuf[i],
1610 row*compptr->v_samp_factor/dinfo->max_v_samp_factor, tmpbuf[i], 0,
DRC40dd3142014-08-17 12:23:49 +00001611 compptr->v_samp_factor, pw[i]);
DRC34dca052014-02-28 09:17:14 +00001612 (dinfo->upsample->upsample)(dinfo, tmpbuf, &inrow,
1613 dinfo->max_v_samp_factor, &row_pointer[row], &outrow,
1614 dinfo->max_v_samp_factor);
1615 }
1616 jpeg_abort_decompress(dinfo);
1617
DRC230d09d2014-04-20 09:42:49 +00001618 #ifndef JCS_EXTENSIONS
1619 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1620 #endif
1621
DRC34dca052014-02-28 09:17:14 +00001622 bailout:
1623 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1624 #ifndef JCS_EXTENSIONS
1625 if(rgbBuf) free(rgbBuf);
1626 #endif
1627 if(row_pointer) free(row_pointer);
1628 for(i=0; i<MAX_COMPONENTS; i++)
1629 {
1630 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
1631 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
1632 if(inbuf[i]!=NULL) free(inbuf[i]);
1633 }
1634 return retval;
1635}
1636
DRCaecea382014-08-11 18:05:41 +00001637DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, unsigned char *srcBuf,
1638 int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
1639 int height, int pixelFormat, int flags)
1640{
1641 unsigned char *srcPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001642 int pw0, ph0, strides[3], retval=-1;
DRC34dca052014-02-28 09:17:14 +00001643
DRCaecea382014-08-11 18:05:41 +00001644 if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT
1645 || width<=0 || height<=0)
1646 _throw("tjDecodeYUV(): Invalid argument");
1647
DRC40dd3142014-08-17 12:23:49 +00001648 pw0=tjPlaneWidth(0, width, subsamp);
1649 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +00001650 srcPlanes[0]=srcBuf;
DRC40dd3142014-08-17 12:23:49 +00001651 strides[0]=PAD(pw0, pad);
1652 if(subsamp==TJSAMP_GRAY)
1653 {
1654 strides[1]=strides[2]=0;
1655 srcPlanes[1]=srcPlanes[2]=NULL;
1656 }
1657 else
1658 {
1659 int pw1=tjPlaneWidth(1, width, subsamp);
1660 int ph1=tjPlaneHeight(1, height, subsamp);
1661 strides[1]=strides[2]=PAD(pw1, pad);
1662 srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1663 srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1664 }
DRCaecea382014-08-11 18:05:41 +00001665
1666 return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1667 pitch, height, pixelFormat, flags);
1668
1669 bailout:
1670 return retval;
1671}
1672
1673DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle,
1674 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char **dstPlanes,
1675 int width, int *strides, int height, int flags)
DRC9b28def2011-05-21 14:37:15 +00001676{
DRCf610d612013-04-26 10:33:29 +00001677 int i, sfi, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001678 int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
DRC40dd3142014-08-17 12:23:49 +00001679 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
DRC9b28def2011-05-21 14:37:15 +00001680 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001681 JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001682 int dctsize;
DRC9b28def2011-05-21 14:37:15 +00001683
DRC41861622014-04-16 23:38:37 +00001684 getdinstance(handle);
DRCb51ee892013-10-31 05:00:19 +00001685
DRCf9cf5c72010-12-10 10:58:49 +00001686 for(i=0; i<MAX_COMPONENTS; i++)
1687 {
1688 tmpbuf[i]=NULL; outbuf[i]=NULL;
1689 }
DRC9e17f7d2010-12-10 04:59:13 +00001690
DRCe2f8e692013-10-30 22:21:06 +00001691 if((this->init&DECOMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001692 _throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
DRCe2f8e692013-10-30 22:21:06 +00001693
DRCaecea382014-08-11 18:05:41 +00001694 if(jpegBuf==NULL || jpegSize<=0 || !dstPlanes || !dstPlanes[0] || width<0
1695 || height<0)
1696 _throw("tjDecompressToYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001697
DRC25b995a2011-05-21 15:34:54 +00001698 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1699 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1700 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +00001701
DRC9b28def2011-05-21 14:37:15 +00001702 if(setjmp(this->jerr.setjmp_buffer))
1703 {
1704 /* If we get here, the JPEG code has signaled an error. */
DRC91e86ba2011-02-15 05:24:08 +00001705 retval=-1;
1706 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +00001707 }
DRC2e7b76b2009-04-03 12:04:24 +00001708
DRCaecea382014-08-11 18:05:41 +00001709 if(!this->headerRead)
1710 {
1711 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1712 jpeg_read_header(dinfo, TRUE);
1713 }
1714 this->headerRead=0;
DRC418fe282013-05-07 21:17:35 +00001715 jpegSubsamp=getSubsamp(dinfo);
1716 if(jpegSubsamp<0)
DRCaecea382014-08-11 18:05:41 +00001717 _throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1718
1719 if(jpegSubsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1720 _throw("tjDecompressToYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001721
DRCf610d612013-04-26 10:33:29 +00001722 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1723 if(width==0) width=jpegwidth;
1724 if(height==0) height=jpegheight;
1725 for(i=0; i<NUMSF; i++)
1726 {
1727 scaledw=TJSCALED(jpegwidth, sf[i]);
1728 scaledh=TJSCALED(jpegheight, sf[i]);
1729 if(scaledw<=width && scaledh<=height)
1730 break;
1731 }
1732 if(scaledw>width || scaledh>height)
DRCaecea382014-08-11 18:05:41 +00001733 _throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
DRCcd7c3e62013-08-23 02:49:25 +00001734 if(dinfo->num_components>3)
DRCaecea382014-08-11 18:05:41 +00001735 _throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
DRCcd7c3e62013-08-23 02:49:25 +00001736
DRCf610d612013-04-26 10:33:29 +00001737 width=scaledw; height=scaledh;
1738 dinfo->scale_num=sf[i].num;
1739 dinfo->scale_denom=sf[i].denom;
1740 sfi=i;
1741 jpeg_calc_output_dimensions(dinfo);
1742
DRC418fe282013-05-07 21:17:35 +00001743 dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
1744
DRC9b28def2011-05-21 14:37:15 +00001745 for(i=0; i<dinfo->num_components; i++)
DRC2e7b76b2009-04-03 12:04:24 +00001746 {
DRC9b28def2011-05-21 14:37:15 +00001747 jpeg_component_info *compptr=&dinfo->comp_info[i];
1748 int ih;
DRC418fe282013-05-07 21:17:35 +00001749 iw[i]=compptr->width_in_blocks*dctsize;
1750 ih=compptr->height_in_blocks*dctsize;
DRC40dd3142014-08-17 12:23:49 +00001751 pw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001752 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001753 ph[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001754 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001755 if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
DRC418fe282013-05-07 21:17:35 +00001756 th[i]=compptr->v_samp_factor*dctsize;
DRC9b28def2011-05-21 14:37:15 +00001757 tmpbufsize+=iw[i]*th[i];
DRC40dd3142014-08-17 12:23:49 +00001758 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001759 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1760 ptr=dstPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001761 for(row=0; row<ph[i]; row++)
DRC9b28def2011-05-21 14:37:15 +00001762 {
1763 outbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001764 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC9b28def2011-05-21 14:37:15 +00001765 }
1766 }
1767 if(usetmpbuf)
1768 {
1769 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRCaecea382014-08-11 18:05:41 +00001770 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001771 ptr=_tmpbuf;
1772 for(i=0; i<dinfo->num_components; i++)
1773 {
1774 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001775 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001776 for(row=0; row<th[i]; row++)
1777 {
1778 tmpbuf[i][row]=ptr;
1779 ptr+=iw[i];
1780 }
1781 }
1782 }
DRC9e17f7d2010-12-10 04:59:13 +00001783
DRC25b995a2011-05-21 15:34:54 +00001784 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRCe0419b52012-07-03 20:01:31 +00001785 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
DRC9b28def2011-05-21 14:37:15 +00001786 dinfo->raw_data_out=TRUE;
1787
1788 jpeg_start_decompress(dinfo);
1789 for(row=0; row<(int)dinfo->output_height;
DRC418fe282013-05-07 21:17:35 +00001790 row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
DRC9b28def2011-05-21 14:37:15 +00001791 {
1792 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1793 int crow[MAX_COMPONENTS];
DRC9e17f7d2010-12-10 04:59:13 +00001794 for(i=0; i<dinfo->num_components; i++)
1795 {
1796 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRC418fe282013-05-07 21:17:35 +00001797 if(jpegSubsamp==TJ_420)
1798 {
1799 /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1800 to be clever and use the IDCT to perform upsampling on the U and V
1801 planes. For instance, if the output image is to be scaled by 1/2
1802 relative to the JPEG image, then the scaling factor and upsampling
1803 effectively cancel each other, so a normal 8x8 IDCT can be used.
1804 However, this is not desirable when using the decompress-to-YUV
1805 functionality in TurboJPEG, since we want to output the U and V
1806 planes in their subsampled form. Thus, we have to override some
1807 internal libjpeg parameters to force it to use the "scaled" IDCT
1808 functions on the U and V planes. */
1809 compptr->_DCT_scaled_size=dctsize;
1810 compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
1811 sf[sfi].num/sf[sfi].denom*
1812 compptr->v_samp_factor/dinfo->max_v_samp_factor;
1813 dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1814 }
DRC9b28def2011-05-21 14:37:15 +00001815 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1816 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1817 else yuvptr[i]=&outbuf[i][crow[i]];
DRCf9cf5c72010-12-10 10:58:49 +00001818 }
DRCf610d612013-04-26 10:33:29 +00001819 jpeg_read_raw_data(dinfo, yuvptr,
DRC418fe282013-05-07 21:17:35 +00001820 dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
DRCf9cf5c72010-12-10 10:58:49 +00001821 if(usetmpbuf)
1822 {
DRC9b28def2011-05-21 14:37:15 +00001823 int j;
DRCf9cf5c72010-12-10 10:58:49 +00001824 for(i=0; i<dinfo->num_components; i++)
1825 {
DRC40dd3142014-08-17 12:23:49 +00001826 for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +00001827 {
DRC40dd3142014-08-17 12:23:49 +00001828 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], pw[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001829 }
DRC9e17f7d2010-12-10 04:59:13 +00001830 }
1831 }
1832 }
DRC9b28def2011-05-21 14:37:15 +00001833 jpeg_finish_decompress(dinfo);
DRC2e7b76b2009-04-03 12:04:24 +00001834
DRC91e86ba2011-02-15 05:24:08 +00001835 bailout:
DRC9b28def2011-05-21 14:37:15 +00001836 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC9e17f7d2010-12-10 04:59:13 +00001837 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +00001838 {
1839 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +00001840 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001841 }
1842 if(_tmpbuf) free(_tmpbuf);
DRC91e86ba2011-02-15 05:24:08 +00001843 return retval;
DRC2e7b76b2009-04-03 12:04:24 +00001844}
1845
DRCaecea382014-08-11 18:05:41 +00001846DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
1847 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1848 int width, int pad, int height, int flags)
1849{
1850 unsigned char *dstPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001851 int pw0, ph0, strides[3], retval=-1, jpegSubsamp=-1;
DRCaecea382014-08-11 18:05:41 +00001852 int i, jpegwidth, jpegheight, scaledw, scaledh;
1853
1854 getdinstance(handle);
1855
1856 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
1857 || !isPow2(pad) || height<0)
1858 _throw("tjDecompressToYUV2(): Invalid argument");
1859
1860 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1861 jpeg_read_header(dinfo, TRUE);
1862 jpegSubsamp=getSubsamp(dinfo);
1863 if(jpegSubsamp<0)
1864 _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1865
1866 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1867 if(width==0) width=jpegwidth;
1868 if(height==0) height=jpegheight;
1869
1870 for(i=0; i<NUMSF; i++)
1871 {
1872 scaledw=TJSCALED(jpegwidth, sf[i]);
1873 scaledh=TJSCALED(jpegheight, sf[i]);
1874 if(scaledw<=width && scaledh<=height)
1875 break;
1876 }
1877 if(scaledw>width || scaledh>height)
1878 _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1879
DRC40dd3142014-08-17 12:23:49 +00001880 pw0=tjPlaneWidth(0, width, jpegSubsamp);
1881 ph0=tjPlaneHeight(0, height, jpegSubsamp);
DRCaecea382014-08-11 18:05:41 +00001882 dstPlanes[0]=dstBuf;
DRC40dd3142014-08-17 12:23:49 +00001883 strides[0]=PAD(pw0, pad);
1884 if(jpegSubsamp==TJSAMP_GRAY)
1885 {
1886 strides[1]=strides[2]=0;
1887 dstPlanes[1]=dstPlanes[2]=NULL;
1888 }
1889 else
1890 {
1891 int pw1=tjPlaneWidth(1, width, jpegSubsamp);
1892 int ph1=tjPlaneHeight(1, height, jpegSubsamp);
1893 strides[1]=strides[2]=PAD(pw1, pad);
1894 dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1895 dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1896 }
DRCaecea382014-08-11 18:05:41 +00001897
1898 this->headerRead=1;
1899 return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1900 strides, height, flags);
1901
1902 bailout:
1903 return retval;
1904
1905}
1906
DRCf610d612013-04-26 10:33:29 +00001907DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1908 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1909 int flags)
1910{
1911 return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1912}
1913
DRC2e7b76b2009-04-03 12:04:24 +00001914
DRC9b28def2011-05-21 14:37:15 +00001915/* Transformer */
DRC890f1e02011-02-26 22:02:37 +00001916
1917DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1918{
DRC9b28def2011-05-21 14:37:15 +00001919 tjinstance *this=NULL; tjhandle handle=NULL;
1920 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00001921 {
DRC007a42c2011-05-22 13:55:56 +00001922 snprintf(errStr, JMSG_LENGTH_MAX,
1923 "tjInitTransform(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00001924 return NULL;
1925 }
DRC007a42c2011-05-22 13:55:56 +00001926 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +00001927 handle=_tjInitCompress(this);
1928 if(!handle) return NULL;
1929 handle=_tjInitDecompress(this);
1930 return handle;
DRC890f1e02011-02-26 22:02:37 +00001931}
1932
1933
DRC9b28def2011-05-21 14:37:15 +00001934DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1935 unsigned long jpegSize, int n, unsigned char **dstBufs,
1936 unsigned long *dstSizes, tjtransform *t, int flags)
DRC890f1e02011-02-26 22:02:37 +00001937{
DRC0a325192011-03-02 09:22:41 +00001938 jpeg_transform_info *xinfo=NULL;
DRC890f1e02011-02-26 22:02:37 +00001939 jvirt_barray_ptr *srccoefs, *dstcoefs;
DRC9b49f0e2011-07-12 03:17:23 +00001940 int retval=0, i, jpegSubsamp;
DRC890f1e02011-02-26 22:02:37 +00001941
DRC9b28def2011-05-21 14:37:15 +00001942 getinstance(handle);
1943 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001944 _throw("tjTransform(): Instance has not been initialized for transformation");
DRC890f1e02011-02-26 22:02:37 +00001945
DRC9b28def2011-05-21 14:37:15 +00001946 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1947 || t==NULL || flags<0)
1948 _throw("tjTransform(): Invalid argument");
1949
DRC25b995a2011-05-21 15:34:54 +00001950 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1951 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1952 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC890f1e02011-02-26 22:02:37 +00001953
DRC9b28def2011-05-21 14:37:15 +00001954 if(setjmp(this->jerr.setjmp_buffer))
1955 {
1956 /* If we get here, the JPEG code has signaled an error. */
DRC890f1e02011-02-26 22:02:37 +00001957 retval=-1;
1958 goto bailout;
1959 }
1960
DRC9b28def2011-05-21 14:37:15 +00001961 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
DRC890f1e02011-02-26 22:02:37 +00001962
DRC0a325192011-03-02 09:22:41 +00001963 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1964 ==NULL)
DRC007a42c2011-05-22 13:55:56 +00001965 _throw("tjTransform(): Memory allocation failure");
1966 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
DRC890f1e02011-02-26 22:02:37 +00001967
DRC0a325192011-03-02 09:22:41 +00001968 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00001969 {
DRC0a325192011-03-02 09:22:41 +00001970 xinfo[i].transform=xformtypes[t[i].op];
DRC25b995a2011-05-21 15:34:54 +00001971 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1972 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1973 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1974 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1975 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
DRCba5ea512011-03-04 03:20:34 +00001976 else xinfo[i].slow_hflip=0;
DRC0a325192011-03-02 09:22:41 +00001977
1978 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00001979 {
DRC0a325192011-03-02 09:22:41 +00001980 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
1981 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
1982 if(t[i].r.w!=0)
1983 {
1984 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
1985 }
DRCd932e582011-03-15 20:09:47 +00001986 else xinfo[i].crop_width=JCROP_UNSET;
DRC0a325192011-03-02 09:22:41 +00001987 if(t[i].r.h!=0)
1988 {
1989 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
1990 }
DRCd932e582011-03-15 20:09:47 +00001991 else xinfo[i].crop_height=JCROP_UNSET;
DRC890f1e02011-02-26 22:02:37 +00001992 }
1993 }
1994
DRC9b28def2011-05-21 14:37:15 +00001995 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1996 jpeg_read_header(dinfo, TRUE);
DRC9b49f0e2011-07-12 03:17:23 +00001997 jpegSubsamp=getSubsamp(dinfo);
1998 if(jpegSubsamp<0)
1999 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC890f1e02011-02-26 22:02:37 +00002000
DRC0a325192011-03-02 09:22:41 +00002001 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00002002 {
DRC9b28def2011-05-21 14:37:15 +00002003 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
DRC007a42c2011-05-22 13:55:56 +00002004 _throw("tjTransform(): Transform is not perfect");
DRC890f1e02011-02-26 22:02:37 +00002005
DRC0a325192011-03-02 09:22:41 +00002006 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00002007 {
DRC0a325192011-03-02 09:22:41 +00002008 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
2009 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
2010 {
DRC9b28def2011-05-21 14:37:15 +00002011 snprintf(errStr, JMSG_LENGTH_MAX,
DRC0a325192011-03-02 09:22:41 +00002012 "To crop this JPEG image, x must be a multiple of %d\n"
2013 "and y must be a multiple of %d.\n",
2014 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
2015 retval=-1; goto bailout;
2016 }
DRC890f1e02011-02-26 22:02:37 +00002017 }
2018 }
2019
DRC9b28def2011-05-21 14:37:15 +00002020 srccoefs=jpeg_read_coefficients(dinfo);
DRC890f1e02011-02-26 22:02:37 +00002021
DRC0a325192011-03-02 09:22:41 +00002022 for(i=0; i<n; i++)
2023 {
DRCff78e372011-05-24 10:17:32 +00002024 int w, h, alloc=1;
DRC0a325192011-03-02 09:22:41 +00002025 if(!xinfo[i].crop)
2026 {
DRC9b28def2011-05-21 14:37:15 +00002027 w=dinfo->image_width; h=dinfo->image_height;
DRC0a325192011-03-02 09:22:41 +00002028 }
2029 else
2030 {
2031 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
2032 }
DRCff78e372011-05-24 10:17:32 +00002033 if(flags&TJFLAG_NOREALLOC)
2034 {
DRC9b49f0e2011-07-12 03:17:23 +00002035 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +00002036 }
DRC7bf04d32011-09-17 00:18:31 +00002037 if(!(t[i].options&TJXOPT_NOOUTPUT))
2038 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
DRC9b28def2011-05-21 14:37:15 +00002039 jpeg_copy_critical_parameters(dinfo, cinfo);
2040 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00002041 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00002042 if(!(t[i].options&TJXOPT_NOOUTPUT))
2043 {
2044 jpeg_write_coefficients(cinfo, dstcoefs);
2045 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
2046 }
2047 else jinit_c_master_control(cinfo, TRUE);
DRC9b28def2011-05-21 14:37:15 +00002048 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00002049 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00002050 if(t[i].customFilter)
2051 {
DRCefe28ce2012-01-17 11:48:38 +00002052 int ci, y; JDIMENSION by;
DRC7bf04d32011-09-17 00:18:31 +00002053 for(ci=0; ci<cinfo->num_components; ci++)
2054 {
2055 jpeg_component_info *compptr=&cinfo->comp_info[ci];
2056 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2057 DCTSIZE};
2058 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2059 compptr->height_in_blocks*DCTSIZE};
2060 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
2061 {
2062 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
2063 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
2064 TRUE);
2065 for(y=0; y<compptr->v_samp_factor; y++)
2066 {
2067 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
DRCf5467112011-09-20 05:02:19 +00002068 ci, i, &t[i])==-1)
DRC7bf04d32011-09-17 00:18:31 +00002069 _throw("tjTransform(): Error in custom filter");
2070 arrayRegion.y+=DCTSIZE;
2071 }
2072 }
2073 }
2074 }
2075 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
DRC0a325192011-03-02 09:22:41 +00002076 }
2077
DRC9b28def2011-05-21 14:37:15 +00002078 jpeg_finish_decompress(dinfo);
DRC890f1e02011-02-26 22:02:37 +00002079
DRC890f1e02011-02-26 22:02:37 +00002080 bailout:
DRC9b28def2011-05-21 14:37:15 +00002081 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
2082 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC0a325192011-03-02 09:22:41 +00002083 if(xinfo) free(xinfo);
DRC890f1e02011-02-26 22:02:37 +00002084 return retval;
2085}