blob: 8b771006f91d47c7668a2ecd30eeb3ff5c4da784 [file] [log] [blame]
DRC9b28def2011-05-21 14:37:15 +00001/*
DRCd4c41fe2017-03-18 12:56:36 -05002 * Copyright (C)2009-2017 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;
DRCb9ab64d2017-05-11 21:02:29 -050099 char errStr[JMSG_LENGTH_MAX];
100 boolean isInstanceError;
DRC9b28def2011-05-21 14:37:15 +0000101} tjinstance;
DRC2e7b76b2009-04-03 12:04:24 +0000102
DRC1f3635c2013-08-18 10:19:00 +0000103static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};
DRC9b28def2011-05-21 14:37:15 +0000104
DRC007a42c2011-05-22 13:55:56 +0000105static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
106{
DRC890f1e02011-02-26 22:02:37 +0000107 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
108 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
109};
DRC9b28def2011-05-21 14:37:15 +0000110
DRCab2df6e2012-01-28 06:49:56 +0000111#define NUMSF 16
DRC109a5782011-03-01 09:53:07 +0000112static const tjscalingfactor sf[NUMSF]={
DRCab2df6e2012-01-28 06:49:56 +0000113 {2, 1},
114 {15, 8},
115 {7, 4},
116 {13, 8},
117 {3, 2},
118 {11, 8},
119 {5, 4},
120 {9, 8},
DRC109a5782011-03-01 09:53:07 +0000121 {1, 1},
DRCab2df6e2012-01-28 06:49:56 +0000122 {7, 8},
123 {3, 4},
124 {5, 8},
DRC109a5782011-03-01 09:53:07 +0000125 {1, 2},
DRCab2df6e2012-01-28 06:49:56 +0000126 {3, 8},
DRC109a5782011-03-01 09:53:07 +0000127 {1, 4},
128 {1, 8}
129};
DRC2e7b76b2009-04-03 12:04:24 +0000130
DRCb9ab64d2017-05-11 21:02:29 -0500131#define _throwg(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
DRCda5220a2011-03-02 02:17:30 +0000132 retval=-1; goto bailout;}
DRCb9ab64d2017-05-11 21:02:29 -0500133#define _throw(m) {snprintf(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
134 this->isInstanceError=TRUE; _throwg(m);}
DRC9b28def2011-05-21 14:37:15 +0000135#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
136 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
137 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
138 return -1;} \
DRC1f79c7c2015-06-01 19:22:41 +0000139 cinfo=&this->cinfo; dinfo=&this->dinfo; \
DRCb9ab64d2017-05-11 21:02:29 -0500140 this->jerr.warning=FALSE; \
141 this->isInstanceError=FALSE;
DRC41861622014-04-16 23:38:37 +0000142#define getcinstance(handle) tjinstance *this=(tjinstance *)handle; \
143 j_compress_ptr cinfo=NULL; \
144 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
145 return -1;} \
DRC1f79c7c2015-06-01 19:22:41 +0000146 cinfo=&this->cinfo; \
DRCb9ab64d2017-05-11 21:02:29 -0500147 this->jerr.warning=FALSE; \
148 this->isInstanceError=FALSE;
DRC41861622014-04-16 23:38:37 +0000149#define getdinstance(handle) tjinstance *this=(tjinstance *)handle; \
150 j_decompress_ptr dinfo=NULL; \
151 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
152 return -1;} \
DRC1f79c7c2015-06-01 19:22:41 +0000153 dinfo=&this->dinfo; \
DRCb9ab64d2017-05-11 21:02:29 -0500154 this->jerr.warning=FALSE; \
155 this->isInstanceError=FALSE;
DRC2e7b76b2009-04-03 12:04:24 +0000156
DRC9b28def2011-05-21 14:37:15 +0000157static int getPixelFormat(int pixelSize, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000158{
DRC25b995a2011-05-21 15:34:54 +0000159 if(pixelSize==1) return TJPF_GRAY;
DRC9b28def2011-05-21 14:37:15 +0000160 if(pixelSize==3)
161 {
DRC25b995a2011-05-21 15:34:54 +0000162 if(flags&TJ_BGR) return TJPF_BGR;
163 else return TJPF_RGB;
DRC9b28def2011-05-21 14:37:15 +0000164 }
165 if(pixelSize==4)
166 {
167 if(flags&TJ_ALPHAFIRST)
168 {
DRC25b995a2011-05-21 15:34:54 +0000169 if(flags&TJ_BGR) return TJPF_XBGR;
170 else return TJPF_XRGB;
DRC9b28def2011-05-21 14:37:15 +0000171 }
172 else
173 {
DRC25b995a2011-05-21 15:34:54 +0000174 if(flags&TJ_BGR) return TJPF_BGRX;
175 else return TJPF_RGBX;
DRC9b28def2011-05-21 14:37:15 +0000176 }
177 }
178 return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000179}
180
DRCf12bb302011-09-07 05:03:18 +0000181static int setCompDefaults(struct jpeg_compress_struct *cinfo,
DRC73d74c12012-06-29 23:46:38 +0000182 int pixelFormat, int subsamp, int jpegQual, int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000183{
DRCf12bb302011-09-07 05:03:18 +0000184 int retval=0;
DRC0713c1b2014-08-22 13:43:33 +0000185 char *env=NULL;
DRCf12bb302011-09-07 05:03:18 +0000186
DRC9b28def2011-05-21 14:37:15 +0000187 switch(pixelFormat)
188 {
DRC25b995a2011-05-21 15:34:54 +0000189 case TJPF_GRAY:
DRC9b28def2011-05-21 14:37:15 +0000190 cinfo->in_color_space=JCS_GRAYSCALE; break;
191 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000192 case TJPF_RGB:
DRC9b28def2011-05-21 14:37:15 +0000193 cinfo->in_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000194 case TJPF_BGR:
DRC9b28def2011-05-21 14:37:15 +0000195 cinfo->in_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000196 case TJPF_RGBX:
DRC67ce3b22011-12-19 02:21:03 +0000197 case TJPF_RGBA:
DRC9b28def2011-05-21 14:37:15 +0000198 cinfo->in_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000199 case TJPF_BGRX:
DRC67ce3b22011-12-19 02:21:03 +0000200 case TJPF_BGRA:
DRC9b28def2011-05-21 14:37:15 +0000201 cinfo->in_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000202 case TJPF_XRGB:
DRC67ce3b22011-12-19 02:21:03 +0000203 case TJPF_ARGB:
DRC9b28def2011-05-21 14:37:15 +0000204 cinfo->in_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000205 case TJPF_XBGR:
DRC67ce3b22011-12-19 02:21:03 +0000206 case TJPF_ABGR:
DRC9b28def2011-05-21 14:37:15 +0000207 cinfo->in_color_space=JCS_EXT_XBGR; break;
208 #else
DRC25b995a2011-05-21 15:34:54 +0000209 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000210 case TJPF_BGR:
211 case TJPF_RGBX:
212 case TJPF_BGRX:
213 case TJPF_XRGB:
214 case TJPF_XBGR:
215 case TJPF_RGBA:
216 case TJPF_BGRA:
217 case TJPF_ARGB:
218 case TJPF_ABGR:
219 cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
220 break;
DRC9b28def2011-05-21 14:37:15 +0000221 #endif
DRCcd7c3e62013-08-23 02:49:25 +0000222 case TJPF_CMYK:
223 cinfo->in_color_space=JCS_CMYK; break;
DRCefa4ddc2010-10-13 19:22:50 +0000224 }
DRC2e7b76b2009-04-03 12:04:24 +0000225
DRC9b28def2011-05-21 14:37:15 +0000226 cinfo->input_components=tjPixelSize[pixelFormat];
227 jpeg_set_defaults(cinfo);
DRC0713c1b2014-08-22 13:43:33 +0000228
DRCfeccdcf2015-02-23 19:19:40 +0000229#ifndef NO_GETENV
DRC0713c1b2014-08-22 13:43:33 +0000230 if((env=getenv("TJ_OPTIMIZE"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
231 cinfo->optimize_coding=TRUE;
232 if((env=getenv("TJ_ARITHMETIC"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
233 cinfo->arith_code=TRUE;
234 if((env=getenv("TJ_RESTART"))!=NULL && strlen(env)>0)
235 {
236 int temp=-1; char tempc=0;
237 if(sscanf(env, "%d%c", &temp, &tempc)>=1 && temp>=0 && temp<=65535)
238 {
239 if(toupper(tempc)=='B')
240 {
241 cinfo->restart_interval=temp;
242 cinfo->restart_in_rows=0;
243 }
244 else
245 cinfo->restart_in_rows=temp;
246 }
247 }
DRCfeccdcf2015-02-23 19:19:40 +0000248#endif
DRC0713c1b2014-08-22 13:43:33 +0000249
DRC9b28def2011-05-21 14:37:15 +0000250 if(jpegQual>=0)
251 {
252 jpeg_set_quality(cinfo, jpegQual, TRUE);
DRC73d74c12012-06-29 23:46:38 +0000253 if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
DRC9b28def2011-05-21 14:37:15 +0000254 else cinfo->dct_method=JDCT_FASTEST;
255 }
DRC25b995a2011-05-21 15:34:54 +0000256 if(subsamp==TJSAMP_GRAY)
DRC9b28def2011-05-21 14:37:15 +0000257 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
DRCcd7c3e62013-08-23 02:49:25 +0000258 else if(pixelFormat==TJPF_CMYK)
259 jpeg_set_colorspace(cinfo, JCS_YCCK);
260 else jpeg_set_colorspace(cinfo, JCS_YCbCr);
DRC2e7b76b2009-04-03 12:04:24 +0000261
DRCfeccdcf2015-02-23 19:19:40 +0000262#ifndef NO_GETENV
DRC0713c1b2014-08-22 13:43:33 +0000263 if((env=getenv("TJ_PROGRESSIVE"))!=NULL && strlen(env)>0
264 && !strcmp(env, "1"))
265 jpeg_simple_progression(cinfo);
DRCfeccdcf2015-02-23 19:19:40 +0000266#endif
DRC0713c1b2014-08-22 13:43:33 +0000267
DRC9b28def2011-05-21 14:37:15 +0000268 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
269 cinfo->comp_info[1].h_samp_factor=1;
270 cinfo->comp_info[2].h_samp_factor=1;
DRCcd7c3e62013-08-23 02:49:25 +0000271 if(cinfo->num_components>3)
272 cinfo->comp_info[3].h_samp_factor=tjMCUWidth[subsamp]/8;
DRC9b28def2011-05-21 14:37:15 +0000273 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
274 cinfo->comp_info[1].v_samp_factor=1;
275 cinfo->comp_info[2].v_samp_factor=1;
DRCcd7c3e62013-08-23 02:49:25 +0000276 if(cinfo->num_components>3)
277 cinfo->comp_info[3].v_samp_factor=tjMCUHeight[subsamp]/8;
DRCf12bb302011-09-07 05:03:18 +0000278
DRCf12bb302011-09-07 05:03:18 +0000279 return retval;
DRC9b28def2011-05-21 14:37:15 +0000280}
281
DRCb9ab64d2017-05-11 21:02:29 -0500282static int setDecompDefaults(tjinstance *this, int pixelFormat, int flags)
DRC9b28def2011-05-21 14:37:15 +0000283{
DRCf12bb302011-09-07 05:03:18 +0000284 int retval=0;
285
DRC9b28def2011-05-21 14:37:15 +0000286 switch(pixelFormat)
287 {
DRC25b995a2011-05-21 15:34:54 +0000288 case TJPF_GRAY:
DRCb9ab64d2017-05-11 21:02:29 -0500289 this->dinfo.out_color_space=JCS_GRAYSCALE; break;
DRC9b28def2011-05-21 14:37:15 +0000290 #if JCS_EXTENSIONS==1
DRC25b995a2011-05-21 15:34:54 +0000291 case TJPF_RGB:
DRCb9ab64d2017-05-11 21:02:29 -0500292 this->dinfo.out_color_space=JCS_EXT_RGB; break;
DRC25b995a2011-05-21 15:34:54 +0000293 case TJPF_BGR:
DRCb9ab64d2017-05-11 21:02:29 -0500294 this->dinfo.out_color_space=JCS_EXT_BGR; break;
DRC25b995a2011-05-21 15:34:54 +0000295 case TJPF_RGBX:
DRCb9ab64d2017-05-11 21:02:29 -0500296 this->dinfo.out_color_space=JCS_EXT_RGBX; break;
DRC25b995a2011-05-21 15:34:54 +0000297 case TJPF_BGRX:
DRCb9ab64d2017-05-11 21:02:29 -0500298 this->dinfo.out_color_space=JCS_EXT_BGRX; break;
DRC25b995a2011-05-21 15:34:54 +0000299 case TJPF_XRGB:
DRCb9ab64d2017-05-11 21:02:29 -0500300 this->dinfo.out_color_space=JCS_EXT_XRGB; break;
DRC25b995a2011-05-21 15:34:54 +0000301 case TJPF_XBGR:
DRCb9ab64d2017-05-11 21:02:29 -0500302 this->dinfo.out_color_space=JCS_EXT_XBGR; break;
DRC67ce3b22011-12-19 02:21:03 +0000303 #if JCS_ALPHA_EXTENSIONS==1
304 case TJPF_RGBA:
DRCb9ab64d2017-05-11 21:02:29 -0500305 this->dinfo.out_color_space=JCS_EXT_RGBA; break;
DRC67ce3b22011-12-19 02:21:03 +0000306 case TJPF_BGRA:
DRCb9ab64d2017-05-11 21:02:29 -0500307 this->dinfo.out_color_space=JCS_EXT_BGRA; break;
DRC67ce3b22011-12-19 02:21:03 +0000308 case TJPF_ARGB:
DRCb9ab64d2017-05-11 21:02:29 -0500309 this->dinfo.out_color_space=JCS_EXT_ARGB; break;
DRC67ce3b22011-12-19 02:21:03 +0000310 case TJPF_ABGR:
DRCb9ab64d2017-05-11 21:02:29 -0500311 this->dinfo.out_color_space=JCS_EXT_ABGR; break;
DRC67ce3b22011-12-19 02:21:03 +0000312 #endif
DRC9b28def2011-05-21 14:37:15 +0000313 #else
DRC25b995a2011-05-21 15:34:54 +0000314 case TJPF_RGB:
DRCafc06922012-03-23 19:47:57 +0000315 case TJPF_BGR:
316 case TJPF_RGBX:
317 case TJPF_BGRX:
318 case TJPF_XRGB:
319 case TJPF_XBGR:
320 case TJPF_RGBA:
321 case TJPF_BGRA:
322 case TJPF_ARGB:
323 case TJPF_ABGR:
DRCb9ab64d2017-05-11 21:02:29 -0500324 this->dinfo.out_color_space=JCS_RGB; break;
DRC67ce3b22011-12-19 02:21:03 +0000325 #endif
DRCcd7c3e62013-08-23 02:49:25 +0000326 case TJPF_CMYK:
DRCb9ab64d2017-05-11 21:02:29 -0500327 this->dinfo.out_color_space=JCS_CMYK; break;
DRC9b28def2011-05-21 14:37:15 +0000328 default:
329 _throw("Unsupported pixel format");
DRC9b28def2011-05-21 14:37:15 +0000330 }
DRCf12bb302011-09-07 05:03:18 +0000331
DRCb9ab64d2017-05-11 21:02:29 -0500332 if(flags&TJFLAG_FASTDCT) this->dinfo.dct_method=JDCT_FASTEST;
DRC73d74c12012-06-29 23:46:38 +0000333
DRCf12bb302011-09-07 05:03:18 +0000334 bailout:
DRCf12bb302011-09-07 05:03:18 +0000335 return retval;
DRC9b28def2011-05-21 14:37:15 +0000336}
337
338
DRC9b49f0e2011-07-12 03:17:23 +0000339static int getSubsamp(j_decompress_ptr dinfo)
340{
341 int retval=-1, i, k;
DRCea1eea42014-11-19 00:55:28 +0000342
343 /* The sampling factors actually have no meaning with grayscale JPEG files,
344 and in fact it's possible to generate grayscale JPEGs with sampling
345 factors > 1 (even though those sampling factors are ignored by the
346 decompressor.) Thus, we need to treat grayscale as a special case. */
347 if(dinfo->num_components==1 && dinfo->jpeg_color_space==JCS_GRAYSCALE)
348 return TJSAMP_GRAY;
349
DRC9b49f0e2011-07-12 03:17:23 +0000350 for(i=0; i<NUMSUBOPT; i++)
351 {
DRCcd7c3e62013-08-23 02:49:25 +0000352 if(dinfo->num_components==pixelsize[i]
353 || ((dinfo->jpeg_color_space==JCS_YCCK
354 || dinfo->jpeg_color_space==JCS_CMYK)
355 && pixelsize[i]==3 && dinfo->num_components==4))
DRC9b49f0e2011-07-12 03:17:23 +0000356 {
357 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
358 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
359 {
360 int match=0;
361 for(k=1; k<dinfo->num_components; k++)
362 {
DRCcd7c3e62013-08-23 02:49:25 +0000363 int href=1, vref=1;
364 if(dinfo->jpeg_color_space==JCS_YCCK && k==3)
365 {
366 href=tjMCUWidth[i]/8; vref=tjMCUHeight[i]/8;
367 }
368 if(dinfo->comp_info[k].h_samp_factor==href
369 && dinfo->comp_info[k].v_samp_factor==vref)
DRC9b49f0e2011-07-12 03:17:23 +0000370 match++;
371 }
372 if(match==dinfo->num_components-1)
373 {
374 retval=i; break;
375 }
376 }
DRC8ce2c912016-08-01 11:22:24 -0500377 /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
378 in non-standard ways. */
379 if(dinfo->comp_info[0].h_samp_factor==2 &&
380 dinfo->comp_info[0].v_samp_factor==2 &&
381 (i==TJSAMP_422 || i==TJSAMP_440))
382 {
383 int match=0;
384 for(k=1; k<dinfo->num_components; k++)
385 {
386 int href=tjMCUHeight[i]/8, vref=tjMCUWidth[i]/8;
387 if(dinfo->jpeg_color_space==JCS_YCCK && k==3)
388 {
389 href=vref=2;
390 }
391 if(dinfo->comp_info[k].h_samp_factor==href
392 && dinfo->comp_info[k].v_samp_factor==vref)
393 match++;
394 }
395 if(match==dinfo->num_components-1)
396 {
397 retval=i; break;
398 }
399 }
DRC9b49f0e2011-07-12 03:17:23 +0000400 }
401 }
402 return retval;
403}
404
405
DRCafc06922012-03-23 19:47:57 +0000406#ifndef JCS_EXTENSIONS
407
408/* Conversion functions to emulate the colorspace extensions. This allows the
409 TurboJPEG wrapper to be used with libjpeg */
410
411#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
412 int rowPad=pitch-width*PS; \
413 while(height--) \
414 { \
415 unsigned char *endOfRow=src+width*PS; \
416 while(src<endOfRow) \
417 { \
418 dst[RGB_RED]=src[ROFFSET]; \
419 dst[RGB_GREEN]=src[GOFFSET]; \
420 dst[RGB_BLUE]=src[BOFFSET]; \
421 dst+=RGB_PIXELSIZE; src+=PS; \
422 } \
423 src+=rowPad; \
424 } \
425}
426
427static unsigned char *toRGB(unsigned char *src, int width, int pitch,
428 int height, int pixelFormat, unsigned char *dst)
429{
430 unsigned char *retval=src;
431 switch(pixelFormat)
432 {
433 case TJPF_RGB:
434 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
435 retval=dst; TORGB(3, 0, 1, 2);
436 #endif
437 break;
438 case TJPF_BGR:
439 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
440 retval=dst; TORGB(3, 2, 1, 0);
441 #endif
442 break;
443 case TJPF_RGBX:
444 case TJPF_RGBA:
445 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
446 retval=dst; TORGB(4, 0, 1, 2);
447 #endif
448 break;
449 case TJPF_BGRX:
450 case TJPF_BGRA:
451 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
452 retval=dst; TORGB(4, 2, 1, 0);
453 #endif
454 break;
455 case TJPF_XRGB:
456 case TJPF_ARGB:
457 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
458 retval=dst; TORGB(4, 1, 2, 3);
459 #endif
460 break;
461 case TJPF_XBGR:
462 case TJPF_ABGR:
463 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
464 retval=dst; TORGB(4, 3, 2, 1);
465 #endif
466 break;
467 }
468 return retval;
469}
470
471#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
472 int rowPad=pitch-width*PS; \
473 while(height--) \
474 { \
475 unsigned char *endOfRow=dst+width*PS; \
476 while(dst<endOfRow) \
477 { \
478 dst[ROFFSET]=src[RGB_RED]; \
479 dst[GOFFSET]=src[RGB_GREEN]; \
480 dst[BOFFSET]=src[RGB_BLUE]; \
481 SETALPHA \
482 dst+=PS; src+=RGB_PIXELSIZE; \
483 } \
484 dst+=rowPad; \
485 } \
486}
487
488static void fromRGB(unsigned char *src, unsigned char *dst, int width,
489 int pitch, int height, int pixelFormat)
490{
491 switch(pixelFormat)
492 {
493 case TJPF_RGB:
494 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
495 FROMRGB(3, 0, 1, 2,);
496 #endif
497 break;
498 case TJPF_BGR:
499 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
500 FROMRGB(3, 2, 1, 0,);
501 #endif
502 break;
503 case TJPF_RGBX:
504 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
505 FROMRGB(4, 0, 1, 2,);
506 #endif
507 break;
508 case TJPF_RGBA:
509 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
510 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
511 #endif
512 break;
513 case TJPF_BGRX:
514 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
515 FROMRGB(4, 2, 1, 0,);
516 #endif
517 break;
518 case TJPF_BGRA:
519 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
520 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
521 #endif
522 break;
523 case TJPF_XRGB:
524 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
525 FROMRGB(4, 1, 2, 3,); return;
526 #endif
527 break;
528 case TJPF_ARGB:
529 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
530 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
531 #endif
532 break;
533 case TJPF_XBGR:
534 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
535 FROMRGB(4, 3, 2, 1,); return;
536 #endif
537 break;
538 case TJPF_ABGR:
539 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
540 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
541 #endif
542 break;
543 }
544}
545
546#endif
547
548
DRC9b28def2011-05-21 14:37:15 +0000549/* General API functions */
550
DRCb9ab64d2017-05-11 21:02:29 -0500551DLLEXPORT char* DLLCALL tjGetErrorStr2(tjhandle handle)
552{
553 tjinstance *this=(tjinstance *)handle;
554 if(this && this->isInstanceError)
555 {
556 this->isInstanceError=FALSE;
557 return this->errStr;
558 }
559 else return errStr;
560}
561
562
DRC9b28def2011-05-21 14:37:15 +0000563DLLEXPORT char* DLLCALL tjGetErrorStr(void)
564{
565 return errStr;
566}
567
568
569DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
570{
571 getinstance(handle);
572 if(setjmp(this->jerr.setjmp_buffer)) return -1;
573 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
574 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
575 free(this);
576 return 0;
577}
578
579
DRC6b76f752011-05-24 16:52:47 +0000580/* These are exposed mainly because Windows can't malloc() and free() across
581 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
582 with turbojpeg.dll for compatibility reasons. However, these functions
583 can potentially be used for other purposes by different implementations. */
584
585DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
586{
587 if(buf) free(buf);
588}
589
590
591DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
592{
593 return (unsigned char *)malloc(bytes);
594}
595
596
DRC9b28def2011-05-21 14:37:15 +0000597/* Compressor */
598
599static tjhandle _tjInitCompress(tjinstance *this)
600{
DRC6e053522016-02-04 09:20:41 -0600601 static unsigned char buffer[1];
602 unsigned char *buf=buffer; unsigned long size=1;
DRC9b28def2011-05-21 14:37:15 +0000603
604 /* This is also straight out of example.c */
605 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
606 this->jerr.pub.error_exit=my_error_exit;
607 this->jerr.pub.output_message=my_output_message;
DRC1f79c7c2015-06-01 19:22:41 +0000608 this->jerr.emit_message=this->jerr.pub.emit_message;
609 this->jerr.pub.emit_message=my_emit_message;
DRC9b28def2011-05-21 14:37:15 +0000610
611 if(setjmp(this->jerr.setjmp_buffer))
612 {
613 /* If we get here, the JPEG code has signaled an error. */
DRCdb044352016-07-14 13:36:47 -0500614 if(this) free(this);
615 return NULL;
DRC9b28def2011-05-21 14:37:15 +0000616 }
617
618 jpeg_create_compress(&this->cinfo);
619 /* Make an initial call so it will create the destination manager */
620 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
621
DRC007a42c2011-05-22 13:55:56 +0000622 this->init|=COMPRESS;
DRC9b28def2011-05-21 14:37:15 +0000623 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +0000624}
625
DRC890f1e02011-02-26 22:02:37 +0000626DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
627{
DRC9b28def2011-05-21 14:37:15 +0000628 tjinstance *this=NULL;
629 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000630 {
DRC007a42c2011-05-22 13:55:56 +0000631 snprintf(errStr, JMSG_LENGTH_MAX,
632 "tjInitCompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +0000633 return NULL;
634 }
DRC007a42c2011-05-22 13:55:56 +0000635 MEMZERO(this, sizeof(tjinstance));
DRCb9ab64d2017-05-11 21:02:29 -0500636 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
DRC9b28def2011-05-21 14:37:15 +0000637 return _tjInitCompress(this);
DRC890f1e02011-02-26 22:02:37 +0000638}
639
DRC84241602011-02-25 02:08:23 +0000640
DRC9b49f0e2011-07-12 03:17:23 +0000641DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
642 int jpegSubsamp)
643{
644 unsigned long retval=0; int mcuw, mcuh, chromasf;
645 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
DRCb9ab64d2017-05-11 21:02:29 -0500646 _throwg("tjBufSize(): Invalid argument");
DRC9b49f0e2011-07-12 03:17:23 +0000647
DRC006bc582014-02-27 21:22:54 +0000648 /* This allows for rare corner cases in which a JPEG image can actually be
649 larger than the uncompressed input (we wouldn't mention it if it hadn't
650 happened before.) */
DRC9b49f0e2011-07-12 03:17:23 +0000651 mcuw=tjMCUWidth[jpegSubsamp];
652 mcuh=tjMCUHeight[jpegSubsamp];
653 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
654 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
655
656 bailout:
657 return retval;
658}
659
DRC2e7b76b2009-04-03 12:04:24 +0000660DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
661{
DRCf3cf9732011-02-22 00:16:14 +0000662 unsigned long retval=0;
663 if(width<1 || height<1)
DRCb9ab64d2017-05-11 21:02:29 -0500664 _throwg("TJBUFSIZE(): Invalid argument");
DRCf3cf9732011-02-22 00:16:14 +0000665
DRC006bc582014-02-27 21:22:54 +0000666 /* This allows for rare corner cases in which a JPEG image can actually be
667 larger than the uncompressed input (we wouldn't mention it if it hadn't
668 happened before.) */
DRC007a42c2011-05-22 13:55:56 +0000669 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
DRCf3cf9732011-02-22 00:16:14 +0000670
671 bailout:
672 return retval;
673}
674
DRC84241602011-02-25 02:08:23 +0000675
DRCf610d612013-04-26 10:33:29 +0000676DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
DRCf3cf9732011-02-22 00:16:14 +0000677 int subsamp)
678{
DRC40dd3142014-08-17 12:23:49 +0000679 int retval=0, nc, i;
680
681 if(subsamp<0 || subsamp>=NUMSUBOPT)
DRCb9ab64d2017-05-11 21:02:29 -0500682 _throwg("tjBufSizeYUV2(): Invalid argument");
DRC40dd3142014-08-17 12:23:49 +0000683
684 nc=(subsamp==TJSAMP_GRAY? 1:3);
685 for(i=0; i<nc; i++)
686 {
DRC55620c62014-10-23 19:08:14 +0000687 int pw=tjPlaneWidth(i, width, subsamp);
688 int stride=PAD(pw, pad);
DRC40dd3142014-08-17 12:23:49 +0000689 int ph=tjPlaneHeight(i, height, subsamp);
DRC55620c62014-10-23 19:08:14 +0000690 if(pw<0 || ph<0) return -1;
DRC40dd3142014-08-17 12:23:49 +0000691 else retval+=stride*ph;
692 }
DRCf3cf9732011-02-22 00:16:14 +0000693
694 bailout:
695 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000696}
697
DRCf610d612013-04-26 10:33:29 +0000698DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
699 int subsamp)
700{
701 return tjBufSizeYUV2(width, 4, height, subsamp);
702}
DRC84241602011-02-25 02:08:23 +0000703
DRC9b49f0e2011-07-12 03:17:23 +0000704DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
705 int subsamp)
706{
707 return tjBufSizeYUV(width, height, subsamp);
708}
709
710
DRC40dd3142014-08-17 12:23:49 +0000711DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
712{
713 int pw, nc, retval=0;
714
715 if(width<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
DRCb9ab64d2017-05-11 21:02:29 -0500716 _throwg("tjPlaneWidth(): Invalid argument");
DRC40dd3142014-08-17 12:23:49 +0000717 nc=(subsamp==TJSAMP_GRAY? 1:3);
718 if(componentID<0 || componentID>=nc)
DRCb9ab64d2017-05-11 21:02:29 -0500719 _throwg("tjPlaneWidth(): Invalid argument");
DRC40dd3142014-08-17 12:23:49 +0000720
721 pw=PAD(width, tjMCUWidth[subsamp]/8);
722 if(componentID==0)
723 retval=pw;
724 else
725 retval=pw*8/tjMCUWidth[subsamp];
726
727 bailout:
728 return retval;
729}
730
731
732DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
733{
734 int ph, nc, retval=0;
735
736 if(height<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
DRCb9ab64d2017-05-11 21:02:29 -0500737 _throwg("tjPlaneHeight(): Invalid argument");
DRC40dd3142014-08-17 12:23:49 +0000738 nc=(subsamp==TJSAMP_GRAY? 1:3);
739 if(componentID<0 || componentID>=nc)
DRCb9ab64d2017-05-11 21:02:29 -0500740 _throwg("tjPlaneHeight(): Invalid argument");
DRC40dd3142014-08-17 12:23:49 +0000741
742 ph=PAD(height, tjMCUHeight[subsamp]/8);
743 if(componentID==0)
744 retval=ph;
745 else
746 retval=ph*8/tjMCUHeight[subsamp];
747
748 bailout:
749 return retval;
750}
751
752
753DLLEXPORT unsigned long DLLCALL tjPlaneSizeYUV(int componentID, int width,
754 int stride, int height, int subsamp)
755{
756 unsigned long retval=0;
757 int pw, ph;
758
759 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
DRCb9ab64d2017-05-11 21:02:29 -0500760 _throwg("tjPlaneSizeYUV(): Invalid argument");
DRC40dd3142014-08-17 12:23:49 +0000761
762 pw=tjPlaneWidth(componentID, width, subsamp);
763 ph=tjPlaneHeight(componentID, height, subsamp);
DRC22409742014-10-23 18:54:42 +0000764 if(pw<0 || ph<0) return -1;
DRC40dd3142014-08-17 12:23:49 +0000765
766 if(stride==0) stride=pw;
767 else stride=abs(stride);
768
769 retval=stride*(ph-1)+pw;
770
771 bailout:
772 return retval;
773}
774
775
DRC6fa14b32015-08-13 20:06:03 -0500776DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, const unsigned char *srcBuf,
DRC9b28def2011-05-21 14:37:15 +0000777 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
778 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
779{
DRCff78e372011-05-24 10:17:32 +0000780 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
DRCafc06922012-03-23 19:47:57 +0000781 #ifndef JCS_EXTENSIONS
782 unsigned char *rgbBuf=NULL;
783 #endif
DRC9b28def2011-05-21 14:37:15 +0000784
DRC41861622014-04-16 23:38:37 +0000785 getcinstance(handle)
DRC9b28def2011-05-21 14:37:15 +0000786 if((this->init&COMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +0000787 _throw("tjCompress2(): Instance has not been initialized for compression");
DRC9b28def2011-05-21 14:37:15 +0000788
789 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
790 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
791 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
DRC007a42c2011-05-22 13:55:56 +0000792 _throw("tjCompress2(): Invalid argument");
DRC9b28def2011-05-21 14:37:15 +0000793
DRC9b28def2011-05-21 14:37:15 +0000794 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
795
DRCafc06922012-03-23 19:47:57 +0000796 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +0000797 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
DRCafc06922012-03-23 19:47:57 +0000798 {
799 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
800 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
801 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
802 pitch=width*RGB_PIXELSIZE;
803 }
804 #endif
805
DRCd4c41fe2017-03-18 12:56:36 -0500806 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
807 _throw("tjCompress2(): Memory allocation failure");
808
809 if(setjmp(this->jerr.setjmp_buffer))
810 {
811 /* If we get here, the JPEG code has signaled an error. */
812 retval=-1;
813 goto bailout;
814 }
815
DRC9b28def2011-05-21 14:37:15 +0000816 cinfo->image_width=width;
817 cinfo->image_height=height;
818
DRCbec45b12015-05-17 15:56:18 +0000819 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
820 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
821 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +0000822
DRCff78e372011-05-24 10:17:32 +0000823 if(flags&TJFLAG_NOREALLOC)
824 {
DRC9b49f0e2011-07-12 03:17:23 +0000825 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +0000826 }
827 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
DRC73d74c12012-06-29 23:46:38 +0000828 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
DRCf12bb302011-09-07 05:03:18 +0000829 return -1;
DRC9b28def2011-05-21 14:37:15 +0000830
831 jpeg_start_compress(cinfo, TRUE);
DRC9b28def2011-05-21 14:37:15 +0000832 for(i=0; i<height; i++)
833 {
DRC6fa14b32015-08-13 20:06:03 -0500834 if(flags&TJFLAG_BOTTOMUP)
835 row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
836 else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
DRC9b28def2011-05-21 14:37:15 +0000837 }
838 while(cinfo->next_scanline<cinfo->image_height)
839 {
840 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
841 cinfo->image_height-cinfo->next_scanline);
842 }
843 jpeg_finish_compress(cinfo);
844
845 bailout:
846 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +0000847 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +0000848 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +0000849 #endif
DRC9b28def2011-05-21 14:37:15 +0000850 if(row_pointer) free(row_pointer);
DRC1f79c7c2015-06-01 19:22:41 +0000851 if(this->jerr.warning) retval=-1;
DRC9b28def2011-05-21 14:37:15 +0000852 return retval;
853}
854
855DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
856 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
857 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
858{
859 int retval=0; unsigned long size;
860 if(flags&TJ_YUV)
861 {
DRC9b49f0e2011-07-12 03:17:23 +0000862 size=tjBufSizeYUV(width, height, jpegSubsamp);
DRC9b28def2011-05-21 14:37:15 +0000863 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
864 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
865 }
866 else
867 {
DRC9b28def2011-05-21 14:37:15 +0000868 retval=tjCompress2(handle, srcBuf, width, pitch, height,
869 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
DRC25b995a2011-05-21 15:34:54 +0000870 flags|TJFLAG_NOREALLOC);
DRC9b28def2011-05-21 14:37:15 +0000871 }
872 *jpegSize=size;
873 return retval;
874}
875
876
DRC6fa14b32015-08-13 20:06:03 -0500877DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle,
878 const unsigned char *srcBuf, int width, int pitch, int height,
879 int pixelFormat, unsigned char **dstPlanes, int *strides, int subsamp,
880 int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000881{
DRC91e86ba2011-02-15 05:24:08 +0000882 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000883 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
884 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
885 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +0000886 int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +0000887 JSAMPLE *ptr;
DRC9b28def2011-05-21 14:37:15 +0000888 jpeg_component_info *compptr;
DRCafc06922012-03-23 19:47:57 +0000889 #ifndef JCS_EXTENSIONS
890 unsigned char *rgbBuf=NULL;
891 #endif
DRC2e7b76b2009-04-03 12:04:24 +0000892
DRC41861622014-04-16 23:38:37 +0000893 getcinstance(handle);
DRCb51ee892013-10-31 05:00:19 +0000894
DRCfbb67472010-11-24 04:02:37 +0000895 for(i=0; i<MAX_COMPONENTS; i++)
896 {
897 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
898 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
899 }
900
DRCe2f8e692013-10-30 22:21:06 +0000901 if((this->init&COMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +0000902 _throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
DRCe2f8e692013-10-30 22:21:06 +0000903
DRC9b28def2011-05-21 14:37:15 +0000904 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
DRCaecea382014-08-11 18:05:41 +0000905 || pixelFormat>=TJ_NUMPF || !dstPlanes || !dstPlanes[0] || subsamp<0
906 || subsamp>=NUMSUBOPT)
907 _throw("tjEncodeYUVPlanes(): Invalid argument");
908 if(subsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
909 _throw("tjEncodeYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000910
DRCcd7c3e62013-08-23 02:49:25 +0000911 if(pixelFormat==TJPF_CMYK)
DRCaecea382014-08-11 18:05:41 +0000912 _throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
DRCcd7c3e62013-08-23 02:49:25 +0000913
DRC9b28def2011-05-21 14:37:15 +0000914 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC2e7b76b2009-04-03 12:04:24 +0000915
DRCafc06922012-03-23 19:47:57 +0000916 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +0000917 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
DRCafc06922012-03-23 19:47:57 +0000918 {
919 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
DRCaecea382014-08-11 18:05:41 +0000920 if(!rgbBuf) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRCafc06922012-03-23 19:47:57 +0000921 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
922 pitch=width*RGB_PIXELSIZE;
923 }
924 #endif
925
DRCd4c41fe2017-03-18 12:56:36 -0500926 if(setjmp(this->jerr.setjmp_buffer))
927 {
928 /* If we get here, the JPEG code has signaled an error. */
929 retval=-1;
930 goto bailout;
931 }
932
DRC9b28def2011-05-21 14:37:15 +0000933 cinfo->image_width=width;
934 cinfo->image_height=height;
DRC2e7b76b2009-04-03 12:04:24 +0000935
DRCbec45b12015-05-17 15:56:18 +0000936 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
937 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
938 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +0000939
DRC73d74c12012-06-29 23:46:38 +0000940 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
DRC2e7b76b2009-04-03 12:04:24 +0000941
DRC38c99702014-02-11 09:45:18 +0000942 /* Execute only the parts of jpeg_start_compress() that we need. If we
943 were to call the whole jpeg_start_compress() function, then it would try
944 to write the file headers, which could overflow the output buffer if the
945 YUV image were very small. */
946 if(cinfo->global_state!=CSTATE_START)
DRCaecea382014-08-11 18:05:41 +0000947 _throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
DRC38c99702014-02-11 09:45:18 +0000948 (*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
DRC38c99702014-02-11 09:45:18 +0000949 jinit_c_master_control(cinfo, FALSE);
950 jinit_color_converter(cinfo);
951 jinit_downsampler(cinfo);
DRC50cfc462014-03-06 20:03:37 +0000952 (*cinfo->cconvert->start_pass)(cinfo);
DRC38c99702014-02-11 09:45:18 +0000953
DRC40dd3142014-08-17 12:23:49 +0000954 pw0=PAD(width, cinfo->max_h_samp_factor);
955 ph0=PAD(height, cinfo->max_v_samp_factor);
DRC2e7b76b2009-04-03 12:04:24 +0000956
DRC40dd3142014-08-17 12:23:49 +0000957 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
DRCaecea382014-08-11 18:05:41 +0000958 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000959 for(i=0; i<height; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000960 {
DRC6fa14b32015-08-13 20:06:03 -0500961 if(flags&TJFLAG_BOTTOMUP)
962 row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
963 else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
DRC9b28def2011-05-21 14:37:15 +0000964 }
DRC40dd3142014-08-17 12:23:49 +0000965 if(height<ph0)
966 for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
DRCfbb67472010-11-24 04:02:37 +0000967
DRC9b28def2011-05-21 14:37:15 +0000968 for(i=0; i<cinfo->num_components; i++)
969 {
970 compptr=&cinfo->comp_info[i];
971 _tmpbuf[i]=(JSAMPLE *)malloc(
972 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC7ee3ce92016-07-05 16:19:26 -0500973 /compptr->h_samp_factor, 32) * cinfo->max_v_samp_factor + 32);
DRCaecea382014-08-11 18:05:41 +0000974 if(!_tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000975 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRCaecea382014-08-11 18:05:41 +0000976 if(!tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000977 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRCfbb67472010-11-24 04:02:37 +0000978 {
DRC9b28def2011-05-21 14:37:15 +0000979 unsigned char *_tmpbuf_aligned=
DRC7ee3ce92016-07-05 16:19:26 -0500980 (unsigned char *)PAD((size_t)_tmpbuf[i], 32);
DRC9b28def2011-05-21 14:37:15 +0000981 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000982 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC7ee3ce92016-07-05 16:19:26 -0500983 /compptr->h_samp_factor, 32) * row];
DRCfbb67472010-11-24 04:02:37 +0000984 }
DRC7ee3ce92016-07-05 16:19:26 -0500985 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 32)
986 * compptr->v_samp_factor + 32);
DRCaecea382014-08-11 18:05:41 +0000987 if(!_tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000988 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCaecea382014-08-11 18:05:41 +0000989 if(!tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +0000990 for(row=0; row<compptr->v_samp_factor; row++)
991 {
992 unsigned char *_tmpbuf2_aligned=
DRC7ee3ce92016-07-05 16:19:26 -0500993 (unsigned char *)PAD((size_t)_tmpbuf2[i], 32);
DRC9b28def2011-05-21 14:37:15 +0000994 tmpbuf2[i][row]=&_tmpbuf2_aligned[
DRC7ee3ce92016-07-05 16:19:26 -0500995 PAD(compptr->width_in_blocks*DCTSIZE, 32) * row];
DRC9b28def2011-05-21 14:37:15 +0000996 }
DRC40dd3142014-08-17 12:23:49 +0000997 pw[i]=pw0*compptr->h_samp_factor/cinfo->max_h_samp_factor;
998 ph[i]=ph0*compptr->v_samp_factor/cinfo->max_v_samp_factor;
999 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
DRCaecea382014-08-11 18:05:41 +00001000 if(!outbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
1001 ptr=dstPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001002 for(row=0; row<ph[i]; row++)
DRC9b28def2011-05-21 14:37:15 +00001003 {
1004 outbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001005 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC9b28def2011-05-21 14:37:15 +00001006 }
1007 }
DRCfbb67472010-11-24 04:02:37 +00001008
DRCd4c41fe2017-03-18 12:56:36 -05001009 if(setjmp(this->jerr.setjmp_buffer))
1010 {
1011 /* If we get here, the JPEG code has signaled an error. */
1012 retval=-1;
1013 goto bailout;
1014 }
1015
DRC40dd3142014-08-17 12:23:49 +00001016 for(row=0; row<ph0; row+=cinfo->max_v_samp_factor)
DRCfbb67472010-11-24 04:02:37 +00001017 {
DRC9b28def2011-05-21 14:37:15 +00001018 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
1019 cinfo->max_v_samp_factor);
1020 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
1021 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
1022 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
1023 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
DRC40dd3142014-08-17 12:23:49 +00001024 compptr->v_samp_factor, pw[i]);
DRC6ee54592011-03-01 08:18:30 +00001025 }
DRC9b28def2011-05-21 14:37:15 +00001026 cinfo->next_scanline+=height;
1027 jpeg_abort_compress(cinfo);
DRC2e7b76b2009-04-03 12:04:24 +00001028
DRC91e86ba2011-02-15 05:24:08 +00001029 bailout:
DRC9b28def2011-05-21 14:37:15 +00001030 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
DRCafc06922012-03-23 19:47:57 +00001031 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +00001032 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +00001033 #endif
DRC2e7b76b2009-04-03 12:04:24 +00001034 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +00001035 for(i=0; i<MAX_COMPONENTS; i++)
1036 {
1037 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +00001038 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +00001039 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +00001040 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +00001041 if(outbuf[i]!=NULL) free(outbuf[i]);
1042 }
DRC1f79c7c2015-06-01 19:22:41 +00001043 if(this->jerr.warning) retval=-1;
DRC91e86ba2011-02-15 05:24:08 +00001044 return retval;
DRC2e7b76b2009-04-03 12:04:24 +00001045}
1046
DRC6fa14b32015-08-13 20:06:03 -05001047DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle,
1048 const unsigned char *srcBuf, int width, int pitch, int height,
1049 int pixelFormat, unsigned char *dstBuf, int pad, int subsamp, int flags)
DRCaecea382014-08-11 18:05:41 +00001050{
1051 unsigned char *dstPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001052 int pw0, ph0, strides[3], retval=-1;
DRCaecea382014-08-11 18:05:41 +00001053
DRCb9ab64d2017-05-11 21:02:29 -05001054 getcinstance(handle);
1055
DRCaecea382014-08-11 18:05:41 +00001056 if(width<=0 || height<=0 || dstBuf==NULL || pad<0 || !isPow2(pad)
1057 || subsamp<0 || subsamp>=NUMSUBOPT)
1058 _throw("tjEncodeYUV3(): Invalid argument");
1059
DRC40dd3142014-08-17 12:23:49 +00001060 pw0=tjPlaneWidth(0, width, subsamp);
1061 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +00001062 dstPlanes[0]=dstBuf;
DRC40dd3142014-08-17 12:23:49 +00001063 strides[0]=PAD(pw0, pad);
1064 if(subsamp==TJSAMP_GRAY)
1065 {
1066 strides[1]=strides[2]=0;
1067 dstPlanes[1]=dstPlanes[2]=NULL;
1068 }
1069 else
1070 {
1071 int pw1=tjPlaneWidth(1, width, subsamp);
1072 int ph1=tjPlaneHeight(1, height, subsamp);
1073 strides[1]=strides[2]=PAD(pw1, pad);
1074 dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1075 dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1076 }
DRCaecea382014-08-11 18:05:41 +00001077
1078 return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
1079 dstPlanes, strides, subsamp, flags);
1080
1081 bailout:
1082 return retval;
1083}
1084
DRCf610d612013-04-26 10:33:29 +00001085DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
1086 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
1087 int subsamp, int flags)
1088{
1089 return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
1090 dstBuf, 4, subsamp, flags);
1091}
1092
DRC9b28def2011-05-21 14:37:15 +00001093DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
1094 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
1095 int subsamp, int flags)
DRC84241602011-02-25 02:08:23 +00001096{
DRC9b28def2011-05-21 14:37:15 +00001097 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1098 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
DRC84241602011-02-25 02:08:23 +00001099}
1100
1101
DRCaecea382014-08-11 18:05:41 +00001102DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle,
DRC6fa14b32015-08-13 20:06:03 -05001103 const unsigned char **srcPlanes, int width, const int *strides, int height,
1104 int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual,
1105 int flags)
DRC910a3572013-10-30 23:02:57 +00001106{
1107 int i, row, retval=0, alloc=1; JSAMPROW *inbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +00001108 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
DRC910a3572013-10-30 23:02:57 +00001109 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001110 JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC910a3572013-10-30 23:02:57 +00001111
DRC41861622014-04-16 23:38:37 +00001112 getcinstance(handle)
DRCb51ee892013-10-31 05:00:19 +00001113
DRC910a3572013-10-30 23:02:57 +00001114 for(i=0; i<MAX_COMPONENTS; i++)
1115 {
1116 tmpbuf[i]=NULL; inbuf[i]=NULL;
1117 }
1118
DRC910a3572013-10-30 23:02:57 +00001119 if((this->init&COMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001120 _throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
DRC910a3572013-10-30 23:02:57 +00001121
DRCaecea382014-08-11 18:05:41 +00001122 if(!srcPlanes || !srcPlanes[0] || width<=0 || height<=0 || subsamp<0
DRC910a3572013-10-30 23:02:57 +00001123 || subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0
1124 || jpegQual>100)
DRCaecea382014-08-11 18:05:41 +00001125 _throw("tjCompressFromYUVPlanes(): Invalid argument");
1126 if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1127 _throw("tjCompressFromYUVPlanes(): Invalid argument");
DRC910a3572013-10-30 23:02:57 +00001128
1129 if(setjmp(this->jerr.setjmp_buffer))
1130 {
1131 /* If we get here, the JPEG code has signaled an error. */
1132 retval=-1;
1133 goto bailout;
1134 }
1135
1136 cinfo->image_width=width;
1137 cinfo->image_height=height;
1138
DRCbec45b12015-05-17 15:56:18 +00001139 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1140 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1141 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC910a3572013-10-30 23:02:57 +00001142
1143 if(flags&TJFLAG_NOREALLOC)
1144 {
1145 alloc=0; *jpegSize=tjBufSize(width, height, subsamp);
1146 }
1147 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1148 if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1)
1149 return -1;
1150 cinfo->raw_data_in=TRUE;
1151
1152 jpeg_start_compress(cinfo, TRUE);
1153 for(i=0; i<cinfo->num_components; i++)
1154 {
1155 jpeg_component_info *compptr=&cinfo->comp_info[i];
1156 int ih;
1157 iw[i]=compptr->width_in_blocks*DCTSIZE;
1158 ih=compptr->height_in_blocks*DCTSIZE;
DRC40dd3142014-08-17 12:23:49 +00001159 pw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor)
DRC910a3572013-10-30 23:02:57 +00001160 *compptr->h_samp_factor/cinfo->max_h_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001161 ph[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor)
DRC910a3572013-10-30 23:02:57 +00001162 *compptr->v_samp_factor/cinfo->max_v_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001163 if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
DRC910a3572013-10-30 23:02:57 +00001164 th[i]=compptr->v_samp_factor*DCTSIZE;
1165 tmpbufsize+=iw[i]*th[i];
DRC40dd3142014-08-17 12:23:49 +00001166 if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001167 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
DRC6fa14b32015-08-13 20:06:03 -05001168 ptr=(JSAMPLE *)srcPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001169 for(row=0; row<ph[i]; row++)
DRC910a3572013-10-30 23:02:57 +00001170 {
1171 inbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001172 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC910a3572013-10-30 23:02:57 +00001173 }
1174 }
1175 if(usetmpbuf)
1176 {
1177 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRCaecea382014-08-11 18:05:41 +00001178 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
DRC910a3572013-10-30 23:02:57 +00001179 ptr=_tmpbuf;
1180 for(i=0; i<cinfo->num_components; i++)
1181 {
1182 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001183 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
DRC910a3572013-10-30 23:02:57 +00001184 for(row=0; row<th[i]; row++)
1185 {
1186 tmpbuf[i][row]=ptr;
1187 ptr+=iw[i];
1188 }
1189 }
1190 }
1191
DRCd4c41fe2017-03-18 12:56:36 -05001192 if(setjmp(this->jerr.setjmp_buffer))
1193 {
1194 /* If we get here, the JPEG code has signaled an error. */
1195 retval=-1;
1196 goto bailout;
1197 }
1198
DRC910a3572013-10-30 23:02:57 +00001199 for(row=0; row<(int)cinfo->image_height;
1200 row+=cinfo->max_v_samp_factor*DCTSIZE)
1201 {
1202 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1203 int crow[MAX_COMPONENTS];
1204 for(i=0; i<cinfo->num_components; i++)
1205 {
1206 jpeg_component_info *compptr=&cinfo->comp_info[i];
1207 crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor;
1208 if(usetmpbuf)
1209 {
1210 int j, k;
DRC40dd3142014-08-17 12:23:49 +00001211 for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
DRC910a3572013-10-30 23:02:57 +00001212 {
DRC40dd3142014-08-17 12:23:49 +00001213 memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], pw[i]);
DRC006bc582014-02-27 21:22:54 +00001214 /* Duplicate last sample in row to fill out MCU */
DRC40dd3142014-08-17 12:23:49 +00001215 for(k=pw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][pw[i]-1];
DRC910a3572013-10-30 23:02:57 +00001216 }
DRC006bc582014-02-27 21:22:54 +00001217 /* Duplicate last row to fill out MCU */
DRC40dd3142014-08-17 12:23:49 +00001218 for(j=ph[i]-crow[i]; j<th[i]; j++)
1219 memcpy(tmpbuf[i][j], tmpbuf[i][ph[i]-crow[i]-1], iw[i]);
DRC910a3572013-10-30 23:02:57 +00001220 yuvptr[i]=tmpbuf[i];
1221 }
1222 else
1223 yuvptr[i]=&inbuf[i][crow[i]];
1224 }
1225 jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE);
1226 }
1227 jpeg_finish_compress(cinfo);
1228
1229 bailout:
1230 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1231 for(i=0; i<MAX_COMPONENTS; i++)
1232 {
1233 if(tmpbuf[i]) free(tmpbuf[i]);
1234 if(inbuf[i]) free(inbuf[i]);
1235 }
1236 if(_tmpbuf) free(_tmpbuf);
DRC1f79c7c2015-06-01 19:22:41 +00001237 if(this->jerr.warning) retval=-1;
DRC910a3572013-10-30 23:02:57 +00001238 return retval;
1239}
1240
DRC6fa14b32015-08-13 20:06:03 -05001241DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle,
1242 const unsigned char *srcBuf, int width, int pad, int height, int subsamp,
1243 unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)
DRCaecea382014-08-11 18:05:41 +00001244{
DRC6fa14b32015-08-13 20:06:03 -05001245 const unsigned char *srcPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001246 int pw0, ph0, strides[3], retval=-1;
DRCaecea382014-08-11 18:05:41 +00001247
DRCb9ab64d2017-05-11 21:02:29 -05001248 getcinstance(handle);
1249
DRCaecea382014-08-11 18:05:41 +00001250 if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
1251 || subsamp>=NUMSUBOPT)
1252 _throw("tjCompressFromYUV(): Invalid argument");
1253
DRC40dd3142014-08-17 12:23:49 +00001254 pw0=tjPlaneWidth(0, width, subsamp);
1255 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +00001256 srcPlanes[0]=srcBuf;
DRC40dd3142014-08-17 12:23:49 +00001257 strides[0]=PAD(pw0, pad);
1258 if(subsamp==TJSAMP_GRAY)
1259 {
1260 strides[1]=strides[2]=0;
1261 srcPlanes[1]=srcPlanes[2]=NULL;
1262 }
1263 else
1264 {
1265 int pw1=tjPlaneWidth(1, width, subsamp);
1266 int ph1=tjPlaneHeight(1, height, subsamp);
1267 strides[1]=strides[2]=PAD(pw1, pad);
1268 srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1269 srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1270 }
DRCaecea382014-08-11 18:05:41 +00001271
1272 return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1273 subsamp, jpegBuf, jpegSize, jpegQual, flags);
1274
1275 bailout:
1276 return retval;
1277}
1278
DRC910a3572013-10-30 23:02:57 +00001279
DRC9b28def2011-05-21 14:37:15 +00001280/* Decompressor */
DRC2e7b76b2009-04-03 12:04:24 +00001281
DRC9b28def2011-05-21 14:37:15 +00001282static tjhandle _tjInitDecompress(tjinstance *this)
DRC2e7b76b2009-04-03 12:04:24 +00001283{
DRC6e053522016-02-04 09:20:41 -06001284 static unsigned char buffer[1];
DRC2e7b76b2009-04-03 12:04:24 +00001285
DRC9b28def2011-05-21 14:37:15 +00001286 /* This is also straight out of example.c */
1287 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
1288 this->jerr.pub.error_exit=my_error_exit;
1289 this->jerr.pub.output_message=my_output_message;
DRC1f79c7c2015-06-01 19:22:41 +00001290 this->jerr.emit_message=this->jerr.pub.emit_message;
1291 this->jerr.pub.emit_message=my_emit_message;
DRC2e7b76b2009-04-03 12:04:24 +00001292
DRC9b28def2011-05-21 14:37:15 +00001293 if(setjmp(this->jerr.setjmp_buffer))
1294 {
1295 /* If we get here, the JPEG code has signaled an error. */
DRCdb044352016-07-14 13:36:47 -05001296 if(this) free(this);
1297 return NULL;
DRC9e17f7d2010-12-10 04:59:13 +00001298 }
DRC2e7b76b2009-04-03 12:04:24 +00001299
DRC9b28def2011-05-21 14:37:15 +00001300 jpeg_create_decompress(&this->dinfo);
1301 /* Make an initial call so it will create the source manager */
1302 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +00001303
DRC007a42c2011-05-22 13:55:56 +00001304 this->init|=DECOMPRESS;
DRC9b28def2011-05-21 14:37:15 +00001305 return (tjhandle)this;
DRC2e7b76b2009-04-03 12:04:24 +00001306}
1307
DRC890f1e02011-02-26 22:02:37 +00001308DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
1309{
DRC9b28def2011-05-21 14:37:15 +00001310 tjinstance *this;
1311 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00001312 {
DRC007a42c2011-05-22 13:55:56 +00001313 snprintf(errStr, JMSG_LENGTH_MAX,
1314 "tjInitDecompress(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00001315 return NULL;
1316 }
DRC007a42c2011-05-22 13:55:56 +00001317 MEMZERO(this, sizeof(tjinstance));
DRCb9ab64d2017-05-11 21:02:29 -05001318 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
DRC9b28def2011-05-21 14:37:15 +00001319 return _tjInitDecompress(this);
DRC890f1e02011-02-26 22:02:37 +00001320}
1321
DRC2e7b76b2009-04-03 12:04:24 +00001322
DRCcd7c3e62013-08-23 02:49:25 +00001323DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
DRC6fa14b32015-08-13 20:06:03 -05001324 const unsigned char *jpegBuf, unsigned long jpegSize, int *width,
1325 int *height, int *jpegSubsamp, int *jpegColorspace)
DRC1fe80f82010-12-14 01:21:29 +00001326{
DRC9b49f0e2011-07-12 03:17:23 +00001327 int retval=0;
DRC1fe80f82010-12-14 01:21:29 +00001328
DRC41861622014-04-16 23:38:37 +00001329 getdinstance(handle);
DRC9b28def2011-05-21 14:37:15 +00001330 if((this->init&DECOMPRESS)==0)
DRCcd7c3e62013-08-23 02:49:25 +00001331 _throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
DRC1fe80f82010-12-14 01:21:29 +00001332
DRC9b28def2011-05-21 14:37:15 +00001333 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
DRCcd7c3e62013-08-23 02:49:25 +00001334 || jpegSubsamp==NULL || jpegColorspace==NULL)
1335 _throw("tjDecompressHeader3(): Invalid argument");
DRC1fe80f82010-12-14 01:21:29 +00001336
DRC9b28def2011-05-21 14:37:15 +00001337 if(setjmp(this->jerr.setjmp_buffer))
1338 {
1339 /* If we get here, the JPEG code has signaled an error. */
DRC1fe80f82010-12-14 01:21:29 +00001340 return -1;
1341 }
1342
DRC9b28def2011-05-21 14:37:15 +00001343 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1344 jpeg_read_header(dinfo, TRUE);
DRC1fe80f82010-12-14 01:21:29 +00001345
DRC9b28def2011-05-21 14:37:15 +00001346 *width=dinfo->image_width;
1347 *height=dinfo->image_height;
DRC9b49f0e2011-07-12 03:17:23 +00001348 *jpegSubsamp=getSubsamp(dinfo);
DRCcd7c3e62013-08-23 02:49:25 +00001349 switch(dinfo->jpeg_color_space)
1350 {
1351 case JCS_GRAYSCALE: *jpegColorspace=TJCS_GRAY; break;
1352 case JCS_RGB: *jpegColorspace=TJCS_RGB; break;
1353 case JCS_YCbCr: *jpegColorspace=TJCS_YCbCr; break;
1354 case JCS_CMYK: *jpegColorspace=TJCS_CMYK; break;
1355 case JCS_YCCK: *jpegColorspace=TJCS_YCCK; break;
1356 default: *jpegColorspace=-1; break;
1357 }
DRC1fe80f82010-12-14 01:21:29 +00001358
DRC9b28def2011-05-21 14:37:15 +00001359 jpeg_abort_decompress(dinfo);
DRC1fe80f82010-12-14 01:21:29 +00001360
DRC9b28def2011-05-21 14:37:15 +00001361 if(*jpegSubsamp<0)
DRCcd7c3e62013-08-23 02:49:25 +00001362 _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1363 if(*jpegColorspace<0)
1364 _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
DRC007a42c2011-05-22 13:55:56 +00001365 if(*width<1 || *height<1)
DRCcd7c3e62013-08-23 02:49:25 +00001366 _throw("tjDecompressHeader3(): Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +00001367
1368 bailout:
DRC1f79c7c2015-06-01 19:22:41 +00001369 if(this->jerr.warning) retval=-1;
DRC91e86ba2011-02-15 05:24:08 +00001370 return retval;
1371}
1372
DRCcd7c3e62013-08-23 02:49:25 +00001373DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
1374 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
1375 int *jpegSubsamp)
1376{
1377 int jpegColorspace;
1378 return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1379 jpegSubsamp, &jpegColorspace);
1380}
1381
DRC9b28def2011-05-21 14:37:15 +00001382DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
1383 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
DRC91e86ba2011-02-15 05:24:08 +00001384{
DRC9b28def2011-05-21 14:37:15 +00001385 int jpegSubsamp;
1386 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1387 &jpegSubsamp);
DRC1fe80f82010-12-14 01:21:29 +00001388}
1389
1390
DRC109a5782011-03-01 09:53:07 +00001391DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +00001392{
DRC109a5782011-03-01 09:53:07 +00001393 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +00001394 {
DRC9b28def2011-05-21 14:37:15 +00001395 snprintf(errStr, JMSG_LENGTH_MAX,
DRC007a42c2011-05-22 13:55:56 +00001396 "tjGetScalingFactors(): Invalid argument");
DRC109a5782011-03-01 09:53:07 +00001397 return NULL;
DRCb28fc572011-02-22 06:41:29 +00001398 }
1399
DRC109a5782011-03-01 09:53:07 +00001400 *numscalingfactors=NUMSF;
1401 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +00001402}
1403
1404
DRC6fa14b32015-08-13 20:06:03 -05001405DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
1406 const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1407 int width, int pitch, int height, int pixelFormat, int flags)
DRC2e7b76b2009-04-03 12:04:24 +00001408{
DRC9b28def2011-05-21 14:37:15 +00001409 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRC109a5782011-03-01 09:53:07 +00001410 int jpegwidth, jpegheight, scaledw, scaledh;
DRCafc06922012-03-23 19:47:57 +00001411 #ifndef JCS_EXTENSIONS
1412 unsigned char *rgbBuf=NULL;
1413 unsigned char *_dstBuf=NULL; int _pitch=0;
1414 #endif
DRC2e7b76b2009-04-03 12:04:24 +00001415
DRC41861622014-04-16 23:38:37 +00001416 getdinstance(handle);
DRC9b28def2011-05-21 14:37:15 +00001417 if((this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00001418 _throw("tjDecompress2(): Instance has not been initialized for decompression");
DRC9b28def2011-05-21 14:37:15 +00001419
1420 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
1421 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
1422 _throw("tjDecompress2(): Invalid argument");
1423
DRCbec45b12015-05-17 15:56:18 +00001424 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1425 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1426 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC9b28def2011-05-21 14:37:15 +00001427
1428 if(setjmp(this->jerr.setjmp_buffer))
1429 {
1430 /* If we get here, the JPEG code has signaled an error. */
1431 retval=-1;
1432 goto bailout;
1433 }
1434
1435 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1436 jpeg_read_header(dinfo, TRUE);
DRCb9ab64d2017-05-11 21:02:29 -05001437 if(setDecompDefaults(this, pixelFormat, flags)==-1)
DRC2eda8212012-03-23 19:32:38 +00001438 {
1439 retval=-1; goto bailout;
1440 }
DRC9b28def2011-05-21 14:37:15 +00001441
DRC25b995a2011-05-21 15:34:54 +00001442 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRC9b28def2011-05-21 14:37:15 +00001443
1444 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1445 if(width==0) width=jpegwidth;
1446 if(height==0) height=jpegheight;
1447 for(i=0; i<NUMSF; i++)
1448 {
1449 scaledw=TJSCALED(jpegwidth, sf[i]);
1450 scaledh=TJSCALED(jpegheight, sf[i]);
1451 if(scaledw<=width && scaledh<=height)
DRCf610d612013-04-26 10:33:29 +00001452 break;
DRC9b28def2011-05-21 14:37:15 +00001453 }
DRC58ae4012015-08-26 20:29:36 -05001454 if(i>=NUMSF)
DRC007a42c2011-05-22 13:55:56 +00001455 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
DRC9b28def2011-05-21 14:37:15 +00001456 width=scaledw; height=scaledh;
1457 dinfo->scale_num=sf[i].num;
1458 dinfo->scale_denom=sf[i].denom;
1459
1460 jpeg_start_decompress(dinfo);
1461 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
DRCafc06922012-03-23 19:47:57 +00001462
1463 #ifndef JCS_EXTENSIONS
DRC230d09d2014-04-20 09:42:49 +00001464 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
DRCafc06922012-03-23 19:47:57 +00001465 (RGB_RED!=tjRedOffset[pixelFormat] ||
1466 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1467 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1468 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1469 {
1470 rgbBuf=(unsigned char *)malloc(width*height*3);
1471 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1472 _pitch=pitch; pitch=width*3;
1473 _dstBuf=dstBuf; dstBuf=rgbBuf;
1474 }
1475 #endif
1476
DRC9b28def2011-05-21 14:37:15 +00001477 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1478 *dinfo->output_height))==NULL)
DRC007a42c2011-05-22 13:55:56 +00001479 _throw("tjDecompress2(): Memory allocation failure");
DRCd4c41fe2017-03-18 12:56:36 -05001480 if(setjmp(this->jerr.setjmp_buffer))
1481 {
1482 /* If we get here, the JPEG code has signaled an error. */
1483 retval=-1;
1484 goto bailout;
1485 }
DRC9b28def2011-05-21 14:37:15 +00001486 for(i=0; i<(int)dinfo->output_height; i++)
1487 {
DRC25b995a2011-05-21 15:34:54 +00001488 if(flags&TJFLAG_BOTTOMUP)
DRC9b28def2011-05-21 14:37:15 +00001489 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1490 else row_pointer[i]=&dstBuf[i*pitch];
1491 }
1492 while(dinfo->output_scanline<dinfo->output_height)
1493 {
1494 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1495 dinfo->output_height-dinfo->output_scanline);
1496 }
1497 jpeg_finish_decompress(dinfo);
1498
DRCafc06922012-03-23 19:47:57 +00001499 #ifndef JCS_EXTENSIONS
1500 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1501 #endif
1502
DRC9b28def2011-05-21 14:37:15 +00001503 bailout:
1504 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRCafc06922012-03-23 19:47:57 +00001505 #ifndef JCS_EXTENSIONS
DRCea3396a2012-04-26 03:18:49 +00001506 if(rgbBuf) free(rgbBuf);
DRCafc06922012-03-23 19:47:57 +00001507 #endif
DRC9b28def2011-05-21 14:37:15 +00001508 if(row_pointer) free(row_pointer);
DRC1f79c7c2015-06-01 19:22:41 +00001509 if(this->jerr.warning) retval=-1;
DRC9b28def2011-05-21 14:37:15 +00001510 return retval;
1511}
1512
1513DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1514 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1515 int height, int pixelSize, int flags)
1516{
1517 if(flags&TJ_YUV)
1518 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1519 else
1520 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1521 height, getPixelFormat(pixelSize, flags), flags);
1522}
1523
1524
DRC34dca052014-02-28 09:17:14 +00001525static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
1526 int pixelFormat, int subsamp, int flags)
1527{
DRC895fd6d2014-02-28 09:35:34 +00001528 int i;
1529
DRC34dca052014-02-28 09:17:14 +00001530 dinfo->scale_num=dinfo->scale_denom=1;
1531
1532 if(subsamp==TJSAMP_GRAY)
1533 {
DRCc9014492014-03-10 09:34:04 +00001534 dinfo->num_components=dinfo->comps_in_scan=1;
DRC34dca052014-02-28 09:17:14 +00001535 dinfo->jpeg_color_space=JCS_GRAYSCALE;
1536 }
1537 else
1538 {
DRCc9014492014-03-10 09:34:04 +00001539 dinfo->num_components=dinfo->comps_in_scan=3;
DRC34dca052014-02-28 09:17:14 +00001540 dinfo->jpeg_color_space=JCS_YCbCr;
1541 }
1542
1543 dinfo->comp_info=(jpeg_component_info *)
1544 (*dinfo->mem->alloc_small)((j_common_ptr)dinfo, JPOOL_IMAGE,
DRC5de454b2014-05-18 19:04:03 +00001545 dinfo->num_components*sizeof(jpeg_component_info));
DRC34dca052014-02-28 09:17:14 +00001546
DRC2bdc0422014-03-07 03:52:57 +00001547 for(i=0; i<dinfo->num_components; i++)
DRC34dca052014-02-28 09:17:14 +00001548 {
DRC2bdc0422014-03-07 03:52:57 +00001549 jpeg_component_info *compptr=&dinfo->comp_info[i];
1550 compptr->h_samp_factor=(i==0)? tjMCUWidth[subsamp]/8:1;
1551 compptr->v_samp_factor=(i==0)? tjMCUHeight[subsamp]/8:1;
1552 compptr->component_index=i;
DRC15c08762014-03-10 20:11:56 +00001553 compptr->component_id=i+1;
DRC2bdc0422014-03-07 03:52:57 +00001554 compptr->quant_tbl_no=compptr->dc_tbl_no=compptr->ac_tbl_no=
1555 (i==0)? 0:1;
1556 dinfo->cur_comp_info[i]=compptr;
DRC34dca052014-02-28 09:17:14 +00001557 }
DRCc9014492014-03-10 09:34:04 +00001558 dinfo->data_precision=8;
1559 for(i=0; i<2; i++)
1560 {
1561 if(dinfo->quant_tbl_ptrs[i]==NULL)
1562 dinfo->quant_tbl_ptrs[i]=jpeg_alloc_quant_table((j_common_ptr)dinfo);
1563 }
DRC34dca052014-02-28 09:17:14 +00001564
1565 return 0;
1566}
1567
1568
1569int my_read_markers(j_decompress_ptr dinfo)
1570{
1571 return JPEG_REACHED_SOS;
1572}
1573
1574void my_reset_marker_reader(j_decompress_ptr dinfo)
1575{
1576}
1577
DRCaecea382014-08-11 18:05:41 +00001578DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
DRC6fa14b32015-08-13 20:06:03 -05001579 const unsigned char **srcPlanes, const int *strides, int subsamp,
1580 unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat,
1581 int flags)
DRC34dca052014-02-28 09:17:14 +00001582{
1583 int i, retval=0; JSAMPROW *row_pointer=NULL;
1584 JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1585 JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
DRC40dd3142014-08-17 12:23:49 +00001586 int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001587 JSAMPLE *ptr;
DRC34dca052014-02-28 09:17:14 +00001588 jpeg_component_info *compptr;
1589 #ifndef JCS_EXTENSIONS
1590 unsigned char *rgbBuf=NULL;
DRC230d09d2014-04-20 09:42:49 +00001591 unsigned char *_dstBuf=NULL; int _pitch=0;
DRC34dca052014-02-28 09:17:14 +00001592 #endif
DRCbc56b752014-05-16 10:43:44 +00001593 int (*old_read_markers)(j_decompress_ptr);
1594 void (*old_reset_marker_reader)(j_decompress_ptr);
DRC34dca052014-02-28 09:17:14 +00001595
DRC41861622014-04-16 23:38:37 +00001596 getdinstance(handle);
DRC34dca052014-02-28 09:17:14 +00001597
1598 for(i=0; i<MAX_COMPONENTS; i++)
1599 {
1600 tmpbuf[i]=NULL; _tmpbuf[i]=NULL; inbuf[i]=NULL;
1601 }
1602
1603 if((this->init&DECOMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001604 _throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
DRC34dca052014-02-28 09:17:14 +00001605
DRCaecea382014-08-11 18:05:41 +00001606 if(!srcPlanes || !srcPlanes[0] || subsamp<0 || subsamp>=NUMSUBOPT
DRC34dca052014-02-28 09:17:14 +00001607 || dstBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
1608 || pixelFormat>=TJ_NUMPF)
DRCaecea382014-08-11 18:05:41 +00001609 _throw("tjDecodeYUVPlanes(): Invalid argument");
1610 if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1611 _throw("tjDecodeYUVPlanes(): Invalid argument");
DRC34dca052014-02-28 09:17:14 +00001612
1613 if(setjmp(this->jerr.setjmp_buffer))
1614 {
1615 /* If we get here, the JPEG code has signaled an error. */
1616 retval=-1;
1617 goto bailout;
1618 }
1619
1620 if(pixelFormat==TJPF_CMYK)
DRCaecea382014-08-11 18:05:41 +00001621 _throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
DRC34dca052014-02-28 09:17:14 +00001622
1623 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
DRC34dca052014-02-28 09:17:14 +00001624 dinfo->image_width=width;
1625 dinfo->image_height=height;
1626
DRCbec45b12015-05-17 15:56:18 +00001627 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1628 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1629 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC34dca052014-02-28 09:17:14 +00001630
DRC34dca052014-02-28 09:17:14 +00001631 if(setDecodeDefaults(dinfo, pixelFormat, subsamp, flags)==-1)
1632 {
1633 retval=-1; goto bailout;
1634 }
1635 old_read_markers=dinfo->marker->read_markers;
1636 dinfo->marker->read_markers=my_read_markers;
1637 old_reset_marker_reader=dinfo->marker->reset_marker_reader;
1638 dinfo->marker->reset_marker_reader=my_reset_marker_reader;
1639 jpeg_read_header(dinfo, TRUE);
1640 dinfo->marker->read_markers=old_read_markers;
1641 dinfo->marker->reset_marker_reader=old_reset_marker_reader;
1642
DRCb9ab64d2017-05-11 21:02:29 -05001643 if(setDecompDefaults(this, pixelFormat, flags)==-1)
DRC34dca052014-02-28 09:17:14 +00001644 {
1645 retval=-1; goto bailout;
1646 }
DRC7d9f7582014-03-10 20:14:53 +00001647 dinfo->do_fancy_upsampling=FALSE;
DRCdb6d8fc2015-06-08 18:31:34 +00001648 dinfo->Se=DCTSIZE2-1;
DRC2bdc0422014-03-07 03:52:57 +00001649 jinit_master_decompress(dinfo);
DRC34dca052014-02-28 09:17:14 +00001650 (*dinfo->upsample->start_pass)(dinfo);
1651
DRC40dd3142014-08-17 12:23:49 +00001652 pw0=PAD(width, dinfo->max_h_samp_factor);
1653 ph0=PAD(height, dinfo->max_v_samp_factor);
DRC34dca052014-02-28 09:17:14 +00001654
1655 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
1656
DRC230d09d2014-04-20 09:42:49 +00001657 #ifndef JCS_EXTENSIONS
1658 if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
1659 (RGB_RED!=tjRedOffset[pixelFormat] ||
1660 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1661 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1662 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1663 {
1664 rgbBuf=(unsigned char *)malloc(width*height*3);
DRCaecea382014-08-11 18:05:41 +00001665 if(!rgbBuf) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC230d09d2014-04-20 09:42:49 +00001666 _pitch=pitch; pitch=width*3;
1667 _dstBuf=dstBuf; dstBuf=rgbBuf;
1668 }
1669 #endif
1670
DRC40dd3142014-08-17 12:23:49 +00001671 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
DRCaecea382014-08-11 18:05:41 +00001672 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001673 for(i=0; i<height; i++)
1674 {
1675 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*pitch];
1676 else row_pointer[i]=&dstBuf[i*pitch];
1677 }
DRC40dd3142014-08-17 12:23:49 +00001678 if(height<ph0)
1679 for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
DRC34dca052014-02-28 09:17:14 +00001680
1681 for(i=0; i<dinfo->num_components; i++)
1682 {
1683 compptr=&dinfo->comp_info[i];
DRC7ee3ce92016-07-05 16:19:26 -05001684 _tmpbuf[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 32)
1685 * compptr->v_samp_factor + 32);
DRCaecea382014-08-11 18:05:41 +00001686 if(!_tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001687 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCaecea382014-08-11 18:05:41 +00001688 if(!tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC34dca052014-02-28 09:17:14 +00001689 for(row=0; row<compptr->v_samp_factor; row++)
1690 {
1691 unsigned char *_tmpbuf_aligned=
DRC7ee3ce92016-07-05 16:19:26 -05001692 (unsigned char *)PAD((size_t)_tmpbuf[i], 32);
DRC34dca052014-02-28 09:17:14 +00001693 tmpbuf[i][row]=&_tmpbuf_aligned[
DRC7ee3ce92016-07-05 16:19:26 -05001694 PAD(compptr->width_in_blocks*DCTSIZE, 32) * row];
DRC34dca052014-02-28 09:17:14 +00001695 }
DRC40dd3142014-08-17 12:23:49 +00001696 pw[i]=pw0*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1697 ph[i]=ph0*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1698 inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
DRCaecea382014-08-11 18:05:41 +00001699 if(!inbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
DRC6fa14b32015-08-13 20:06:03 -05001700 ptr=(JSAMPLE *)srcPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001701 for(row=0; row<ph[i]; row++)
DRC34dca052014-02-28 09:17:14 +00001702 {
1703 inbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001704 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC34dca052014-02-28 09:17:14 +00001705 }
1706 }
1707
DRCd4c41fe2017-03-18 12:56:36 -05001708 if(setjmp(this->jerr.setjmp_buffer))
1709 {
1710 /* If we get here, the JPEG code has signaled an error. */
1711 retval=-1;
1712 goto bailout;
1713 }
1714
DRC40dd3142014-08-17 12:23:49 +00001715 for(row=0; row<ph0; row+=dinfo->max_v_samp_factor)
DRC34dca052014-02-28 09:17:14 +00001716 {
1717 JDIMENSION inrow=0, outrow=0;
1718 for(i=0, compptr=dinfo->comp_info; i<dinfo->num_components; i++, compptr++)
1719 jcopy_sample_rows(inbuf[i],
1720 row*compptr->v_samp_factor/dinfo->max_v_samp_factor, tmpbuf[i], 0,
DRC40dd3142014-08-17 12:23:49 +00001721 compptr->v_samp_factor, pw[i]);
DRC34dca052014-02-28 09:17:14 +00001722 (dinfo->upsample->upsample)(dinfo, tmpbuf, &inrow,
1723 dinfo->max_v_samp_factor, &row_pointer[row], &outrow,
1724 dinfo->max_v_samp_factor);
1725 }
1726 jpeg_abort_decompress(dinfo);
1727
DRC230d09d2014-04-20 09:42:49 +00001728 #ifndef JCS_EXTENSIONS
1729 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1730 #endif
1731
DRC34dca052014-02-28 09:17:14 +00001732 bailout:
1733 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1734 #ifndef JCS_EXTENSIONS
1735 if(rgbBuf) free(rgbBuf);
1736 #endif
1737 if(row_pointer) free(row_pointer);
1738 for(i=0; i<MAX_COMPONENTS; i++)
1739 {
1740 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
1741 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
1742 if(inbuf[i]!=NULL) free(inbuf[i]);
1743 }
DRC1f79c7c2015-06-01 19:22:41 +00001744 if(this->jerr.warning) retval=-1;
DRC34dca052014-02-28 09:17:14 +00001745 return retval;
1746}
1747
DRC6fa14b32015-08-13 20:06:03 -05001748DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
DRCaecea382014-08-11 18:05:41 +00001749 int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
1750 int height, int pixelFormat, int flags)
1751{
DRC6fa14b32015-08-13 20:06:03 -05001752 const unsigned char *srcPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001753 int pw0, ph0, strides[3], retval=-1;
DRC34dca052014-02-28 09:17:14 +00001754
DRCb9ab64d2017-05-11 21:02:29 -05001755 getdinstance(handle);
1756
DRCaecea382014-08-11 18:05:41 +00001757 if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT
1758 || width<=0 || height<=0)
1759 _throw("tjDecodeYUV(): Invalid argument");
1760
DRC40dd3142014-08-17 12:23:49 +00001761 pw0=tjPlaneWidth(0, width, subsamp);
1762 ph0=tjPlaneHeight(0, height, subsamp);
DRCaecea382014-08-11 18:05:41 +00001763 srcPlanes[0]=srcBuf;
DRC40dd3142014-08-17 12:23:49 +00001764 strides[0]=PAD(pw0, pad);
1765 if(subsamp==TJSAMP_GRAY)
1766 {
1767 strides[1]=strides[2]=0;
1768 srcPlanes[1]=srcPlanes[2]=NULL;
1769 }
1770 else
1771 {
1772 int pw1=tjPlaneWidth(1, width, subsamp);
1773 int ph1=tjPlaneHeight(1, height, subsamp);
1774 strides[1]=strides[2]=PAD(pw1, pad);
1775 srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1776 srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1777 }
DRCaecea382014-08-11 18:05:41 +00001778
1779 return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1780 pitch, height, pixelFormat, flags);
1781
1782 bailout:
1783 return retval;
1784}
1785
1786DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle,
DRC6fa14b32015-08-13 20:06:03 -05001787 const unsigned char *jpegBuf, unsigned long jpegSize,
1788 unsigned char **dstPlanes, int width, int *strides, int height, int flags)
DRC9b28def2011-05-21 14:37:15 +00001789{
DRCf610d612013-04-26 10:33:29 +00001790 int i, sfi, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001791 int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
DRC40dd3142014-08-17 12:23:49 +00001792 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
DRC9b28def2011-05-21 14:37:15 +00001793 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
DRCaecea382014-08-11 18:05:41 +00001794 JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC418fe282013-05-07 21:17:35 +00001795 int dctsize;
DRC9b28def2011-05-21 14:37:15 +00001796
DRC41861622014-04-16 23:38:37 +00001797 getdinstance(handle);
DRCb51ee892013-10-31 05:00:19 +00001798
DRCf9cf5c72010-12-10 10:58:49 +00001799 for(i=0; i<MAX_COMPONENTS; i++)
1800 {
1801 tmpbuf[i]=NULL; outbuf[i]=NULL;
1802 }
DRC9e17f7d2010-12-10 04:59:13 +00001803
DRCe2f8e692013-10-30 22:21:06 +00001804 if((this->init&DECOMPRESS)==0)
DRCaecea382014-08-11 18:05:41 +00001805 _throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
DRCe2f8e692013-10-30 22:21:06 +00001806
DRCaecea382014-08-11 18:05:41 +00001807 if(jpegBuf==NULL || jpegSize<=0 || !dstPlanes || !dstPlanes[0] || width<0
1808 || height<0)
1809 _throw("tjDecompressToYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001810
DRCbec45b12015-05-17 15:56:18 +00001811 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1812 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1813 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC0c6a2712010-02-22 08:34:44 +00001814
DRC9b28def2011-05-21 14:37:15 +00001815 if(setjmp(this->jerr.setjmp_buffer))
1816 {
1817 /* If we get here, the JPEG code has signaled an error. */
DRC91e86ba2011-02-15 05:24:08 +00001818 retval=-1;
1819 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +00001820 }
DRC2e7b76b2009-04-03 12:04:24 +00001821
DRCaecea382014-08-11 18:05:41 +00001822 if(!this->headerRead)
1823 {
1824 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1825 jpeg_read_header(dinfo, TRUE);
1826 }
1827 this->headerRead=0;
DRC418fe282013-05-07 21:17:35 +00001828 jpegSubsamp=getSubsamp(dinfo);
1829 if(jpegSubsamp<0)
DRCaecea382014-08-11 18:05:41 +00001830 _throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1831
1832 if(jpegSubsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1833 _throw("tjDecompressToYUVPlanes(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +00001834
DRCf610d612013-04-26 10:33:29 +00001835 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1836 if(width==0) width=jpegwidth;
1837 if(height==0) height=jpegheight;
1838 for(i=0; i<NUMSF; i++)
1839 {
1840 scaledw=TJSCALED(jpegwidth, sf[i]);
1841 scaledh=TJSCALED(jpegheight, sf[i]);
1842 if(scaledw<=width && scaledh<=height)
1843 break;
1844 }
DRC58ae4012015-08-26 20:29:36 -05001845 if(i>=NUMSF)
DRCaecea382014-08-11 18:05:41 +00001846 _throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
DRCcd7c3e62013-08-23 02:49:25 +00001847 if(dinfo->num_components>3)
DRCaecea382014-08-11 18:05:41 +00001848 _throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
DRCcd7c3e62013-08-23 02:49:25 +00001849
DRCf610d612013-04-26 10:33:29 +00001850 width=scaledw; height=scaledh;
1851 dinfo->scale_num=sf[i].num;
1852 dinfo->scale_denom=sf[i].denom;
1853 sfi=i;
1854 jpeg_calc_output_dimensions(dinfo);
1855
DRC418fe282013-05-07 21:17:35 +00001856 dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
1857
DRC9b28def2011-05-21 14:37:15 +00001858 for(i=0; i<dinfo->num_components; i++)
DRC2e7b76b2009-04-03 12:04:24 +00001859 {
DRC9b28def2011-05-21 14:37:15 +00001860 jpeg_component_info *compptr=&dinfo->comp_info[i];
1861 int ih;
DRC418fe282013-05-07 21:17:35 +00001862 iw[i]=compptr->width_in_blocks*dctsize;
1863 ih=compptr->height_in_blocks*dctsize;
DRC40dd3142014-08-17 12:23:49 +00001864 pw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001865 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001866 ph[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
DRC9b28def2011-05-21 14:37:15 +00001867 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRC40dd3142014-08-17 12:23:49 +00001868 if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
DRC418fe282013-05-07 21:17:35 +00001869 th[i]=compptr->v_samp_factor*dctsize;
DRC9b28def2011-05-21 14:37:15 +00001870 tmpbufsize+=iw[i]*th[i];
DRC40dd3142014-08-17 12:23:49 +00001871 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001872 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1873 ptr=dstPlanes[i];
DRC40dd3142014-08-17 12:23:49 +00001874 for(row=0; row<ph[i]; row++)
DRC9b28def2011-05-21 14:37:15 +00001875 {
1876 outbuf[i][row]=ptr;
DRC40dd3142014-08-17 12:23:49 +00001877 ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
DRC9b28def2011-05-21 14:37:15 +00001878 }
1879 }
1880 if(usetmpbuf)
1881 {
1882 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRCaecea382014-08-11 18:05:41 +00001883 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001884 ptr=_tmpbuf;
1885 for(i=0; i<dinfo->num_components; i++)
1886 {
1887 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRCaecea382014-08-11 18:05:41 +00001888 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
DRC9b28def2011-05-21 14:37:15 +00001889 for(row=0; row<th[i]; row++)
1890 {
1891 tmpbuf[i][row]=ptr;
1892 ptr+=iw[i];
1893 }
1894 }
1895 }
DRC9e17f7d2010-12-10 04:59:13 +00001896
DRCd4c41fe2017-03-18 12:56:36 -05001897 if(setjmp(this->jerr.setjmp_buffer))
1898 {
1899 /* If we get here, the JPEG code has signaled an error. */
1900 retval=-1;
1901 goto bailout;
1902 }
1903
DRC25b995a2011-05-21 15:34:54 +00001904 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
DRCe0419b52012-07-03 20:01:31 +00001905 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
DRC9b28def2011-05-21 14:37:15 +00001906 dinfo->raw_data_out=TRUE;
1907
1908 jpeg_start_decompress(dinfo);
1909 for(row=0; row<(int)dinfo->output_height;
DRC418fe282013-05-07 21:17:35 +00001910 row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
DRC9b28def2011-05-21 14:37:15 +00001911 {
1912 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1913 int crow[MAX_COMPONENTS];
DRC9e17f7d2010-12-10 04:59:13 +00001914 for(i=0; i<dinfo->num_components; i++)
1915 {
1916 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRC418fe282013-05-07 21:17:35 +00001917 if(jpegSubsamp==TJ_420)
1918 {
1919 /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1920 to be clever and use the IDCT to perform upsampling on the U and V
1921 planes. For instance, if the output image is to be scaled by 1/2
1922 relative to the JPEG image, then the scaling factor and upsampling
1923 effectively cancel each other, so a normal 8x8 IDCT can be used.
1924 However, this is not desirable when using the decompress-to-YUV
1925 functionality in TurboJPEG, since we want to output the U and V
1926 planes in their subsampled form. Thus, we have to override some
1927 internal libjpeg parameters to force it to use the "scaled" IDCT
1928 functions on the U and V planes. */
1929 compptr->_DCT_scaled_size=dctsize;
1930 compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
1931 sf[sfi].num/sf[sfi].denom*
1932 compptr->v_samp_factor/dinfo->max_v_samp_factor;
1933 dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1934 }
DRC9b28def2011-05-21 14:37:15 +00001935 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1936 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1937 else yuvptr[i]=&outbuf[i][crow[i]];
DRCf9cf5c72010-12-10 10:58:49 +00001938 }
DRCf610d612013-04-26 10:33:29 +00001939 jpeg_read_raw_data(dinfo, yuvptr,
DRC418fe282013-05-07 21:17:35 +00001940 dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
DRCf9cf5c72010-12-10 10:58:49 +00001941 if(usetmpbuf)
1942 {
DRC9b28def2011-05-21 14:37:15 +00001943 int j;
DRCf9cf5c72010-12-10 10:58:49 +00001944 for(i=0; i<dinfo->num_components; i++)
1945 {
DRC40dd3142014-08-17 12:23:49 +00001946 for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +00001947 {
DRC40dd3142014-08-17 12:23:49 +00001948 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], pw[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001949 }
DRC9e17f7d2010-12-10 04:59:13 +00001950 }
1951 }
1952 }
DRC9b28def2011-05-21 14:37:15 +00001953 jpeg_finish_decompress(dinfo);
DRC2e7b76b2009-04-03 12:04:24 +00001954
DRC91e86ba2011-02-15 05:24:08 +00001955 bailout:
DRC9b28def2011-05-21 14:37:15 +00001956 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC9e17f7d2010-12-10 04:59:13 +00001957 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +00001958 {
1959 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +00001960 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +00001961 }
1962 if(_tmpbuf) free(_tmpbuf);
DRC1f79c7c2015-06-01 19:22:41 +00001963 if(this->jerr.warning) retval=-1;
DRC91e86ba2011-02-15 05:24:08 +00001964 return retval;
DRC2e7b76b2009-04-03 12:04:24 +00001965}
1966
DRCaecea382014-08-11 18:05:41 +00001967DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
DRC6fa14b32015-08-13 20:06:03 -05001968 const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
DRCaecea382014-08-11 18:05:41 +00001969 int width, int pad, int height, int flags)
1970{
1971 unsigned char *dstPlanes[3];
DRC40dd3142014-08-17 12:23:49 +00001972 int pw0, ph0, strides[3], retval=-1, jpegSubsamp=-1;
DRCaecea382014-08-11 18:05:41 +00001973 int i, jpegwidth, jpegheight, scaledw, scaledh;
1974
1975 getdinstance(handle);
1976
1977 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
1978 || !isPow2(pad) || height<0)
1979 _throw("tjDecompressToYUV2(): Invalid argument");
1980
DRCdec79952016-04-20 11:27:42 -05001981 if(setjmp(this->jerr.setjmp_buffer))
1982 {
1983 /* If we get here, the JPEG code has signaled an error. */
1984 return -1;
1985 }
1986
DRCaecea382014-08-11 18:05:41 +00001987 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1988 jpeg_read_header(dinfo, TRUE);
1989 jpegSubsamp=getSubsamp(dinfo);
1990 if(jpegSubsamp<0)
1991 _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1992
1993 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
1994 if(width==0) width=jpegwidth;
1995 if(height==0) height=jpegheight;
1996
1997 for(i=0; i<NUMSF; i++)
1998 {
1999 scaledw=TJSCALED(jpegwidth, sf[i]);
2000 scaledh=TJSCALED(jpegheight, sf[i]);
2001 if(scaledw<=width && scaledh<=height)
2002 break;
2003 }
DRC58ae4012015-08-26 20:29:36 -05002004 if(i>=NUMSF)
DRCaecea382014-08-11 18:05:41 +00002005 _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
2006
DRC40dd3142014-08-17 12:23:49 +00002007 pw0=tjPlaneWidth(0, width, jpegSubsamp);
2008 ph0=tjPlaneHeight(0, height, jpegSubsamp);
DRCaecea382014-08-11 18:05:41 +00002009 dstPlanes[0]=dstBuf;
DRC40dd3142014-08-17 12:23:49 +00002010 strides[0]=PAD(pw0, pad);
2011 if(jpegSubsamp==TJSAMP_GRAY)
2012 {
2013 strides[1]=strides[2]=0;
2014 dstPlanes[1]=dstPlanes[2]=NULL;
2015 }
2016 else
2017 {
2018 int pw1=tjPlaneWidth(1, width, jpegSubsamp);
2019 int ph1=tjPlaneHeight(1, height, jpegSubsamp);
2020 strides[1]=strides[2]=PAD(pw1, pad);
2021 dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
2022 dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
2023 }
DRCaecea382014-08-11 18:05:41 +00002024
2025 this->headerRead=1;
2026 return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
2027 strides, height, flags);
2028
2029 bailout:
2030 return retval;
2031
2032}
2033
DRCf610d612013-04-26 10:33:29 +00002034DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
2035 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
2036 int flags)
2037{
2038 return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
2039}
2040
DRC2e7b76b2009-04-03 12:04:24 +00002041
DRC9b28def2011-05-21 14:37:15 +00002042/* Transformer */
DRC890f1e02011-02-26 22:02:37 +00002043
2044DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
2045{
DRC9b28def2011-05-21 14:37:15 +00002046 tjinstance *this=NULL; tjhandle handle=NULL;
2047 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
DRCda5220a2011-03-02 02:17:30 +00002048 {
DRC007a42c2011-05-22 13:55:56 +00002049 snprintf(errStr, JMSG_LENGTH_MAX,
2050 "tjInitTransform(): Memory allocation failure");
DRCda5220a2011-03-02 02:17:30 +00002051 return NULL;
2052 }
DRC007a42c2011-05-22 13:55:56 +00002053 MEMZERO(this, sizeof(tjinstance));
DRCb9ab64d2017-05-11 21:02:29 -05002054 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
DRC9b28def2011-05-21 14:37:15 +00002055 handle=_tjInitCompress(this);
2056 if(!handle) return NULL;
2057 handle=_tjInitDecompress(this);
2058 return handle;
DRC890f1e02011-02-26 22:02:37 +00002059}
2060
2061
DRC6fa14b32015-08-13 20:06:03 -05002062DLLEXPORT int DLLCALL tjTransform(tjhandle handle,
2063 const unsigned char *jpegBuf, unsigned long jpegSize, int n,
2064 unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *t, int flags)
DRC890f1e02011-02-26 22:02:37 +00002065{
DRC0a325192011-03-02 09:22:41 +00002066 jpeg_transform_info *xinfo=NULL;
DRC890f1e02011-02-26 22:02:37 +00002067 jvirt_barray_ptr *srccoefs, *dstcoefs;
DRC9b49f0e2011-07-12 03:17:23 +00002068 int retval=0, i, jpegSubsamp;
DRC890f1e02011-02-26 22:02:37 +00002069
DRC9b28def2011-05-21 14:37:15 +00002070 getinstance(handle);
2071 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
DRC007a42c2011-05-22 13:55:56 +00002072 _throw("tjTransform(): Instance has not been initialized for transformation");
DRC890f1e02011-02-26 22:02:37 +00002073
DRC9b28def2011-05-21 14:37:15 +00002074 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
2075 || t==NULL || flags<0)
2076 _throw("tjTransform(): Invalid argument");
2077
DRCbec45b12015-05-17 15:56:18 +00002078 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
2079 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
2080 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
DRC890f1e02011-02-26 22:02:37 +00002081
DRCd4c41fe2017-03-18 12:56:36 -05002082 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
2083 ==NULL)
2084 _throw("tjTransform(): Memory allocation failure");
2085 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
2086
DRC9b28def2011-05-21 14:37:15 +00002087 if(setjmp(this->jerr.setjmp_buffer))
2088 {
2089 /* If we get here, the JPEG code has signaled an error. */
DRC890f1e02011-02-26 22:02:37 +00002090 retval=-1;
2091 goto bailout;
2092 }
2093
DRC9b28def2011-05-21 14:37:15 +00002094 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
DRC890f1e02011-02-26 22:02:37 +00002095
DRC0a325192011-03-02 09:22:41 +00002096 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00002097 {
DRC0a325192011-03-02 09:22:41 +00002098 xinfo[i].transform=xformtypes[t[i].op];
DRC25b995a2011-05-21 15:34:54 +00002099 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
2100 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
2101 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
2102 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
2103 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
DRCba5ea512011-03-04 03:20:34 +00002104 else xinfo[i].slow_hflip=0;
DRC0a325192011-03-02 09:22:41 +00002105
2106 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00002107 {
DRC0a325192011-03-02 09:22:41 +00002108 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
2109 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
2110 if(t[i].r.w!=0)
2111 {
2112 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
2113 }
DRCd932e582011-03-15 20:09:47 +00002114 else xinfo[i].crop_width=JCROP_UNSET;
DRC0a325192011-03-02 09:22:41 +00002115 if(t[i].r.h!=0)
2116 {
2117 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
2118 }
DRCd932e582011-03-15 20:09:47 +00002119 else xinfo[i].crop_height=JCROP_UNSET;
DRC890f1e02011-02-26 22:02:37 +00002120 }
2121 }
2122
DRC9b28def2011-05-21 14:37:15 +00002123 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
2124 jpeg_read_header(dinfo, TRUE);
DRC9b49f0e2011-07-12 03:17:23 +00002125 jpegSubsamp=getSubsamp(dinfo);
2126 if(jpegSubsamp<0)
2127 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
DRC890f1e02011-02-26 22:02:37 +00002128
DRC0a325192011-03-02 09:22:41 +00002129 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +00002130 {
DRC9b28def2011-05-21 14:37:15 +00002131 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
DRC007a42c2011-05-22 13:55:56 +00002132 _throw("tjTransform(): Transform is not perfect");
DRC890f1e02011-02-26 22:02:37 +00002133
DRC0a325192011-03-02 09:22:41 +00002134 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +00002135 {
DRC0a325192011-03-02 09:22:41 +00002136 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
2137 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
2138 {
DRC9b28def2011-05-21 14:37:15 +00002139 snprintf(errStr, JMSG_LENGTH_MAX,
DRC0a325192011-03-02 09:22:41 +00002140 "To crop this JPEG image, x must be a multiple of %d\n"
2141 "and y must be a multiple of %d.\n",
2142 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
2143 retval=-1; goto bailout;
2144 }
DRC890f1e02011-02-26 22:02:37 +00002145 }
2146 }
2147
DRC9b28def2011-05-21 14:37:15 +00002148 srccoefs=jpeg_read_coefficients(dinfo);
DRC890f1e02011-02-26 22:02:37 +00002149
DRC0a325192011-03-02 09:22:41 +00002150 for(i=0; i<n; i++)
2151 {
DRCff78e372011-05-24 10:17:32 +00002152 int w, h, alloc=1;
DRC0a325192011-03-02 09:22:41 +00002153 if(!xinfo[i].crop)
2154 {
DRC9b28def2011-05-21 14:37:15 +00002155 w=dinfo->image_width; h=dinfo->image_height;
DRC0a325192011-03-02 09:22:41 +00002156 }
2157 else
2158 {
2159 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
2160 }
DRCff78e372011-05-24 10:17:32 +00002161 if(flags&TJFLAG_NOREALLOC)
2162 {
DRC9b49f0e2011-07-12 03:17:23 +00002163 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
DRCff78e372011-05-24 10:17:32 +00002164 }
DRC7bf04d32011-09-17 00:18:31 +00002165 if(!(t[i].options&TJXOPT_NOOUTPUT))
2166 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
DRC9b28def2011-05-21 14:37:15 +00002167 jpeg_copy_critical_parameters(dinfo, cinfo);
2168 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00002169 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00002170 if(!(t[i].options&TJXOPT_NOOUTPUT))
2171 {
2172 jpeg_write_coefficients(cinfo, dstcoefs);
2173 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
2174 }
2175 else jinit_c_master_control(cinfo, TRUE);
DRC9b28def2011-05-21 14:37:15 +00002176 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
DRC0a325192011-03-02 09:22:41 +00002177 &xinfo[i]);
DRC7bf04d32011-09-17 00:18:31 +00002178 if(t[i].customFilter)
2179 {
DRCefe28ce2012-01-17 11:48:38 +00002180 int ci, y; JDIMENSION by;
DRC7bf04d32011-09-17 00:18:31 +00002181 for(ci=0; ci<cinfo->num_components; ci++)
2182 {
2183 jpeg_component_info *compptr=&cinfo->comp_info[ci];
2184 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2185 DCTSIZE};
2186 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2187 compptr->height_in_blocks*DCTSIZE};
2188 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
2189 {
2190 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
2191 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
2192 TRUE);
2193 for(y=0; y<compptr->v_samp_factor; y++)
2194 {
2195 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
DRCf5467112011-09-20 05:02:19 +00002196 ci, i, &t[i])==-1)
DRC7bf04d32011-09-17 00:18:31 +00002197 _throw("tjTransform(): Error in custom filter");
2198 arrayRegion.y+=DCTSIZE;
2199 }
2200 }
2201 }
2202 }
2203 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
DRC0a325192011-03-02 09:22:41 +00002204 }
2205
DRC9b28def2011-05-21 14:37:15 +00002206 jpeg_finish_decompress(dinfo);
DRC890f1e02011-02-26 22:02:37 +00002207
DRC890f1e02011-02-26 22:02:37 +00002208 bailout:
DRC9b28def2011-05-21 14:37:15 +00002209 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
2210 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
DRC0a325192011-03-02 09:22:41 +00002211 if(xinfo) free(xinfo);
DRC1f79c7c2015-06-01 19:22:41 +00002212 if(this->jerr.warning) retval=-1;
DRC890f1e02011-02-26 22:02:37 +00002213 return retval;
2214}