blob: 5754cb17e819c8b2ae322a3921e18d041bd0ee16 [file] [log] [blame]
DRC9b28def2011-05-21 14:37:15 +00001/*
DRC1f79c7c2015-06-01 19:22:41 +00002 * Copyright (C)2009-2015 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);
DRC6fa14b32015-08-13 20:06:03 -050047extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
48 unsigned long);
DRC9b28def2011-05-21 14:37:15 +000049
DRCfbb67472010-11-24 04:02:37 +000050#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
DRCf610d612013-04-26 10:33:29 +000051#define isPow2(x) (((x)&(x-1))==0)
DRC2e7b76b2009-04-03 12:04:24 +000052
53
DRC9b28def2011-05-21 14:37:15 +000054/* Error handling (based on example in example.c) */
DRC2e7b76b2009-04-03 12:04:24 +000055
DRC9b28def2011-05-21 14:37:15 +000056static char errStr[JMSG_LENGTH_MAX]="No error";
DRC2e7b76b2009-04-03 12:04:24 +000057
DRC9b28def2011-05-21 14:37:15 +000058struct my_error_mgr
DRC2e7b76b2009-04-03 12:04:24 +000059{
60 struct jpeg_error_mgr pub;
DRC9b28def2011-05-21 14:37:15 +000061 jmp_buf setjmp_buffer;
DRC1f79c7c2015-06-01 19:22:41 +000062 void (*emit_message)(j_common_ptr, int);
63 boolean warning;
DRC9b28def2011-05-21 14:37:15 +000064};
65typedef struct my_error_mgr *my_error_ptr;
DRC2e7b76b2009-04-03 12:04:24 +000066
67static void my_error_exit(j_common_ptr cinfo)
68{
DRC9b28def2011-05-21 14:37:15 +000069 my_error_ptr myerr=(my_error_ptr)cinfo->err;
DRC2e7b76b2009-04-03 12:04:24 +000070 (*cinfo->err->output_message)(cinfo);
DRC9b28def2011-05-21 14:37:15 +000071 longjmp(myerr->setjmp_buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +000072}
73
DRC9b28def2011-05-21 14:37:15 +000074/* Based on output_message() in jerror.c */
75
DRC2e7b76b2009-04-03 12:04:24 +000076static void my_output_message(j_common_ptr cinfo)
77{
DRC9b28def2011-05-21 14:37:15 +000078 (*cinfo->err->format_message)(cinfo, errStr);
DRC2e7b76b2009-04-03 12:04:24 +000079}
80
DRC1f79c7c2015-06-01 19:22:41 +000081static void my_emit_message(j_common_ptr cinfo, int msg_level)
82{
83 my_error_ptr myerr=(my_error_ptr)cinfo->err;
84 myerr->emit_message(cinfo, msg_level);
85 if(msg_level<0) myerr->warning=TRUE;
86}
87
DRC2e7b76b2009-04-03 12:04:24 +000088
DRC9b28def2011-05-21 14:37:15 +000089/* Global structures, macros, etc. */
DRC2e7b76b2009-04-03 12:04:24 +000090
DRC9b28def2011-05-21 14:37:15 +000091enum {COMPRESS=1, DECOMPRESS=2};
92
93typedef struct _tjinstance
DRC2e7b76b2009-04-03 12:04:24 +000094{
95 struct jpeg_compress_struct cinfo;
96 struct jpeg_decompress_struct dinfo;
DRC9b28def2011-05-21 14:37:15 +000097 struct my_error_mgr jerr;
DRCaecea382014-08-11 18:05:41 +000098 int init, headerRead;
DRC9b28def2011-05-21 14:37:15 +000099} tjinstance;
DRC2e7b76b2009-04-03 12:04:24 +0000100
DRC1f3635c2013-08-18 10:19:00 +0000101static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};
DRC9b28def2011-05-21 14:37:15 +0000102
DRC007a42c2011-05-22 13:55:56 +0000103static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
104{
DRC890f1e02011-02-26 22:02:37 +0000105 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
106 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
107};
DRC9b28def2011-05-21 14:37:15 +0000108
DRCab2df6e2012-01-28 06:49:56 +0000109#define NUMSF 16
DRC109a5782011-03-01 09:53:07 +0000110static const tjscalingfactor sf[NUMSF]={
DRCab2df6e2012-01-28 06:49:56 +0000111 {2, 1},
112 {15, 8},
113 {7, 4},
114 {13, 8},
115 {3, 2},
116 {11, 8},
117 {5, 4},
118 {9, 8},
DRC109a5782011-03-01 09:53:07 +0000119 {1, 1},
DRCab2df6e2012-01-28 06:49:56 +0000120 {7, 8},
121 {3, 4},
122 {5, 8},
DRC109a5782011-03-01 09:53:07 +0000123 {1, 2},
DRCab2df6e2012-01-28 06:49:56 +0000124 {3, 8},
DRC109a5782011-03-01 09:53:07 +0000125 {1, 4},
126 {1, 8}
127};
DRC2e7b76b2009-04-03 12:04:24 +0000128
DRCa29294a2011-05-24 09:17:57 +0000129#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
DRCda5220a2011-03-02 02:17:30 +0000130 retval=-1; goto bailout;}
DRC9b28def2011-05-21 14:37:15 +0000131#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
132 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
133 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
134 return -1;} \
DRC1f79c7c2015-06-01 19:22:41 +0000135 cinfo=&this->cinfo; dinfo=&this->dinfo; \
136 this->jerr.warning=FALSE;
DRC41861622014-04-16 23:38:37 +0000137#define getcinstance(handle) tjinstance *this=(tjinstance *)handle; \
138 j_compress_ptr cinfo=NULL; \
139 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
140 return -1;} \
DRC1f79c7c2015-06-01 19:22:41 +0000141 cinfo=&this->cinfo; \
142 this->jerr.warning=FALSE;
DRC41861622014-04-16 23:38:37 +0000143#define getdinstance(handle) tjinstance *this=(tjinstance *)handle; \
144 j_decompress_ptr dinfo=NULL; \
145 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
146 return -1;} \
DRC1f79c7c2015-06-01 19:22:41 +0000147 dinfo=&this->dinfo; \
148 this->jerr.warning=FALSE;
DRC2e7b76b2009-04-03 12:04:24 +0000149
DRC9b28def2011-05-21 14:37:15 +0000150static int getPixelFormat(int pixelSize, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000151{
DRC25b995a2011-05-21 15:34:54 +0000152 if(pixelSize==1) return TJPF_GRAY;
DRC9b28def2011-05-21 14:37:15 +0000153 if(pixelSize==3)
154 {
DRC25b995a2011-05-21 15:34:54 +0000155 if(flags&TJ_BGR) return TJPF_BGR;
156 else return TJPF_RGB;
DRC9b28def2011-05-21 14:37:15 +0000157 }
158 if(pixelSize==4)
159 {
160 if(flags&TJ_ALPHAFIRST)
161 {
DRC25b995a2011-05-21 15:34:54 +0000162 if(flags&TJ_BGR) return TJPF_XBGR;
163 else return TJPF_XRGB;
DRC9b28def2011-05-21 14:37:15 +0000164 }
165 else
166 {
DRC25b995a2011-05-21 15:34:54 +0000167 if(flags&TJ_BGR) return TJPF_BGRX;
168 else return TJPF_RGBX;
DRC9b28def2011-05-21 14:37:15 +0000169 }
170 }
171 return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000172}
173
DRCf12bb302011-09-07 05:03:18 +0000174static int setCompDefaults(struct jpeg_compress_struct *cinfo,
DRC73d74c12012-06-29 23:46:38 +0000175 int pixelFormat, int subsamp, int jpegQual, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000176{
DRCf12bb302011-09-07 05:03:18 +0000177 int retval=0;
DRC0713c1b2014-08-22 13:43:33 +0000178 char *env=NULL;
DRCf12bb302011-09-07 05:03:18 +0000179
DRC9b28def2011-05-21 14:37:15 +0000180 switch(pixelFormat)
181 {
DRC25b995a2011-05-21 15:34:54 +0000182 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000183 cinfo->in_color_space=JCS_GRAYSCALE; break;
184 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000185 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000186 cinfo->in_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000187 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000188 cinfo->in_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000189 case TJPF_RGBX:
DRC67ce3b22011-12-19 02:21:03 +0000190 case TJPF_RGBA:
DRC9b28def2011-05-21 14:37:15 +0000191 cinfo->in_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000192 case TJPF_BGRX:
DRC67ce3b22011-12-19 02:21:03 +0000193 case TJPF_BGRA:
DRC9b28def2011-05-21 14:37:15 +0000194 cinfo->in_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000195 case TJPF_XRGB:
DRC67ce3b22011-12-19 02:21:03 +0000196 case TJPF_ARGB:
DRC9b28def2011-05-21 14:37:15 +0000197 cinfo->in_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000198 case TJPF_XBGR:
DRC67ce3b22011-12-19 02:21:03 +0000199 case TJPF_ABGR:
DRC9b28def2011-05-21 14:37:15 +0000200 cinfo->in_color_space=JCS_EXT_XBGR; break;
201 #else
DRC25b995a2011-05-21 15:34:54 +0000202 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000203 case TJPF_BGR:
204 case TJPF_RGBX:
205 case TJPF_BGRX:
206 case TJPF_XRGB:
207 case TJPF_XBGR:
208 case TJPF_RGBA:
209 case TJPF_BGRA:
210 case TJPF_ARGB:
211 case TJPF_ABGR:
212 cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
213 break;
DRC9b28def2011-05-21 14:37:15 +0000214 #endif
DRCcd7c3e62013-08-23 02:49:25 +0000215 case TJPF_CMYK:
216 cinfo->in_color_space=JCS_CMYK; break;
DRCefa4ddc2010-10-13 19:22:50 +0000217 }
DRC2e7b76b2009-04-03 12:04:24 +0000218
DRC9b28def2011-05-21 14:37:15 +0000219 cinfo->input_components=tjPixelSize[pixelFormat];
220 jpeg_set_defaults(cinfo);
DRC0713c1b2014-08-22 13:43:33 +0000221
DRCfeccdcf2015-02-23 19:19:40 +0000222#ifndef NO_GETENV
DRC0713c1b2014-08-22 13:43:33 +0000223 if((env=getenv("TJ_OPTIMIZE"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
224 cinfo->optimize_coding=TRUE;
225 if((env=getenv("TJ_ARITHMETIC"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
226 cinfo->arith_code=TRUE;
227 if((env=getenv("TJ_RESTART"))!=NULL && strlen(env)>0)
228 {
229 int temp=-1; char tempc=0;
230 if(sscanf(env, "%d%c", &temp, &tempc)>=1 && temp>=0 && temp<=65535)
231 {
232 if(toupper(tempc)=='B')
233 {
234 cinfo->restart_interval=temp;
235 cinfo->restart_in_rows=0;
236 }
237 else
238 cinfo->restart_in_rows=temp;
239 }
240 }
DRCfeccdcf2015-02-23 19:19:40 +0000241#endif
DRC0713c1b2014-08-22 13:43:33 +0000242
DRC9b28def2011-05-21 14:37:15 +0000243 if(jpegQual>=0)
244 {
245 jpeg_set_quality(cinfo, jpegQual, TRUE);
DRC73d74c12012-06-29 23:46:38 +0000246 if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
DRC9b28def2011-05-21 14:37:15 +0000247 else cinfo->dct_method=JDCT_FASTEST;
248 }
DRC25b995a2011-05-21 15:34:54 +0000249 if(subsamp==TJSAMP_GRAY)
DRC9b28def2011-05-21 14:37:15 +0000250 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
DRCcd7c3e62013-08-23 02:49:25 +0000251 else if(pixelFormat==TJPF_CMYK)
252 jpeg_set_colorspace(cinfo, JCS_YCCK);
253 else jpeg_set_colorspace(cinfo, JCS_YCbCr);
DRC2e7b76b2009-04-03 12:04:24 +0000254
DRCfeccdcf2015-02-23 19:19:40 +0000255#ifndef NO_GETENV
DRC0713c1b2014-08-22 13:43:33 +0000256 if((env=getenv("TJ_PROGRESSIVE"))!=NULL && strlen(env)>0
257 && !strcmp(env, "1"))
258 jpeg_simple_progression(cinfo);
DRCfeccdcf2015-02-23 19:19:40 +0000259#endif
DRC0713c1b2014-08-22 13:43:33 +0000260
DRC9b28def2011-05-21 14:37:15 +0000261 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
262 cinfo->comp_info[1].h_samp_factor=1;
263 cinfo->comp_info[2].h_samp_factor=1;
DRCcd7c3e62013-08-23 02:49:25 +0000264 if(cinfo->num_components>3)
265 cinfo->comp_info[3].h_samp_factor=tjMCUWidth[subsamp]/8;
DRC9b28def2011-05-21 14:37:15 +0000266 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
267 cinfo->comp_info[1].v_samp_factor=1;
268 cinfo->comp_info[2].v_samp_factor=1;
DRCcd7c3e62013-08-23 02:49:25 +0000269 if(cinfo->num_components>3)
270 cinfo->comp_info[3].v_samp_factor=tjMCUHeight[subsamp]/8;
DRCf12bb302011-09-07 05:03:18 +0000271
DRCf12bb302011-09-07 05:03:18 +0000272 return retval;
DRC9b28def2011-05-21 14:37:15 +0000273}
274
DRCf12bb302011-09-07 05:03:18 +0000275static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
DRC73d74c12012-06-29 23:46:38 +0000276 int pixelFormat, int flags)
DRC9b28def2011-05-21 14:37:15 +0000277{
DRCf12bb302011-09-07 05:03:18 +0000278 int retval=0;
279
DRC9b28def2011-05-21 14:37:15 +0000280 switch(pixelFormat)
281 {
DRC25b995a2011-05-21 15:34:54 +0000282 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000283 dinfo->out_color_space=JCS_GRAYSCALE; break;
284 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000285 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000286 dinfo->out_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000287 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000288 dinfo->out_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000289 case TJPF_RGBX:
DRC9b28def2011-05-21 14:37:15 +0000290 dinfo->out_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000291 case TJPF_BGRX:
DRC9b28def2011-05-21 14:37:15 +0000292 dinfo->out_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000293 case TJPF_XRGB:
DRC9b28def2011-05-21 14:37:15 +0000294 dinfo->out_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000295 case TJPF_XBGR:
DRC9b28def2011-05-21 14:37:15 +0000296 dinfo->out_color_space=JCS_EXT_XBGR; break;
DRC67ce3b22011-12-19 02:21:03 +0000297 #if JCS_ALPHA_EXTENSIONS==1
298 case TJPF_RGBA:
299 dinfo->out_color_space=JCS_EXT_RGBA; break;
300 case TJPF_BGRA:
301 dinfo->out_color_space=JCS_EXT_BGRA; break;
302 case TJPF_ARGB:
303 dinfo->out_color_space=JCS_EXT_ARGB; break;
304 case TJPF_ABGR:
305 dinfo->out_color_space=JCS_EXT_ABGR; break;
306 #endif
DRC9b28def2011-05-21 14:37:15 +0000307 #else
DRC25b995a2011-05-21 15:34:54 +0000308 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000309 case TJPF_BGR:
310 case TJPF_RGBX:
311 case TJPF_BGRX:
312 case TJPF_XRGB:
313 case TJPF_XBGR:
314 case TJPF_RGBA:
315 case TJPF_BGRA:
316 case TJPF_ARGB:
317 case TJPF_ABGR:
318 dinfo->out_color_space=JCS_RGB; break;
DRC67ce3b22011-12-19 02:21:03 +0000319 #endif
DRCcd7c3e62013-08-23 02:49:25 +0000320 case TJPF_CMYK:
321 dinfo->out_color_space=JCS_CMYK; break;
DRC9b28def2011-05-21 14:37:15 +0000322 default:
323 _throw("Unsupported pixel format");
DRC9b28def2011-05-21 14:37:15 +0000324 }
DRCf12bb302011-09-07 05:03:18 +0000325
DRC73d74c12012-06-29 23:46:38 +0000326 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
327
DRCf12bb302011-09-07 05:03:18 +0000328 bailout:
DRCf12bb302011-09-07 05:03:18 +0000329 return retval;
DRC9b28def2011-05-21 14:37:15 +0000330}
331
332
DRC9b49f0e2011-07-12 03:17:23 +0000333static int getSubsamp(j_decompress_ptr dinfo)
334{
335 int retval=-1, i, k;
DRCea1eea42014-11-19 00:55:28 +0000336
337 /* The sampling factors actually have no meaning with grayscale JPEG files,
338 and in fact it's possible to generate grayscale JPEGs with sampling
339 factors > 1 (even though those sampling factors are ignored by the
340 decompressor.) Thus, we need to treat grayscale as a special case. */
341 if(dinfo->num_components==1 && dinfo->jpeg_color_space==JCS_GRAYSCALE)
342 return TJSAMP_GRAY;
343
DRC9b49f0e2011-07-12 03:17:23 +0000344 for(i=0; i<NUMSUBOPT; i++)
345 {
DRCcd7c3e62013-08-23 02:49:25 +0000346 if(dinfo->num_components==pixelsize[i]
347 || ((dinfo->jpeg_color_space==JCS_YCCK
348 || dinfo->jpeg_color_space==JCS_CMYK)
349 && pixelsize[i]==3 && dinfo->num_components==4))
DRC9b49f0e2011-07-12 03:17:23 +0000350 {
351 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
352 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
353 {
354 int match=0;
355 for(k=1; k<dinfo->num_components; k++)
356 {
DRCcd7c3e62013-08-23 02:49:25 +0000357 int href=1, vref=1;
358 if(dinfo->jpeg_color_space==JCS_YCCK && k==3)
359 {
360 href=tjMCUWidth[i]/8; vref=tjMCUHeight[i]/8;
361 }
362 if(dinfo->comp_info[k].h_samp_factor==href
363 && dinfo->comp_info[k].v_samp_factor==vref)
DRC9b49f0e2011-07-12 03:17:23 +0000364 match++;
365 }
366 if(match==dinfo->num_components-1)
367 {
368 retval=i; break;
369 }
370 }
371 }
372 }
373 return retval;
374}
375
376
DRCafc06922012-03-23 19:47:57 +0000377#ifndef JCS_EXTENSIONS
378
379/* Conversion functions to emulate the colorspace extensions. This allows the
380 TurboJPEG wrapper to be used with libjpeg */
381
382#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
383 int rowPad=pitch-width*PS; \
384 while(height--) \
385 { \
386 unsigned char *endOfRow=src+width*PS; \
387 while(src<endOfRow) \
388 { \
389 dst[RGB_RED]=src[ROFFSET]; \
390 dst[RGB_GREEN]=src[GOFFSET]; \
391 dst[RGB_BLUE]=src[BOFFSET]; \
392 dst+=RGB_PIXELSIZE; src+=PS; \
393 } \
394 src+=rowPad; \
395 } \
396}
397
398static unsigned char *toRGB(unsigned char *src, int width, int pitch,
399 int height, int pixelFormat, unsigned char *dst)
400{
401 unsigned char *retval=src;
402 switch(pixelFormat)
403 {
404 case TJPF_RGB:
405 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
406 retval=dst; TORGB(3, 0, 1, 2);
407 #endif
408 break;
409 case TJPF_BGR:
410 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
411 retval=dst; TORGB(3, 2, 1, 0);
412 #endif
413 break;
414 case TJPF_RGBX:
415 case TJPF_RGBA:
416 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
417 retval=dst; TORGB(4, 0, 1, 2);
418 #endif
419 break;
420 case TJPF_BGRX:
421 case TJPF_BGRA:
422 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
423 retval=dst; TORGB(4, 2, 1, 0);
424 #endif
425 break;
426 case TJPF_XRGB:
427 case TJPF_ARGB:
428 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
429 retval=dst; TORGB(4, 1, 2, 3);
430 #endif
431 break;
432 case TJPF_XBGR:
433 case TJPF_ABGR:
434 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
435 retval=dst; TORGB(4, 3, 2, 1);
436 #endif
437 break;
438 }
439 return retval;
440}
441
442#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
443 int rowPad=pitch-width*PS; \
444 while(height--) \
445 { \
446 unsigned char *endOfRow=dst+width*PS; \
447 while(dst<endOfRow) \
448 { \
449 dst[ROFFSET]=src[RGB_RED]; \
450 dst[GOFFSET]=src[RGB_GREEN]; \
451 dst[BOFFSET]=src[RGB_BLUE]; \
452 SETALPHA \
453 dst+=PS; src+=RGB_PIXELSIZE; \
454 } \
455 dst+=rowPad; \
456 } \
457}
458
459static void fromRGB(unsigned char *src, unsigned char *dst, int width,
460 int pitch, int height, int pixelFormat)
461{
462 switch(pixelFormat)
463 {
464 case TJPF_RGB:
465 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
466 FROMRGB(3, 0, 1, 2,);
467 #endif
468 break;
469 case TJPF_BGR:
470 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
471 FROMRGB(3, 2, 1, 0,);
472 #endif
473 break;
474 case TJPF_RGBX:
475 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
476 FROMRGB(4, 0, 1, 2,);
477 #endif
478 break;
479 case TJPF_RGBA:
480 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
481 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
482 #endif
483 break;
484 case TJPF_BGRX:
485 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
486 FROMRGB(4, 2, 1, 0,);
487 #endif
488 break;
489 case TJPF_BGRA:
490 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
491 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
492 #endif
493 break;
494 case TJPF_XRGB:
495 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
496 FROMRGB(4, 1, 2, 3,); return;
497 #endif
498 break;
499 case TJPF_ARGB:
500 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
501 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
502 #endif
503 break;
504 case TJPF_XBGR:
505 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
506 FROMRGB(4, 3, 2, 1,); return;
507 #endif
508 break;
509 case TJPF_ABGR:
510 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
511 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
512 #endif
513 break;
514 }
515}
516
517#endif
518
519
DRC9b28def2011-05-21 14:37:15 +0000520/* General API functions */
521
522DLLEXPORT char* DLLCALL tjGetErrorStr(void)
523{
524 return errStr;
525}
526
527
528DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
529{
530 getinstance(handle);
531 if(setjmp(this->jerr.setjmp_buffer)) return -1;
532 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
533 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
534 free(this);
535 return 0;
536}
537
538
DRC6b76f752011-05-24 16:52:47 +0000539/* These are exposed mainly because Windows can't malloc() and free() across
540 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
541 with turbojpeg.dll for compatibility reasons. However, these functions
542 can potentially be used for other purposes by different implementations. */
543
544DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
545{
546 if(buf) free(buf);
547}
548
549
550DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
551{
552 return (unsigned char *)malloc(bytes);
553}
554
555
DRC9b28def2011-05-21 14:37:15 +0000556/* Compressor */
557
558static tjhandle _tjInitCompress(tjinstance *this)
559{
560 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
561
562 /* This is also straight out of example.c */
563 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
564 this->jerr.pub.error_exit=my_error_exit;
565 this->jerr.pub.output_message=my_output_message;
DRC1f79c7c2015-06-01 19:22:41 +0000566 this->jerr.emit_message=this->jerr.pub.emit_message;
567 this->jerr.pub.emit_message=my_emit_message;
DRC9b28def2011-05-21 14:37:15 +0000568
569 if(setjmp(this->jerr.setjmp_buffer))
570 {
571 /* If we get here, the JPEG code has signaled an error. */
572 if(this) free(this); return NULL;
573 }
574
575 jpeg_create_compress(&this->cinfo);
576 /* Make an initial call so it will create the destination manager */
577 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
578
DRC007a42c2011-05-22 13:55:56 +0000579 this->init|=COMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000580 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000581}
582
DRC890f1e02011-02-26 22:02:37 +0000583DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
584{
DRC9b28def2011-05-21 14:37:15 +0000585 tjinstance *this=NULL;
586 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000587 {
DRC007a42c2011-05-22 13:55:56 +0000588 snprintf(errStr, JMSG_LENGTH_MAX,
589 "tjInitCompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000590 return NULL;
591 }
DRC007a42c2011-05-22 13:55:56 +0000592 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +0000593 return _tjInitCompress(this);
DRC890f1e02011-02-26 22:02:37 +0000594}
595
DRC84241602011-02-25 02:08:23 +0000596
DRC9b49f0e2011-07-12 03:17:23 +0000597DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
598 int jpegSubsamp)
599{
600 unsigned long retval=0; int mcuw, mcuh, chromasf;
601 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
602 _throw("tjBufSize(): Invalid argument");
603
DRC006bc582014-02-27 21:22:54 +0000604 /* This allows for rare corner cases in which a JPEG image can actually be
605 larger than the uncompressed input (we wouldn't mention it if it hadn't
606 happened before.) */
DRC9b49f0e2011-07-12 03:17:23 +0000607 mcuw=tjMCUWidth[jpegSubsamp];
608 mcuh=tjMCUHeight[jpegSubsamp];
609 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
610 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
611
612 bailout:
613 return retval;
614}
615
DRC2e7b76b2009-04-03 12:04:24 +0000616DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
617{
DRCf3cf9732011-02-22 00:16:14 +0000618 unsigned long retval=0;
619 if(width<1 || height<1)
DRC007a42c2011-05-22 13:55:56 +0000620 _throw("TJBUFSIZE(): Invalid argument");
DRCf3cf9732011-02-22 00:16:14 +0000621
DRC006bc582014-02-27 21:22:54 +0000622 /* This allows for rare corner cases in which a JPEG image can actually be
623 larger than the uncompressed input (we wouldn't mention it if it hadn't
624 happened before.) */
DRC007a42c2011-05-22 13:55:56 +0000625 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
DRCf3cf9732011-02-22 00:16:14 +0000626
627 bailout:
628 return retval;
629}
630
DRC84241602011-02-25 02:08:23 +0000631
DRCf610d612013-04-26 10:33:29 +0000632DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
DRCf3cf9732011-02-22 00:16:14 +0000633 int subsamp)
634{
DRC40dd3142014-08-17 12:23:49 +0000635 int retval=0, nc, i;
636
637 if(subsamp<0 || subsamp>=NUMSUBOPT)
DRCf610d612013-04-26 10:33:29 +0000638 _throw("tjBufSizeYUV2(): Invalid argument");
DRC40dd3142014-08-17 12:23:49 +0000639
640 nc=(subsamp==TJSAMP_GRAY? 1:3);
641 for(i=0; i<nc; i++)
642 {
DRC55620c62014-10-23 19:08:14 +0000643 int pw=tjPlaneWidth(i, width, subsamp);
644 int stride=PAD(pw, pad);
DRC40dd3142014-08-17 12:23:49 +0000645 int ph=tjPlaneHeight(i, height, subsamp);
DRC55620c62014-10-23 19:08:14 +0000646 if(pw<0 || ph<0) return -1;
DRC40dd3142014-08-17 12:23:49 +0000647 else retval+=stride*ph;
648 }
DRCf3cf9732011-02-22 00:16:14 +0000649
650 bailout:
651 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000652}
653
DRCf610d612013-04-26 10:33:29 +0000654DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
655 int subsamp)
656{
657 return tjBufSizeYUV2(width, 4, height, subsamp);
658}
DRC84241602011-02-25 02:08:23 +0000659
DRC9b49f0e2011-07-12 03:17:23 +0000660DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
661 int subsamp)
662{
663 return tjBufSizeYUV(width, height, subsamp);
664}
665
666
DRC40dd3142014-08-17 12:23:49 +0000667DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
668{
669 int pw, nc, retval=0;
670
671 if(width<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
672 _throw("tjPlaneWidth(): Invalid argument");
673 nc=(subsamp==TJSAMP_GRAY? 1:3);
674 if(componentID<0 || componentID>=nc)
675 _throw("tjPlaneWidth(): Invalid argument");
676
677 pw=PAD(width, tjMCUWidth[subsamp]/8);
678 if(componentID==0)
679 retval=pw;
680 else
681 retval=pw*8/tjMCUWidth[subsamp];
682
683 bailout:
684 return retval;
685}
686
687
688DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
689{
690 int ph, nc, retval=0;
691
692 if(height<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
693 _throw("tjPlaneHeight(): Invalid argument");
694 nc=(subsamp==TJSAMP_GRAY? 1:3);
695 if(componentID<0 || componentID>=nc)
696 _throw("tjPlaneHeight(): Invalid argument");
697
698 ph=PAD(height, tjMCUHeight[subsamp]/8);
699 if(componentID==0)
700 retval=ph;
701 else
702 retval=ph*8/tjMCUHeight[subsamp];
703
704 bailout:
705 return retval;
706}
707
708
709DLLEXPORT unsigned long DLLCALL tjPlaneSizeYUV(int componentID, int width,
710 int stride, int height, int subsamp)
711{
712 unsigned long retval=0;
713 int pw, ph;
714
715 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
716 _throw("tjPlaneSizeYUV(): Invalid argument");
717
718 pw=tjPlaneWidth(componentID, width, subsamp);
719 ph=tjPlaneHeight(componentID, height, subsamp);
DRC22409742014-10-23 18:54:42 +0000720 if(pw<0 || ph<0) return -1;
DRC40dd3142014-08-17 12:23:49 +0000721
722 if(stride==0) stride=pw;
723 else stride=abs(stride);
724
725 retval=stride*(ph-1)+pw;
726
727 bailout:
728 return retval;
729}
730
731
DRC6fa14b32015-08-13 20:06:03 -0500732DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, const unsigned char *srcBuf,
DRC9b28def2011-05-21 14:37:15 +0000733 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
734 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
735{
DRCff78e372011-05-24 10:17:32 +0000736 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
DRCafc06922012-03-23 19:47:57 +0000737 #ifndef JCS_EXTENSIONS
738 unsigned char *rgbBuf=NULL;
739 #endif
DRC9b28def2011-05-21 14:37:15 +0000740
DRC41861622014-04-16 23:38:37 +0000741 getcinstance(handle)
DRC9b28def2011-05-21 14:37:15 +0000742 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000743 _throw("tjCompress2(): Instance has not been initialized for compression");
DRC9b28def2011-05-21 14:37:15 +0000744
745 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
746 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
747 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
DRC007a42c2011-05-22 13:55:56 +0000748 _throw("tjCompress2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000749
750 if(setjmp(this->jerr.setjmp_buffer))
751 {
752 /* If we get here, the JPEG code has signaled an error. */
753 retval=-1;
754 goto bailout;
755 }
756
757 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
758
DRCafc06922012-03-23 19:47:57 +0000759 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +0000760 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
DRCafc06922012-03-23 19:47:57 +0000761 {
762 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
763 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
764 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
765 pitch=width*RGB_PIXELSIZE;
766 }
767 #endif
768
DRC9b28def2011-05-21 14:37:15 +0000769 cinfo->image_width=width;
770 cinfo->image_height=height;
771
DRCbec45b12015-05-17 15:56:18 +0000772 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
773 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
774 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000775
DRCff78e372011-05-24 10:17:32 +0000776 if(flags&TJFLAG_NOREALLOC)
777 {
DRC9b49f0e2011-07-12 03:17:23 +0000778 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +0000779 }
780 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
DRC73d74c12012-06-29 23:46:38 +0000781 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
DRCf12bb302011-09-07 05:03:18 +0000782 return -1;
DRC9b28def2011-05-21 14:37:15 +0000783
784 jpeg_start_compress(cinfo, TRUE);
785 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
DRC007a42c2011-05-22 13:55:56 +0000786 _throw("tjCompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000787 for(i=0; i<height; i++)
788 {
DRC6fa14b32015-08-13 20:06:03 -0500789 if(flags&TJFLAG_BOTTOMUP)
790 row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
791 else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
DRC9b28def2011-05-21 14:37:15 +0000792 }
793 while(cinfo->next_scanline<cinfo->image_height)
794 {
795 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
796 cinfo->image_height-cinfo->next_scanline);
797 }
798 jpeg_finish_compress(cinfo);
799
800 bailout:
801 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000802 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000803 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000804 #endif
DRC9b28def2011-05-21 14:37:15 +0000805 if(row_pointer) free(row_pointer);
DRC1f79c7c2015-06-01 19:22:41 +0000806 if(this->jerr.warning) retval=-1;
DRC9b28def2011-05-21 14:37:15 +0000807 return retval;
808}
809
810DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
811 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
812 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
813{
814 int retval=0; unsigned long size;
815 if(flags&TJ_YUV)
816 {
DRC9b49f0e2011-07-12 03:17:23 +0000817 size=tjBufSizeYUV(width, height, jpegSubsamp);
DRC9b28def2011-05-21 14:37:15 +0000818 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
819 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
820 }
821 else
822 {
DRC9b28def2011-05-21 14:37:15 +0000823 retval=tjCompress2(handle, srcBuf, width, pitch, height,
824 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
DRC25b995a2011-05-21 15:34:54 +0000825 flags|TJFLAG_NOREALLOC);
DRC9b28def2011-05-21 14:37:15 +0000826 }
827 *jpegSize=size;
828 return retval;
829}
830
831
DRC6fa14b32015-08-13 20:06:03 -0500832DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle,
833 const unsigned char *srcBuf, int width, int pitch, int height,
834 int pixelFormat, unsigned char **dstPlanes, int *strides, int subsamp,
835 int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000836{
DRC91e86ba2011-02-15 05:24:08 +0000837 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000838 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
839 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
840 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +0000841 int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +0000842 JSAMPLE *ptr;
DRC9b28def2011-05-21 14:37:15 +0000843 jpeg_component_info *compptr;
DRCafc06922012-03-23 19:47:57 +0000844 #ifndef JCS_EXTENSIONS
845 unsigned char *rgbBuf=NULL;
846 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000847
DRC41861622014-04-16 23:38:37 +0000848 getcinstance(handle);
DRCb51ee892013-10-31 05:00:19 +0000849
DRCfbb67472010-11-24 04:02:37 +0000850 for(i=0; i<MAX_COMPONENTS; i++)
851 {
852 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
853 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
854 }
855
DRCe2f8e692013-10-30 22:21:06 +0000856 if((this->init&COMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +0000857 _throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
DRCe2f8e692013-10-30 22:21:06 +0000858
DRC9b28def2011-05-21 14:37:15 +0000859 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
DRCaecea382014-08-11 18:05:41 +0000860 || pixelFormat>=TJ_NUMPF || !dstPlanes || !dstPlanes[0] || subsamp<0
861 || subsamp>=NUMSUBOPT)
862 _throw("tjEncodeYUVPlanes(): Invalid argument");
863 if(subsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
864 _throw("tjEncodeYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000865
DRC9b28def2011-05-21 14:37:15 +0000866 if(setjmp(this->jerr.setjmp_buffer))
867 {
868 /* If we get here, the JPEG code has signaled an error. */
869 retval=-1;
870 goto bailout;
871 }
DRC2e7b76b2009-04-03 12:04:24 +0000872
DRCcd7c3e62013-08-23 02:49:25 +0000873 if(pixelFormat==TJPF_CMYK)
DRCaecea382014-08-11 18:05:41 +0000874 _throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
DRCcd7c3e62013-08-23 02:49:25 +0000875
DRC9b28def2011-05-21 14:37:15 +0000876 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC2e7b76b2009-04-03 12:04:24 +0000877
DRCafc06922012-03-23 19:47:57 +0000878 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +0000879 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
DRCafc06922012-03-23 19:47:57 +0000880 {
881 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
DRCaecea382014-08-11 18:05:41 +0000882 if(!rgbBuf) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRCafc06922012-03-23 19:47:57 +0000883 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
884 pitch=width*RGB_PIXELSIZE;
885 }
886 #endif
887
DRC9b28def2011-05-21 14:37:15 +0000888 cinfo->image_width=width;
889 cinfo->image_height=height;
DRC2e7b76b2009-04-03 12:04:24 +0000890
DRCbec45b12015-05-17 15:56:18 +0000891 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
892 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
893 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000894
DRC73d74c12012-06-29 23:46:38 +0000895 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000896
DRC38c99702014-02-11 09:45:18 +0000897 /* Execute only the parts of jpeg_start_compress() that we need. If we
898 were to call the whole jpeg_start_compress() function, then it would try
899 to write the file headers, which could overflow the output buffer if the
900 YUV image were very small. */
901 if(cinfo->global_state!=CSTATE_START)
DRCaecea382014-08-11 18:05:41 +0000902 _throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
DRC38c99702014-02-11 09:45:18 +0000903 (*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
DRC38c99702014-02-11 09:45:18 +0000904 jinit_c_master_control(cinfo, FALSE);
905 jinit_color_converter(cinfo);
906 jinit_downsampler(cinfo);
DRC50cfc462014-03-06 20:03:37 +0000907 (*cinfo->cconvert->start_pass)(cinfo);
DRC38c99702014-02-11 09:45:18 +0000908
DRC40dd3142014-08-17 12:23:49 +0000909 pw0=PAD(width, cinfo->max_h_samp_factor);
910 ph0=PAD(height, cinfo->max_v_samp_factor);
DRC2e7b76b2009-04-03 12:04:24 +0000911
DRC40dd3142014-08-17 12:23:49 +0000912 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
DRCaecea382014-08-11 18:05:41 +0000913 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000914 for(i=0; i<height; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000915 {
DRC6fa14b32015-08-13 20:06:03 -0500916 if(flags&TJFLAG_BOTTOMUP)
917 row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
918 else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
DRC9b28def2011-05-21 14:37:15 +0000919 }
DRC40dd3142014-08-17 12:23:49 +0000920 if(height<ph0)
921 for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
DRCfbb67472010-11-24 04:02:37 +0000922
DRC9b28def2011-05-21 14:37:15 +0000923 for(i=0; i<cinfo->num_components; i++)
924 {
925 compptr=&cinfo->comp_info[i];
926 _tmpbuf[i]=(JSAMPLE *)malloc(
927 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
928 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRCaecea382014-08-11 18:05:41 +0000929 if(!_tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000930 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRCaecea382014-08-11 18:05:41 +0000931 if(!tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000932 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRCfbb67472010-11-24 04:02:37 +0000933 {
DRC9b28def2011-05-21 14:37:15 +0000934 unsigned char *_tmpbuf_aligned=
935 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
936 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000937 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC9b28def2011-05-21 14:37:15 +0000938 /compptr->h_samp_factor, 16) * row];
DRCfbb67472010-11-24 04:02:37 +0000939 }
DRC9b28def2011-05-21 14:37:15 +0000940 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
941 * compptr->v_samp_factor + 16);
DRCaecea382014-08-11 18:05:41 +0000942 if(!_tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000943 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCaecea382014-08-11 18:05:41 +0000944 if(!tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000945 for(row=0; row<compptr->v_samp_factor; row++)
946 {
947 unsigned char *_tmpbuf2_aligned=
948 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
949 tmpbuf2[i][row]=&_tmpbuf2_aligned[
950 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
951 }
DRC40dd3142014-08-17 12:23:49 +0000952 pw[i]=pw0*compptr->h_samp_factor/cinfo->max_h_samp_factor;
953 ph[i]=ph0*compptr->v_samp_factor/cinfo->max_v_samp_factor;
954 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
DRCaecea382014-08-11 18:05:41 +0000955 if(!outbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
956 ptr=dstPlanes[i];
DRC40dd3142014-08-17 12:23:49 +0000957 for(row=0; row<ph[i]; row++)
DRC9b28def2011-05-21 14:37:15 +0000958 {
959 outbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +0000960 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC9b28def2011-05-21 14:37:15 +0000961 }
962 }
DRCfbb67472010-11-24 04:02:37 +0000963
DRC40dd3142014-08-17 12:23:49 +0000964 for(row=0; row<ph0; row+=cinfo->max_v_samp_factor)
DRCfbb67472010-11-24 04:02:37 +0000965 {
DRC9b28def2011-05-21 14:37:15 +0000966 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
967 cinfo->max_v_samp_factor);
968 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
969 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
970 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
971 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
DRC40dd3142014-08-17 12:23:49 +0000972 compptr->v_samp_factor, pw[i]);
DRC6ee54592011-03-01 08:18:30 +0000973 }
DRC9b28def2011-05-21 14:37:15 +0000974 cinfo->next_scanline+=height;
975 jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000976
DRC91e86ba2011-02-15 05:24:08 +0000977 bailout:
DRC9b28def2011-05-21 14:37:15 +0000978 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000979 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000980 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000981 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000982 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000983 for(i=0; i<MAX_COMPONENTS; i++)
984 {
985 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000986 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000987 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000988 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000989 if(outbuf[i]!=NULL) free(outbuf[i]);
990 }
DRC1f79c7c2015-06-01 19:22:41 +0000991 if(this->jerr.warning) retval=-1;
DRC91e86ba2011-02-15 05:24:08 +0000992 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000993}
994
DRC6fa14b32015-08-13 20:06:03 -0500995DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle,
996 const unsigned char *srcBuf, int width, int pitch, int height,
997 int pixelFormat, unsigned char *dstBuf, int pad, int subsamp, int flags)
DRCaecea382014-08-11 18:05:41 +0000998{
999 unsigned char *dstPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001000 int pw0, ph0, strides[3], retval=-1;
DRCaecea382014-08-11 18:05:41 +00001001
1002 if(width<=0 || height<=0 || dstBuf==NULL || pad<0 || !isPow2(pad)
1003 || subsamp<0 || subsamp>=NUMSUBOPT)
1004 _throw("tjEncodeYUV3(): Invalid argument");
1005
DRC40dd3142014-08-17 12:23:49 +00001006 pw0=tjPlaneWidth(0, width, subsamp);
1007 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +00001008 dstPlanes[0]=dstBuf;
DRC40dd3142014-08-17 12:23:49 +00001009 strides[0]=PAD(pw0, pad);
1010 if(subsamp==TJSAMP_GRAY)
1011 {
1012 strides[1]=strides[2]=0;
1013 dstPlanes[1]=dstPlanes[2]=NULL;
1014 }
1015 else
1016 {
1017 int pw1=tjPlaneWidth(1, width, subsamp);
1018 int ph1=tjPlaneHeight(1, height, subsamp);
1019 strides[1]=strides[2]=PAD(pw1, pad);
1020 dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1021 dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1022 }
DRCaecea382014-08-11 18:05:41 +00001023
1024 return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
1025 dstPlanes, strides, subsamp, flags);
1026
1027 bailout:
1028 return retval;
1029}
1030
DRCf610d612013-04-26 10:33:29 +00001031DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
1032 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
1033 int subsamp, int flags)
1034{
1035 return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
1036 dstBuf, 4, subsamp, flags);
1037}
1038
DRC9b28def2011-05-21 14:37:15 +00001039DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
1040 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
1041 int subsamp, int flags)
DRC84241602011-02-25 02:08:23 +00001042{
DRC9b28def2011-05-21 14:37:15 +00001043 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1044 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
DRC84241602011-02-25 02:08:23 +00001045}
1046
1047
DRCaecea382014-08-11 18:05:41 +00001048DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle,
DRC6fa14b32015-08-13 20:06:03 -05001049 const unsigned char **srcPlanes, int width, const int *strides, int height,
1050 int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual,
1051 int flags)
DRC910a3572013-10-30 23:02:57 +00001052{
1053 int i, row, retval=0, alloc=1; JSAMPROW *inbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +00001054 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
DRC910a3572013-10-30 23:02:57 +00001055 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001056 JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC910a3572013-10-30 23:02:57 +00001057
DRC41861622014-04-16 23:38:37 +00001058 getcinstance(handle)
DRCb51ee892013-10-31 05:00:19 +00001059
DRC910a3572013-10-30 23:02:57 +00001060 for(i=0; i<MAX_COMPONENTS; i++)
1061 {
1062 tmpbuf[i]=NULL; inbuf[i]=NULL;
1063 }
1064
DRC910a3572013-10-30 23:02:57 +00001065 if((this->init&COMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001066 _throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
DRC910a3572013-10-30 23:02:57 +00001067
DRCaecea382014-08-11 18:05:41 +00001068 if(!srcPlanes || !srcPlanes[0] || width<=0 || height<=0 || subsamp<0
DRC910a3572013-10-30 23:02:57 +00001069 || subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0
1070 || jpegQual>100)
DRCaecea382014-08-11 18:05:41 +00001071 _throw("tjCompressFromYUVPlanes(): Invalid argument");
1072 if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1073 _throw("tjCompressFromYUVPlanes(): Invalid argument");
DRC910a3572013-10-30 23:02:57 +00001074
1075 if(setjmp(this->jerr.setjmp_buffer))
1076 {
1077 /* If we get here, the JPEG code has signaled an error. */
1078 retval=-1;
1079 goto bailout;
1080 }
1081
1082 cinfo->image_width=width;
1083 cinfo->image_height=height;
1084
DRCbec45b12015-05-17 15:56:18 +00001085 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1086 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1087 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC910a3572013-10-30 23:02:57 +00001088
1089 if(flags&TJFLAG_NOREALLOC)
1090 {
1091 alloc=0; *jpegSize=tjBufSize(width, height, subsamp);
1092 }
1093 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1094 if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1)
1095 return -1;
1096 cinfo->raw_data_in=TRUE;
1097
1098 jpeg_start_compress(cinfo, TRUE);
1099 for(i=0; i<cinfo->num_components; i++)
1100 {
1101 jpeg_component_info *compptr=&cinfo->comp_info[i];
1102 int ih;
1103 iw[i]=compptr->width_in_blocks*DCTSIZE;
1104 ih=compptr->height_in_blocks*DCTSIZE;
DRC40dd3142014-08-17 12:23:49 +00001105 pw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor)
DRC910a3572013-10-30 23:02:57 +00001106 *compptr->h_samp_factor/cinfo->max_h_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001107 ph[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor)
DRC910a3572013-10-30 23:02:57 +00001108 *compptr->v_samp_factor/cinfo->max_v_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001109 if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
DRC910a3572013-10-30 23:02:57 +00001110 th[i]=compptr->v_samp_factor*DCTSIZE;
1111 tmpbufsize+=iw[i]*th[i];
DRC40dd3142014-08-17 12:23:49 +00001112 if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001113 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
DRC6fa14b32015-08-13 20:06:03 -05001114 ptr=(JSAMPLE *)srcPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001115 for(row=0; row<ph[i]; row++)
DRC910a3572013-10-30 23:02:57 +00001116 {
1117 inbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001118 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC910a3572013-10-30 23:02:57 +00001119 }
1120 }
1121 if(usetmpbuf)
1122 {
1123 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRCaecea382014-08-11 18:05:41 +00001124 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
DRC910a3572013-10-30 23:02:57 +00001125 ptr=_tmpbuf;
1126 for(i=0; i<cinfo->num_components; i++)
1127 {
1128 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001129 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
DRC910a3572013-10-30 23:02:57 +00001130 for(row=0; row<th[i]; row++)
1131 {
1132 tmpbuf[i][row]=ptr;
1133 ptr+=iw[i];
1134 }
1135 }
1136 }
1137
1138 for(row=0; row<(int)cinfo->image_height;
1139 row+=cinfo->max_v_samp_factor*DCTSIZE)
1140 {
1141 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1142 int crow[MAX_COMPONENTS];
1143 for(i=0; i<cinfo->num_components; i++)
1144 {
1145 jpeg_component_info *compptr=&cinfo->comp_info[i];
1146 crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor;
1147 if(usetmpbuf)
1148 {
1149 int j, k;
DRC40dd3142014-08-17 12:23:49 +00001150 for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
DRC910a3572013-10-30 23:02:57 +00001151 {
DRC40dd3142014-08-17 12:23:49 +00001152 memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], pw[i]);
DRC006bc582014-02-27 21:22:54 +00001153 /* Duplicate last sample in row to fill out MCU */
DRC40dd3142014-08-17 12:23:49 +00001154 for(k=pw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][pw[i]-1];
DRC910a3572013-10-30 23:02:57 +00001155 }
DRC006bc582014-02-27 21:22:54 +00001156 /* Duplicate last row to fill out MCU */
DRC40dd3142014-08-17 12:23:49 +00001157 for(j=ph[i]-crow[i]; j<th[i]; j++)
1158 memcpy(tmpbuf[i][j], tmpbuf[i][ph[i]-crow[i]-1], iw[i]);
DRC910a3572013-10-30 23:02:57 +00001159 yuvptr[i]=tmpbuf[i];
1160 }
1161 else
1162 yuvptr[i]=&inbuf[i][crow[i]];
1163 }
1164 jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE);
1165 }
1166 jpeg_finish_compress(cinfo);
1167
1168 bailout:
1169 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1170 for(i=0; i<MAX_COMPONENTS; i++)
1171 {
1172 if(tmpbuf[i]) free(tmpbuf[i]);
1173 if(inbuf[i]) free(inbuf[i]);
1174 }
1175 if(_tmpbuf) free(_tmpbuf);
DRC1f79c7c2015-06-01 19:22:41 +00001176 if(this->jerr.warning) retval=-1;
DRC910a3572013-10-30 23:02:57 +00001177 return retval;
1178}
1179
DRC6fa14b32015-08-13 20:06:03 -05001180DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle,
1181 const unsigned char *srcBuf, int width, int pad, int height, int subsamp,
1182 unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)
DRCaecea382014-08-11 18:05:41 +00001183{
DRC6fa14b32015-08-13 20:06:03 -05001184 const unsigned char *srcPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001185 int pw0, ph0, strides[3], retval=-1;
DRCaecea382014-08-11 18:05:41 +00001186
1187 if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
1188 || subsamp>=NUMSUBOPT)
1189 _throw("tjCompressFromYUV(): Invalid argument");
1190
DRC40dd3142014-08-17 12:23:49 +00001191 pw0=tjPlaneWidth(0, width, subsamp);
1192 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +00001193 srcPlanes[0]=srcBuf;
DRC40dd3142014-08-17 12:23:49 +00001194 strides[0]=PAD(pw0, pad);
1195 if(subsamp==TJSAMP_GRAY)
1196 {
1197 strides[1]=strides[2]=0;
1198 srcPlanes[1]=srcPlanes[2]=NULL;
1199 }
1200 else
1201 {
1202 int pw1=tjPlaneWidth(1, width, subsamp);
1203 int ph1=tjPlaneHeight(1, height, subsamp);
1204 strides[1]=strides[2]=PAD(pw1, pad);
1205 srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1206 srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1207 }
DRCaecea382014-08-11 18:05:41 +00001208
1209 return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1210 subsamp, jpegBuf, jpegSize, jpegQual, flags);
1211
1212 bailout:
1213 return retval;
1214}
1215
DRC910a3572013-10-30 23:02:57 +00001216
DRC9b28def2011-05-21 14:37:15 +00001217/* Decompressor */
DRC2e7b76b2009-04-03 12:04:24 +00001218
DRC9b28def2011-05-21 14:37:15 +00001219static tjhandle _tjInitDecompress(tjinstance *this)
DRC2e7b76b2009-04-03 12:04:24 +00001220{
DRC9b28def2011-05-21 14:37:15 +00001221 unsigned char buffer[1];
DRC2e7b76b2009-04-03 12:04:24 +00001222
DRC9b28def2011-05-21 14:37:15 +00001223 /* This is also straight out of example.c */
1224 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
1225 this->jerr.pub.error_exit=my_error_exit;
1226 this->jerr.pub.output_message=my_output_message;
DRC1f79c7c2015-06-01 19:22:41 +00001227 this->jerr.emit_message=this->jerr.pub.emit_message;
1228 this->jerr.pub.emit_message=my_emit_message;
DRC2e7b76b2009-04-03 12:04:24 +00001229
DRC9b28def2011-05-21 14:37:15 +00001230 if(setjmp(this->jerr.setjmp_buffer))
1231 {
1232 /* If we get here, the JPEG code has signaled an error. */
1233 if(this) free(this); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +00001234 }
DRC2e7b76b2009-04-03 12:04:24 +00001235
DRC9b28def2011-05-21 14:37:15 +00001236 jpeg_create_decompress(&this->dinfo);
1237 /* Make an initial call so it will create the source manager */
1238 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +00001239
DRC007a42c2011-05-22 13:55:56 +00001240 this->init|=DECOMPRESS;
DRC9b28def2011-05-21 14:37:15 +00001241 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +00001242}
1243
DRC890f1e02011-02-26 22:02:37 +00001244DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
1245{
DRC9b28def2011-05-21 14:37:15 +00001246 tjinstance *this;
1247 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00001248 {
DRC007a42c2011-05-22 13:55:56 +00001249 snprintf(errStr, JMSG_LENGTH_MAX,
1250 "tjInitDecompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00001251 return NULL;
1252 }
DRC007a42c2011-05-22 13:55:56 +00001253 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +00001254 return _tjInitDecompress(this);
DRC890f1e02011-02-26 22:02:37 +00001255}
1256
DRC2e7b76b2009-04-03 12:04:24 +00001257
DRCcd7c3e62013-08-23 02:49:25 +00001258DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
DRC6fa14b32015-08-13 20:06:03 -05001259 const unsigned char *jpegBuf, unsigned long jpegSize, int *width,
1260 int *height, int *jpegSubsamp, int *jpegColorspace)
DRC1fe80f82010-12-14 01:21:29 +00001261{
DRC9b49f0e2011-07-12 03:17:23 +00001262 int retval=0;
DRC1fe80f82010-12-14 01:21:29 +00001263
DRC41861622014-04-16 23:38:37 +00001264 getdinstance(handle);
DRC9b28def2011-05-21 14:37:15 +00001265 if((this->init&DECOMPRESS)==0)
DRCcd7c3e62013-08-23 02:49:25 +00001266 _throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
DRC1fe80f82010-12-14 01:21:29 +00001267
DRC9b28def2011-05-21 14:37:15 +00001268 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
DRCcd7c3e62013-08-23 02:49:25 +00001269 || jpegSubsamp==NULL || jpegColorspace==NULL)
1270 _throw("tjDecompressHeader3(): Invalid argument");
DRC1fe80f82010-12-14 01:21:29 +00001271
DRC9b28def2011-05-21 14:37:15 +00001272 if(setjmp(this->jerr.setjmp_buffer))
1273 {
1274 /* If we get here, the JPEG code has signaled an error. */
DRC1fe80f82010-12-14 01:21:29 +00001275 return -1;
1276 }
1277
DRC9b28def2011-05-21 14:37:15 +00001278 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1279 jpeg_read_header(dinfo, TRUE);
DRC1fe80f82010-12-14 01:21:29 +00001280
DRC9b28def2011-05-21 14:37:15 +00001281 *width=dinfo->image_width;
1282 *height=dinfo->image_height;
DRC9b49f0e2011-07-12 03:17:23 +00001283 *jpegSubsamp=getSubsamp(dinfo);
DRCcd7c3e62013-08-23 02:49:25 +00001284 switch(dinfo->jpeg_color_space)
1285 {
1286 case JCS_GRAYSCALE: *jpegColorspace=TJCS_GRAY; break;
1287 case JCS_RGB: *jpegColorspace=TJCS_RGB; break;
1288 case JCS_YCbCr: *jpegColorspace=TJCS_YCbCr; break;
1289 case JCS_CMYK: *jpegColorspace=TJCS_CMYK; break;
1290 case JCS_YCCK: *jpegColorspace=TJCS_YCCK; break;
1291 default: *jpegColorspace=-1; break;
1292 }
DRC1fe80f82010-12-14 01:21:29 +00001293
DRC9b28def2011-05-21 14:37:15 +00001294 jpeg_abort_decompress(dinfo);
DRC1fe80f82010-12-14 01:21:29 +00001295
DRC9b28def2011-05-21 14:37:15 +00001296 if(*jpegSubsamp<0)
DRCcd7c3e62013-08-23 02:49:25 +00001297 _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1298 if(*jpegColorspace<0)
1299 _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
DRC007a42c2011-05-22 13:55:56 +00001300 if(*width<1 || *height<1)
DRCcd7c3e62013-08-23 02:49:25 +00001301 _throw("tjDecompressHeader3(): Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +00001302
1303 bailout:
DRC1f79c7c2015-06-01 19:22:41 +00001304 if(this->jerr.warning) retval=-1;
DRC91e86ba2011-02-15 05:24:08 +00001305 return retval;
1306}
1307
DRCcd7c3e62013-08-23 02:49:25 +00001308DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
1309 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
1310 int *jpegSubsamp)
1311{
1312 int jpegColorspace;
1313 return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1314 jpegSubsamp, &jpegColorspace);
1315}
1316
DRC9b28def2011-05-21 14:37:15 +00001317DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
1318 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
DRC91e86ba2011-02-15 05:24:08 +00001319{
DRC9b28def2011-05-21 14:37:15 +00001320 int jpegSubsamp;
1321 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1322 &jpegSubsamp);
DRC1fe80f82010-12-14 01:21:29 +00001323}
1324
1325
DRC109a5782011-03-01 09:53:07 +00001326DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +00001327{
DRC109a5782011-03-01 09:53:07 +00001328 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +00001329 {
DRC9b28def2011-05-21 14:37:15 +00001330 snprintf(errStr, JMSG_LENGTH_MAX,
DRC007a42c2011-05-22 13:55:56 +00001331 "tjGetScalingFactors(): Invalid argument");
DRC109a5782011-03-01 09:53:07 +00001332 return NULL;
DRCb28fc572011-02-22 06:41:29 +00001333 }
1334
DRC109a5782011-03-01 09:53:07 +00001335 *numscalingfactors=NUMSF;
1336 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +00001337}
1338
1339
DRC6fa14b32015-08-13 20:06:03 -05001340DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
1341 const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1342 int width, int pitch, int height, int pixelFormat, int flags)
DRC2e7b76b2009-04-03 12:04:24 +00001343{
DRC9b28def2011-05-21 14:37:15 +00001344 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRC109a5782011-03-01 09:53:07 +00001345 int jpegwidth, jpegheight, scaledw, scaledh;
DRCafc06922012-03-23 19:47:57 +00001346 #ifndef JCS_EXTENSIONS
1347 unsigned char *rgbBuf=NULL;
1348 unsigned char *_dstBuf=NULL; int _pitch=0;
1349 #endif
DRC2e7b76b2009-04-03 12:04:24 +00001350
DRC41861622014-04-16 23:38:37 +00001351 getdinstance(handle);
DRC9b28def2011-05-21 14:37:15 +00001352 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001353 _throw("tjDecompress2(): Instance has not been initialized for decompression");
DRC9b28def2011-05-21 14:37:15 +00001354
1355 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
1356 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
1357 _throw("tjDecompress2(): Invalid argument");
1358
DRCbec45b12015-05-17 15:56:18 +00001359 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1360 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1361 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +00001362
1363 if(setjmp(this->jerr.setjmp_buffer))
1364 {
1365 /* If we get here, the JPEG code has signaled an error. */
1366 retval=-1;
1367 goto bailout;
1368 }
1369
1370 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1371 jpeg_read_header(dinfo, TRUE);
DRC73d74c12012-06-29 23:46:38 +00001372 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
DRC2eda8212012-03-23 19:32:38 +00001373 {
1374 retval=-1; goto bailout;
1375 }
DRC9b28def2011-05-21 14:37:15 +00001376
DRC25b995a2011-05-21 15:34:54 +00001377 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +00001378
1379 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1380 if(width==0) width=jpegwidth;
1381 if(height==0) height=jpegheight;
1382 for(i=0; i<NUMSF; i++)
1383 {
1384 scaledw=TJSCALED(jpegwidth, sf[i]);
1385 scaledh=TJSCALED(jpegheight, sf[i]);
1386 if(scaledw<=width && scaledh<=height)
DRCf610d612013-04-26 10:33:29 +00001387 break;
DRC9b28def2011-05-21 14:37:15 +00001388 }
DRC58ae4012015-08-26 20:29:36 -05001389 if(i>=NUMSF)
DRC007a42c2011-05-22 13:55:56 +00001390 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
DRC9b28def2011-05-21 14:37:15 +00001391 width=scaledw; height=scaledh;
1392 dinfo->scale_num=sf[i].num;
1393 dinfo->scale_denom=sf[i].denom;
1394
1395 jpeg_start_decompress(dinfo);
1396 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
DRCafc06922012-03-23 19:47:57 +00001397
1398 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +00001399 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
DRCafc06922012-03-23 19:47:57 +00001400 (RGB_RED!=tjRedOffset[pixelFormat] ||
1401 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1402 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1403 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1404 {
1405 rgbBuf=(unsigned char *)malloc(width*height*3);
1406 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1407 _pitch=pitch; pitch=width*3;
1408 _dstBuf=dstBuf; dstBuf=rgbBuf;
1409 }
1410 #endif
1411
DRC9b28def2011-05-21 14:37:15 +00001412 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1413 *dinfo->output_height))==NULL)
DRC007a42c2011-05-22 13:55:56 +00001414 _throw("tjDecompress2(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001415 for(i=0; i<(int)dinfo->output_height; i++)
1416 {
DRC25b995a2011-05-21 15:34:54 +00001417 if(flags&TJFLAG_BOTTOMUP)
DRC9b28def2011-05-21 14:37:15 +00001418 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1419 else row_pointer[i]=&dstBuf[i*pitch];
1420 }
1421 while(dinfo->output_scanline<dinfo->output_height)
1422 {
1423 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1424 dinfo->output_height-dinfo->output_scanline);
1425 }
1426 jpeg_finish_decompress(dinfo);
1427
DRCafc06922012-03-23 19:47:57 +00001428 #ifndef JCS_EXTENSIONS
1429 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1430 #endif
1431
DRC9b28def2011-05-21 14:37:15 +00001432 bailout:
1433 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRCafc06922012-03-23 19:47:57 +00001434 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +00001435 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +00001436 #endif
DRC9b28def2011-05-21 14:37:15 +00001437 if(row_pointer) free(row_pointer);
DRC1f79c7c2015-06-01 19:22:41 +00001438 if(this->jerr.warning) retval=-1;
DRC9b28def2011-05-21 14:37:15 +00001439 return retval;
1440}
1441
1442DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1443 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1444 int height, int pixelSize, int flags)
1445{
1446 if(flags&TJ_YUV)
1447 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1448 else
1449 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1450 height, getPixelFormat(pixelSize, flags), flags);
1451}
1452
1453
DRC34dca052014-02-28 09:17:14 +00001454static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
1455 int pixelFormat, int subsamp, int flags)
1456{
DRC895fd6d2014-02-28 09:35:34 +00001457 int i;
1458
DRC34dca052014-02-28 09:17:14 +00001459 dinfo->scale_num=dinfo->scale_denom=1;
1460
1461 if(subsamp==TJSAMP_GRAY)
1462 {
DRCc9014492014-03-10 09:34:04 +00001463 dinfo->num_components=dinfo->comps_in_scan=1;
DRC34dca052014-02-28 09:17:14 +00001464 dinfo->jpeg_color_space=JCS_GRAYSCALE;
1465 }
1466 else
1467 {
DRCc9014492014-03-10 09:34:04 +00001468 dinfo->num_components=dinfo->comps_in_scan=3;
DRC34dca052014-02-28 09:17:14 +00001469 dinfo->jpeg_color_space=JCS_YCbCr;
1470 }
1471
1472 dinfo->comp_info=(jpeg_component_info *)
1473 (*dinfo->mem->alloc_small)((j_common_ptr)dinfo, JPOOL_IMAGE,
DRC5de454b2014-05-18 19:04:03 +00001474 dinfo->num_components*sizeof(jpeg_component_info));
DRC34dca052014-02-28 09:17:14 +00001475
DRC2bdc0422014-03-07 03:52:57 +00001476 for(i=0; i<dinfo->num_components; i++)
DRC34dca052014-02-28 09:17:14 +00001477 {
DRC2bdc0422014-03-07 03:52:57 +00001478 jpeg_component_info *compptr=&dinfo->comp_info[i];
1479 compptr->h_samp_factor=(i==0)? tjMCUWidth[subsamp]/8:1;
1480 compptr->v_samp_factor=(i==0)? tjMCUHeight[subsamp]/8:1;
1481 compptr->component_index=i;
DRC15c08762014-03-10 20:11:56 +00001482 compptr->component_id=i+1;
DRC2bdc0422014-03-07 03:52:57 +00001483 compptr->quant_tbl_no=compptr->dc_tbl_no=compptr->ac_tbl_no=
1484 (i==0)? 0:1;
1485 dinfo->cur_comp_info[i]=compptr;
DRC34dca052014-02-28 09:17:14 +00001486 }
DRCc9014492014-03-10 09:34:04 +00001487 dinfo->data_precision=8;
1488 for(i=0; i<2; i++)
1489 {
1490 if(dinfo->quant_tbl_ptrs[i]==NULL)
1491 dinfo->quant_tbl_ptrs[i]=jpeg_alloc_quant_table((j_common_ptr)dinfo);
1492 }
DRC34dca052014-02-28 09:17:14 +00001493
1494 return 0;
1495}
1496
1497
1498int my_read_markers(j_decompress_ptr dinfo)
1499{
1500 return JPEG_REACHED_SOS;
1501}
1502
1503void my_reset_marker_reader(j_decompress_ptr dinfo)
1504{
1505}
1506
DRCaecea382014-08-11 18:05:41 +00001507DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
DRC6fa14b32015-08-13 20:06:03 -05001508 const unsigned char **srcPlanes, const int *strides, int subsamp,
1509 unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat,
1510 int flags)
DRC34dca052014-02-28 09:17:14 +00001511{
1512 int i, retval=0; JSAMPROW *row_pointer=NULL;
1513 JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1514 JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +00001515 int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001516 JSAMPLE *ptr;
DRC34dca052014-02-28 09:17:14 +00001517 jpeg_component_info *compptr;
1518 #ifndef JCS_EXTENSIONS
1519 unsigned char *rgbBuf=NULL;
DRC230d09d2014-04-20 09:42:49 +00001520 unsigned char *_dstBuf=NULL; int _pitch=0;
DRC34dca052014-02-28 09:17:14 +00001521 #endif
DRCbc56b752014-05-16 10:43:44 +00001522 int (*old_read_markers)(j_decompress_ptr);
1523 void (*old_reset_marker_reader)(j_decompress_ptr);
DRC34dca052014-02-28 09:17:14 +00001524
DRC41861622014-04-16 23:38:37 +00001525 getdinstance(handle);
DRC34dca052014-02-28 09:17:14 +00001526
1527 for(i=0; i<MAX_COMPONENTS; i++)
1528 {
1529 tmpbuf[i]=NULL; _tmpbuf[i]=NULL; inbuf[i]=NULL;
1530 }
1531
1532 if((this->init&DECOMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001533 _throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
DRC34dca052014-02-28 09:17:14 +00001534
DRCaecea382014-08-11 18:05:41 +00001535 if(!srcPlanes || !srcPlanes[0] || subsamp<0 || subsamp>=NUMSUBOPT
DRC34dca052014-02-28 09:17:14 +00001536 || dstBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
1537 || pixelFormat>=TJ_NUMPF)
DRCaecea382014-08-11 18:05:41 +00001538 _throw("tjDecodeYUVPlanes(): Invalid argument");
1539 if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1540 _throw("tjDecodeYUVPlanes(): Invalid argument");
DRC34dca052014-02-28 09:17:14 +00001541
1542 if(setjmp(this->jerr.setjmp_buffer))
1543 {
1544 /* If we get here, the JPEG code has signaled an error. */
1545 retval=-1;
1546 goto bailout;
1547 }
1548
1549 if(pixelFormat==TJPF_CMYK)
DRCaecea382014-08-11 18:05:41 +00001550 _throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
DRC34dca052014-02-28 09:17:14 +00001551
1552 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC34dca052014-02-28 09:17:14 +00001553 dinfo->image_width=width;
1554 dinfo->image_height=height;
1555
DRCbec45b12015-05-17 15:56:18 +00001556 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1557 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1558 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC34dca052014-02-28 09:17:14 +00001559
DRC34dca052014-02-28 09:17:14 +00001560 if(setDecodeDefaults(dinfo, pixelFormat, subsamp, flags)==-1)
1561 {
1562 retval=-1; goto bailout;
1563 }
1564 old_read_markers=dinfo->marker->read_markers;
1565 dinfo->marker->read_markers=my_read_markers;
1566 old_reset_marker_reader=dinfo->marker->reset_marker_reader;
1567 dinfo->marker->reset_marker_reader=my_reset_marker_reader;
1568 jpeg_read_header(dinfo, TRUE);
1569 dinfo->marker->read_markers=old_read_markers;
1570 dinfo->marker->reset_marker_reader=old_reset_marker_reader;
1571
1572 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
1573 {
1574 retval=-1; goto bailout;
1575 }
DRC7d9f7582014-03-10 20:14:53 +00001576 dinfo->do_fancy_upsampling=FALSE;
DRCdb6d8fc2015-06-08 18:31:34 +00001577 dinfo->Se=DCTSIZE2-1;
DRC2bdc0422014-03-07 03:52:57 +00001578 jinit_master_decompress(dinfo);
DRC34dca052014-02-28 09:17:14 +00001579 (*dinfo->upsample->start_pass)(dinfo);
1580
DRC40dd3142014-08-17 12:23:49 +00001581 pw0=PAD(width, dinfo->max_h_samp_factor);
1582 ph0=PAD(height, dinfo->max_v_samp_factor);
DRC34dca052014-02-28 09:17:14 +00001583
1584 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
1585
DRC230d09d2014-04-20 09:42:49 +00001586 #ifndef JCS_EXTENSIONS
1587 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
1588 (RGB_RED!=tjRedOffset[pixelFormat] ||
1589 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1590 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1591 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1592 {
1593 rgbBuf=(unsigned char *)malloc(width*height*3);
DRCaecea382014-08-11 18:05:41 +00001594 if(!rgbBuf) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC230d09d2014-04-20 09:42:49 +00001595 _pitch=pitch; pitch=width*3;
1596 _dstBuf=dstBuf; dstBuf=rgbBuf;
1597 }
1598 #endif
1599
DRC40dd3142014-08-17 12:23:49 +00001600 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
DRCaecea382014-08-11 18:05:41 +00001601 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001602 for(i=0; i<height; i++)
1603 {
1604 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*pitch];
1605 else row_pointer[i]=&dstBuf[i*pitch];
1606 }
DRC40dd3142014-08-17 12:23:49 +00001607 if(height<ph0)
1608 for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
DRC34dca052014-02-28 09:17:14 +00001609
1610 for(i=0; i<dinfo->num_components; i++)
1611 {
1612 compptr=&dinfo->comp_info[i];
1613 _tmpbuf[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
1614 * compptr->v_samp_factor + 16);
DRCaecea382014-08-11 18:05:41 +00001615 if(!_tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001616 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCaecea382014-08-11 18:05:41 +00001617 if(!tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001618 for(row=0; row<compptr->v_samp_factor; row++)
1619 {
1620 unsigned char *_tmpbuf_aligned=
1621 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
1622 tmpbuf[i][row]=&_tmpbuf_aligned[
1623 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
1624 }
DRC40dd3142014-08-17 12:23:49 +00001625 pw[i]=pw0*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1626 ph[i]=ph0*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1627 inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
DRCaecea382014-08-11 18:05:41 +00001628 if(!inbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC6fa14b32015-08-13 20:06:03 -05001629 ptr=(JSAMPLE *)srcPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001630 for(row=0; row<ph[i]; row++)
DRC34dca052014-02-28 09:17:14 +00001631 {
1632 inbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001633 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC34dca052014-02-28 09:17:14 +00001634 }
1635 }
1636
DRC40dd3142014-08-17 12:23:49 +00001637 for(row=0; row<ph0; row+=dinfo->max_v_samp_factor)
DRC34dca052014-02-28 09:17:14 +00001638 {
1639 JDIMENSION inrow=0, outrow=0;
1640 for(i=0, compptr=dinfo->comp_info; i<dinfo->num_components; i++, compptr++)
1641 jcopy_sample_rows(inbuf[i],
1642 row*compptr->v_samp_factor/dinfo->max_v_samp_factor, tmpbuf[i], 0,
DRC40dd3142014-08-17 12:23:49 +00001643 compptr->v_samp_factor, pw[i]);
DRC34dca052014-02-28 09:17:14 +00001644 (dinfo->upsample->upsample)(dinfo, tmpbuf, &inrow,
1645 dinfo->max_v_samp_factor, &row_pointer[row], &outrow,
1646 dinfo->max_v_samp_factor);
1647 }
1648 jpeg_abort_decompress(dinfo);
1649
DRC230d09d2014-04-20 09:42:49 +00001650 #ifndef JCS_EXTENSIONS
1651 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1652 #endif
1653
DRC34dca052014-02-28 09:17:14 +00001654 bailout:
1655 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1656 #ifndef JCS_EXTENSIONS
1657 if(rgbBuf) free(rgbBuf);
1658 #endif
1659 if(row_pointer) free(row_pointer);
1660 for(i=0; i<MAX_COMPONENTS; i++)
1661 {
1662 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
1663 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
1664 if(inbuf[i]!=NULL) free(inbuf[i]);
1665 }
DRC1f79c7c2015-06-01 19:22:41 +00001666 if(this->jerr.warning) retval=-1;
DRC34dca052014-02-28 09:17:14 +00001667 return retval;
1668}
1669
DRC6fa14b32015-08-13 20:06:03 -05001670DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
DRCaecea382014-08-11 18:05:41 +00001671 int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
1672 int height, int pixelFormat, int flags)
1673{
DRC6fa14b32015-08-13 20:06:03 -05001674 const unsigned char *srcPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001675 int pw0, ph0, strides[3], retval=-1;
DRC34dca052014-02-28 09:17:14 +00001676
DRCaecea382014-08-11 18:05:41 +00001677 if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT
1678 || width<=0 || height<=0)
1679 _throw("tjDecodeYUV(): Invalid argument");
1680
DRC40dd3142014-08-17 12:23:49 +00001681 pw0=tjPlaneWidth(0, width, subsamp);
1682 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +00001683 srcPlanes[0]=srcBuf;
DRC40dd3142014-08-17 12:23:49 +00001684 strides[0]=PAD(pw0, pad);
1685 if(subsamp==TJSAMP_GRAY)
1686 {
1687 strides[1]=strides[2]=0;
1688 srcPlanes[1]=srcPlanes[2]=NULL;
1689 }
1690 else
1691 {
1692 int pw1=tjPlaneWidth(1, width, subsamp);
1693 int ph1=tjPlaneHeight(1, height, subsamp);
1694 strides[1]=strides[2]=PAD(pw1, pad);
1695 srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1696 srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1697 }
DRCaecea382014-08-11 18:05:41 +00001698
1699 return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1700 pitch, height, pixelFormat, flags);
1701
1702 bailout:
1703 return retval;
1704}
1705
1706DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle,
DRC6fa14b32015-08-13 20:06:03 -05001707 const unsigned char *jpegBuf, unsigned long jpegSize,
1708 unsigned char **dstPlanes, int width, int *strides, int height, int flags)
DRC9b28def2011-05-21 14:37:15 +00001709{
DRCf610d612013-04-26 10:33:29 +00001710 int i, sfi, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001711 int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
DRC40dd3142014-08-17 12:23:49 +00001712 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
DRC9b28def2011-05-21 14:37:15 +00001713 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001714 JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001715 int dctsize;
DRC9b28def2011-05-21 14:37:15 +00001716
DRC41861622014-04-16 23:38:37 +00001717 getdinstance(handle);
DRCb51ee892013-10-31 05:00:19 +00001718
DRCf9cf5c72010-12-10 10:58:49 +00001719 for(i=0; i<MAX_COMPONENTS; i++)
1720 {
1721 tmpbuf[i]=NULL; outbuf[i]=NULL;
1722 }
DRC9e17f7d2010-12-10 04:59:13 +00001723
DRCe2f8e692013-10-30 22:21:06 +00001724 if((this->init&DECOMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001725 _throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
DRCe2f8e692013-10-30 22:21:06 +00001726
DRCaecea382014-08-11 18:05:41 +00001727 if(jpegBuf==NULL || jpegSize<=0 || !dstPlanes || !dstPlanes[0] || width<0
1728 || height<0)
1729 _throw("tjDecompressToYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001730
DRCbec45b12015-05-17 15:56:18 +00001731 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1732 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1733 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +00001734
DRC9b28def2011-05-21 14:37:15 +00001735 if(setjmp(this->jerr.setjmp_buffer))
1736 {
1737 /* If we get here, the JPEG code has signaled an error. */
DRC91e86ba2011-02-15 05:24:08 +00001738 retval=-1;
1739 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +00001740 }
DRC2e7b76b2009-04-03 12:04:24 +00001741
DRCaecea382014-08-11 18:05:41 +00001742 if(!this->headerRead)
1743 {
1744 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1745 jpeg_read_header(dinfo, TRUE);
1746 }
1747 this->headerRead=0;
DRC418fe282013-05-07 21:17:35 +00001748 jpegSubsamp=getSubsamp(dinfo);
1749 if(jpegSubsamp<0)
DRCaecea382014-08-11 18:05:41 +00001750 _throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1751
1752 if(jpegSubsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1753 _throw("tjDecompressToYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001754
DRCf610d612013-04-26 10:33:29 +00001755 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1756 if(width==0) width=jpegwidth;
1757 if(height==0) height=jpegheight;
1758 for(i=0; i<NUMSF; i++)
1759 {
1760 scaledw=TJSCALED(jpegwidth, sf[i]);
1761 scaledh=TJSCALED(jpegheight, sf[i]);
1762 if(scaledw<=width && scaledh<=height)
1763 break;
1764 }
DRC58ae4012015-08-26 20:29:36 -05001765 if(i>=NUMSF)
DRCaecea382014-08-11 18:05:41 +00001766 _throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
DRCcd7c3e62013-08-23 02:49:25 +00001767 if(dinfo->num_components>3)
DRCaecea382014-08-11 18:05:41 +00001768 _throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
DRCcd7c3e62013-08-23 02:49:25 +00001769
DRCf610d612013-04-26 10:33:29 +00001770 width=scaledw; height=scaledh;
1771 dinfo->scale_num=sf[i].num;
1772 dinfo->scale_denom=sf[i].denom;
1773 sfi=i;
1774 jpeg_calc_output_dimensions(dinfo);
1775
DRC418fe282013-05-07 21:17:35 +00001776 dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
1777
DRC9b28def2011-05-21 14:37:15 +00001778 for(i=0; i<dinfo->num_components; i++)
DRC2e7b76b2009-04-03 12:04:24 +00001779 {
DRC9b28def2011-05-21 14:37:15 +00001780 jpeg_component_info *compptr=&dinfo->comp_info[i];
1781 int ih;
DRC418fe282013-05-07 21:17:35 +00001782 iw[i]=compptr->width_in_blocks*dctsize;
1783 ih=compptr->height_in_blocks*dctsize;
DRC40dd3142014-08-17 12:23:49 +00001784 pw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001785 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001786 ph[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001787 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001788 if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
DRC418fe282013-05-07 21:17:35 +00001789 th[i]=compptr->v_samp_factor*dctsize;
DRC9b28def2011-05-21 14:37:15 +00001790 tmpbufsize+=iw[i]*th[i];
DRC40dd3142014-08-17 12:23:49 +00001791 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001792 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1793 ptr=dstPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001794 for(row=0; row<ph[i]; row++)
DRC9b28def2011-05-21 14:37:15 +00001795 {
1796 outbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001797 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC9b28def2011-05-21 14:37:15 +00001798 }
1799 }
1800 if(usetmpbuf)
1801 {
1802 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRCaecea382014-08-11 18:05:41 +00001803 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001804 ptr=_tmpbuf;
1805 for(i=0; i<dinfo->num_components; i++)
1806 {
1807 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001808 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001809 for(row=0; row<th[i]; row++)
1810 {
1811 tmpbuf[i][row]=ptr;
1812 ptr+=iw[i];
1813 }
1814 }
1815 }
DRC9e17f7d2010-12-10 04:59:13 +00001816
DRC25b995a2011-05-21 15:34:54 +00001817 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRCe0419b52012-07-03 20:01:31 +00001818 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
DRC9b28def2011-05-21 14:37:15 +00001819 dinfo->raw_data_out=TRUE;
1820
1821 jpeg_start_decompress(dinfo);
1822 for(row=0; row<(int)dinfo->output_height;
DRC418fe282013-05-07 21:17:35 +00001823 row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
DRC9b28def2011-05-21 14:37:15 +00001824 {
1825 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1826 int crow[MAX_COMPONENTS];
DRC9e17f7d2010-12-10 04:59:13 +00001827 for(i=0; i<dinfo->num_components; i++)
1828 {
1829 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRC418fe282013-05-07 21:17:35 +00001830 if(jpegSubsamp==TJ_420)
1831 {
1832 /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1833 to be clever and use the IDCT to perform upsampling on the U and V
1834 planes. For instance, if the output image is to be scaled by 1/2
1835 relative to the JPEG image, then the scaling factor and upsampling
1836 effectively cancel each other, so a normal 8x8 IDCT can be used.
1837 However, this is not desirable when using the decompress-to-YUV
1838 functionality in TurboJPEG, since we want to output the U and V
1839 planes in their subsampled form. Thus, we have to override some
1840 internal libjpeg parameters to force it to use the "scaled" IDCT
1841 functions on the U and V planes. */
1842 compptr->_DCT_scaled_size=dctsize;
1843 compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
1844 sf[sfi].num/sf[sfi].denom*
1845 compptr->v_samp_factor/dinfo->max_v_samp_factor;
1846 dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1847 }
DRC9b28def2011-05-21 14:37:15 +00001848 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1849 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1850 else yuvptr[i]=&outbuf[i][crow[i]];
DRCf9cf5c72010-12-10 10:58:49 +00001851 }
DRCf610d612013-04-26 10:33:29 +00001852 jpeg_read_raw_data(dinfo, yuvptr,
DRC418fe282013-05-07 21:17:35 +00001853 dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
DRCf9cf5c72010-12-10 10:58:49 +00001854 if(usetmpbuf)
1855 {
DRC9b28def2011-05-21 14:37:15 +00001856 int j;
DRCf9cf5c72010-12-10 10:58:49 +00001857 for(i=0; i<dinfo->num_components; i++)
1858 {
DRC40dd3142014-08-17 12:23:49 +00001859 for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +00001860 {
DRC40dd3142014-08-17 12:23:49 +00001861 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], pw[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001862 }
DRC9e17f7d2010-12-10 04:59:13 +00001863 }
1864 }
1865 }
DRC9b28def2011-05-21 14:37:15 +00001866 jpeg_finish_decompress(dinfo);
DRC2e7b76b2009-04-03 12:04:24 +00001867
DRC91e86ba2011-02-15 05:24:08 +00001868 bailout:
DRC9b28def2011-05-21 14:37:15 +00001869 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC9e17f7d2010-12-10 04:59:13 +00001870 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +00001871 {
1872 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +00001873 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001874 }
1875 if(_tmpbuf) free(_tmpbuf);
DRC1f79c7c2015-06-01 19:22:41 +00001876 if(this->jerr.warning) retval=-1;
DRC91e86ba2011-02-15 05:24:08 +00001877 return retval;
DRC2e7b76b2009-04-03 12:04:24 +00001878}
1879
DRCaecea382014-08-11 18:05:41 +00001880DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
DRC6fa14b32015-08-13 20:06:03 -05001881 const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
DRCaecea382014-08-11 18:05:41 +00001882 int width, int pad, int height, int flags)
1883{
1884 unsigned char *dstPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001885 int pw0, ph0, strides[3], retval=-1, jpegSubsamp=-1;
DRCaecea382014-08-11 18:05:41 +00001886 int i, jpegwidth, jpegheight, scaledw, scaledh;
1887
1888 getdinstance(handle);
1889
1890 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
1891 || !isPow2(pad) || height<0)
1892 _throw("tjDecompressToYUV2(): Invalid argument");
1893
1894 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1895 jpeg_read_header(dinfo, TRUE);
1896 jpegSubsamp=getSubsamp(dinfo);
1897 if(jpegSubsamp<0)
1898 _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1899
1900 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1901 if(width==0) width=jpegwidth;
1902 if(height==0) height=jpegheight;
1903
1904 for(i=0; i<NUMSF; i++)
1905 {
1906 scaledw=TJSCALED(jpegwidth, sf[i]);
1907 scaledh=TJSCALED(jpegheight, sf[i]);
1908 if(scaledw<=width && scaledh<=height)
1909 break;
1910 }
DRC58ae4012015-08-26 20:29:36 -05001911 if(i>=NUMSF)
DRCaecea382014-08-11 18:05:41 +00001912 _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1913
DRC40dd3142014-08-17 12:23:49 +00001914 pw0=tjPlaneWidth(0, width, jpegSubsamp);
1915 ph0=tjPlaneHeight(0, height, jpegSubsamp);
DRCaecea382014-08-11 18:05:41 +00001916 dstPlanes[0]=dstBuf;
DRC40dd3142014-08-17 12:23:49 +00001917 strides[0]=PAD(pw0, pad);
1918 if(jpegSubsamp==TJSAMP_GRAY)
1919 {
1920 strides[1]=strides[2]=0;
1921 dstPlanes[1]=dstPlanes[2]=NULL;
1922 }
1923 else
1924 {
1925 int pw1=tjPlaneWidth(1, width, jpegSubsamp);
1926 int ph1=tjPlaneHeight(1, height, jpegSubsamp);
1927 strides[1]=strides[2]=PAD(pw1, pad);
1928 dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1929 dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1930 }
DRCaecea382014-08-11 18:05:41 +00001931
1932 this->headerRead=1;
1933 return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1934 strides, height, flags);
1935
1936 bailout:
1937 return retval;
1938
1939}
1940
DRCf610d612013-04-26 10:33:29 +00001941DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1942 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1943 int flags)
1944{
1945 return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1946}
1947
DRC2e7b76b2009-04-03 12:04:24 +00001948
DRC9b28def2011-05-21 14:37:15 +00001949/* Transformer */
DRC890f1e02011-02-26 22:02:37 +00001950
1951DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1952{
DRC9b28def2011-05-21 14:37:15 +00001953 tjinstance *this=NULL; tjhandle handle=NULL;
1954 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00001955 {
DRC007a42c2011-05-22 13:55:56 +00001956 snprintf(errStr, JMSG_LENGTH_MAX,
1957 "tjInitTransform(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00001958 return NULL;
1959 }
DRC007a42c2011-05-22 13:55:56 +00001960 MEMZERO(this, sizeof(tjinstance));
DRC9b28def2011-05-21 14:37:15 +00001961 handle=_tjInitCompress(this);
1962 if(!handle) return NULL;
1963 handle=_tjInitDecompress(this);
1964 return handle;
DRC890f1e02011-02-26 22:02:37 +00001965}
1966
1967
DRC6fa14b32015-08-13 20:06:03 -05001968DLLEXPORT int DLLCALL tjTransform(tjhandle handle,
1969 const unsigned char *jpegBuf, unsigned long jpegSize, int n,
1970 unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *t, int flags)
DRC890f1e02011-02-26 22:02:37 +00001971{
DRC0a325192011-03-02 09:22:41 +00001972 jpeg_transform_info *xinfo=NULL;
DRC890f1e02011-02-26 22:02:37 +00001973 jvirt_barray_ptr *srccoefs, *dstcoefs;
DRC9b49f0e2011-07-12 03:17:23 +00001974 int retval=0, i, jpegSubsamp;
DRC890f1e02011-02-26 22:02:37 +00001975
DRC9b28def2011-05-21 14:37:15 +00001976 getinstance(handle);
1977 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001978 _throw("tjTransform(): Instance has not been initialized for transformation");
DRC890f1e02011-02-26 22:02:37 +00001979
DRC9b28def2011-05-21 14:37:15 +00001980 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1981 || t==NULL || flags<0)
1982 _throw("tjTransform(): Invalid argument");
1983
DRCbec45b12015-05-17 15:56:18 +00001984 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1985 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1986 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC890f1e02011-02-26 22:02:37 +00001987
DRC9b28def2011-05-21 14:37:15 +00001988 if(setjmp(this->jerr.setjmp_buffer))
1989 {
1990 /* If we get here, the JPEG code has signaled an error. */
DRC890f1e02011-02-26 22:02:37 +00001991 retval=-1;
1992 goto bailout;
1993 }
1994
DRC9b28def2011-05-21 14:37:15 +00001995 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
DRC890f1e02011-02-26 22:02:37 +00001996
DRC0a325192011-03-02 09:22:41 +00001997 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1998 ==NULL)
DRC007a42c2011-05-22 13:55:56 +00001999 _throw("tjTransform(): Memory allocation failure");
2000 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
DRC890f1e02011-02-26 22:02:37 +00002001
DRC0a325192011-03-02 09:22:41 +00002002 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00002003 {
DRC0a325192011-03-02 09:22:41 +00002004 xinfo[i].transform=xformtypes[t[i].op];
DRC25b995a2011-05-21 15:34:54 +00002005 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
2006 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
2007 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
2008 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
2009 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
DRCba5ea512011-03-04 03:20:34 +00002010 else xinfo[i].slow_hflip=0;
DRC0a325192011-03-02 09:22:41 +00002011
2012 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00002013 {
DRC0a325192011-03-02 09:22:41 +00002014 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
2015 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
2016 if(t[i].r.w!=0)
2017 {
2018 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
2019 }
DRCd932e582011-03-15 20:09:47 +00002020 else xinfo[i].crop_width=JCROP_UNSET;
DRC0a325192011-03-02 09:22:41 +00002021 if(t[i].r.h!=0)
2022 {
2023 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
2024 }
DRCd932e582011-03-15 20:09:47 +00002025 else xinfo[i].crop_height=JCROP_UNSET;
DRC890f1e02011-02-26 22:02:37 +00002026 }
2027 }
2028
DRC9b28def2011-05-21 14:37:15 +00002029 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
2030 jpeg_read_header(dinfo, TRUE);
DRC9b49f0e2011-07-12 03:17:23 +00002031 jpegSubsamp=getSubsamp(dinfo);
2032 if(jpegSubsamp<0)
2033 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC890f1e02011-02-26 22:02:37 +00002034
DRC0a325192011-03-02 09:22:41 +00002035 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00002036 {
DRC9b28def2011-05-21 14:37:15 +00002037 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
DRC007a42c2011-05-22 13:55:56 +00002038 _throw("tjTransform(): Transform is not perfect");
DRC890f1e02011-02-26 22:02:37 +00002039
DRC0a325192011-03-02 09:22:41 +00002040 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00002041 {
DRC0a325192011-03-02 09:22:41 +00002042 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
2043 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
2044 {
DRC9b28def2011-05-21 14:37:15 +00002045 snprintf(errStr, JMSG_LENGTH_MAX,
DRC0a325192011-03-02 09:22:41 +00002046 "To crop this JPEG image, x must be a multiple of %d\n"
2047 "and y must be a multiple of %d.\n",
2048 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
2049 retval=-1; goto bailout;
2050 }
DRC890f1e02011-02-26 22:02:37 +00002051 }
2052 }
2053
DRC9b28def2011-05-21 14:37:15 +00002054 srccoefs=jpeg_read_coefficients(dinfo);
DRC890f1e02011-02-26 22:02:37 +00002055
DRC0a325192011-03-02 09:22:41 +00002056 for(i=0; i<n; i++)
2057 {
DRCff78e372011-05-24 10:17:32 +00002058 int w, h, alloc=1;
DRC0a325192011-03-02 09:22:41 +00002059 if(!xinfo[i].crop)
2060 {
DRC9b28def2011-05-21 14:37:15 +00002061 w=dinfo->image_width; h=dinfo->image_height;
DRC0a325192011-03-02 09:22:41 +00002062 }
2063 else
2064 {
2065 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
2066 }
DRCff78e372011-05-24 10:17:32 +00002067 if(flags&TJFLAG_NOREALLOC)
2068 {
DRC9b49f0e2011-07-12 03:17:23 +00002069 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +00002070 }
DRC7bf04d32011-09-17 00:18:31 +00002071 if(!(t[i].options&TJXOPT_NOOUTPUT))
2072 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
DRC9b28def2011-05-21 14:37:15 +00002073 jpeg_copy_critical_parameters(dinfo, cinfo);
2074 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00002075 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00002076 if(!(t[i].options&TJXOPT_NOOUTPUT))
2077 {
2078 jpeg_write_coefficients(cinfo, dstcoefs);
2079 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
2080 }
2081 else jinit_c_master_control(cinfo, TRUE);
DRC9b28def2011-05-21 14:37:15 +00002082 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00002083 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00002084 if(t[i].customFilter)
2085 {
DRCefe28ce2012-01-17 11:48:38 +00002086 int ci, y; JDIMENSION by;
DRC7bf04d32011-09-17 00:18:31 +00002087 for(ci=0; ci<cinfo->num_components; ci++)
2088 {
2089 jpeg_component_info *compptr=&cinfo->comp_info[ci];
2090 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2091 DCTSIZE};
2092 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2093 compptr->height_in_blocks*DCTSIZE};
2094 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
2095 {
2096 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
2097 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
2098 TRUE);
2099 for(y=0; y<compptr->v_samp_factor; y++)
2100 {
2101 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
DRCf5467112011-09-20 05:02:19 +00002102 ci, i, &t[i])==-1)
DRC7bf04d32011-09-17 00:18:31 +00002103 _throw("tjTransform(): Error in custom filter");
2104 arrayRegion.y+=DCTSIZE;
2105 }
2106 }
2107 }
2108 }
2109 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
DRC0a325192011-03-02 09:22:41 +00002110 }
2111
DRC9b28def2011-05-21 14:37:15 +00002112 jpeg_finish_decompress(dinfo);
DRC890f1e02011-02-26 22:02:37 +00002113
DRC890f1e02011-02-26 22:02:37 +00002114 bailout:
DRC9b28def2011-05-21 14:37:15 +00002115 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
2116 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC0a325192011-03-02 09:22:41 +00002117 if(xinfo) free(xinfo);
DRC1f79c7c2015-06-01 19:22:41 +00002118 if(this->jerr.warning) retval=-1;
DRC890f1e02011-02-26 22:02:37 +00002119 return retval;
2120}