1 /*
2 * Copyright (C)2009-2019 D. R. Commander. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * - 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.
27 */
28
29 /* TurboJPEG/LJT: this implements the TurboJPEG API using libjpeg or
30 libjpeg-turbo */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <jinclude.h>
36 #define JPEG_INTERNALS
37 #include <jpeglib.h>
38 #include <jerror.h>
39 #include <setjmp.h>
40 #include <errno.h>
41 #include "./turbojpeg.h"
42 #include "./tjutil.h"
43 #include "transupp.h"
44 #include "./jpegcomp.h"
45 #include "./cdjpeg.h"
46
47 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, unsigned long *,
48 boolean);
49 extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
50 unsigned long);
51
52 #define PAD(v, p) ((v + (p) - 1) & (~((p) - 1)))
53 #define isPow2(x) (((x) & (x - 1)) == 0)
54
55
56 /* Error handling (based on example in example.txt) */
57
58 static char errStr[JMSG_LENGTH_MAX] = "No error";
59
60 struct my_error_mgr {
61 struct jpeg_error_mgr pub;
62 jmp_buf setjmp_buffer;
63 void (*emit_message) (j_common_ptr, int);
64 boolean warning, stopOnWarning;
65 };
66 typedef struct my_error_mgr *my_error_ptr;
67
68 #define JMESSAGE(code, string) string,
69 static const char *turbojpeg_message_table[] = {
70 #include "cderror.h"
71 NULL
72 };
73
my_error_exit(j_common_ptr cinfo)74 static void my_error_exit(j_common_ptr cinfo)
75 {
76 my_error_ptr myerr = (my_error_ptr)cinfo->err;
77
78 (*cinfo->err->output_message) (cinfo);
79 longjmp(myerr->setjmp_buffer, 1);
80 }
81
82 /* Based on output_message() in jerror.c */
83
my_output_message(j_common_ptr cinfo)84 static void my_output_message(j_common_ptr cinfo)
85 {
86 (*cinfo->err->format_message) (cinfo, errStr);
87 }
88
my_emit_message(j_common_ptr cinfo,int msg_level)89 static void my_emit_message(j_common_ptr cinfo, int msg_level)
90 {
91 my_error_ptr myerr = (my_error_ptr)cinfo->err;
92
93 myerr->emit_message(cinfo, msg_level);
94 if (msg_level < 0) {
95 myerr->warning = TRUE;
96 if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
97 }
98 }
99
100
101 /* Global structures, macros, etc. */
102
103 enum { COMPRESS = 1, DECOMPRESS = 2 };
104
105 typedef struct _tjinstance {
106 struct jpeg_compress_struct cinfo;
107 struct jpeg_decompress_struct dinfo;
108 struct my_error_mgr jerr;
109 int init, headerRead;
110 char errStr[JMSG_LENGTH_MAX];
111 boolean isInstanceError;
112 } tjinstance;
113
114 static const int pixelsize[TJ_NUMSAMP] = { 3, 3, 3, 1, 3, 3 };
115
116 static const JXFORM_CODE xformtypes[TJ_NUMXOP] = {
117 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
118 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
119 };
120
121 #define NUMSF 16
122 static const tjscalingfactor sf[NUMSF] = {
123 { 2, 1 },
124 { 15, 8 },
125 { 7, 4 },
126 { 13, 8 },
127 { 3, 2 },
128 { 11, 8 },
129 { 5, 4 },
130 { 9, 8 },
131 { 1, 1 },
132 { 7, 8 },
133 { 3, 4 },
134 { 5, 8 },
135 { 1, 2 },
136 { 3, 8 },
137 { 1, 4 },
138 { 1, 8 }
139 };
140
141 static J_COLOR_SPACE pf2cs[TJ_NUMPF] = {
142 JCS_EXT_RGB, JCS_EXT_BGR, JCS_EXT_RGBX, JCS_EXT_BGRX, JCS_EXT_XBGR,
143 JCS_EXT_XRGB, JCS_GRAYSCALE, JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ABGR,
144 JCS_EXT_ARGB, JCS_CMYK
145 };
146
147 static int cs2pf[JPEG_NUMCS] = {
148 TJPF_UNKNOWN, TJPF_GRAY,
149 #if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
150 TJPF_RGB,
151 #elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 3
152 TJPF_BGR,
153 #elif RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 4
154 TJPF_RGBX,
155 #elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 4
156 TJPF_BGRX,
157 #elif RGB_RED == 3 && RGB_GREEN == 2 && RGB_BLUE == 1 && RGB_PIXELSIZE == 4
158 TJPF_XBGR,
159 #elif RGB_RED == 1 && RGB_GREEN == 2 && RGB_BLUE == 3 && RGB_PIXELSIZE == 4
160 TJPF_XRGB,
161 #endif
162 TJPF_UNKNOWN, TJPF_CMYK, TJPF_UNKNOWN, TJPF_RGB, TJPF_RGBX, TJPF_BGR,
163 TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_RGBA, TJPF_BGRA, TJPF_ABGR, TJPF_ARGB,
164 TJPF_UNKNOWN
165 };
166
167 #define _throwg(m) { \
168 snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
169 retval = -1; goto bailout; \
170 }
171 #define _throwunix(m) { \
172 snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerror(errno)); \
173 retval = -1; goto bailout; \
174 }
175 #define _throw(m) { \
176 snprintf(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
177 this->isInstanceError = TRUE; _throwg(m) \
178 }
179
180 #define getinstance(handle) \
181 tjinstance *this = (tjinstance *)handle; \
182 j_compress_ptr cinfo = NULL; \
183 j_decompress_ptr dinfo = NULL; \
184 \
185 if (!this) { \
186 snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
187 return -1; \
188 } \
189 cinfo = &this->cinfo; dinfo = &this->dinfo; \
190 this->jerr.warning = FALSE; \
191 this->isInstanceError = FALSE;
192
193 #define getcinstance(handle) \
194 tjinstance *this = (tjinstance *)handle; \
195 j_compress_ptr cinfo = NULL; \
196 \
197 if (!this) { \
198 snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
199 return -1; \
200 } \
201 cinfo = &this->cinfo; \
202 this->jerr.warning = FALSE; \
203 this->isInstanceError = FALSE;
204
205 #define getdinstance(handle) \
206 tjinstance *this = (tjinstance *)handle; \
207 j_decompress_ptr dinfo = NULL; \
208 \
209 if (!this) { \
210 snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
211 return -1; \
212 } \
213 dinfo = &this->dinfo; \
214 this->jerr.warning = FALSE; \
215 this->isInstanceError = FALSE;
216
getPixelFormat(int pixelSize,int flags)217 static int getPixelFormat(int pixelSize, int flags)
218 {
219 if (pixelSize == 1) return TJPF_GRAY;
220 if (pixelSize == 3) {
221 if (flags & TJ_BGR) return TJPF_BGR;
222 else return TJPF_RGB;
223 }
224 if (pixelSize == 4) {
225 if (flags & TJ_ALPHAFIRST) {
226 if (flags & TJ_BGR) return TJPF_XBGR;
227 else return TJPF_XRGB;
228 } else {
229 if (flags & TJ_BGR) return TJPF_BGRX;
230 else return TJPF_RGBX;
231 }
232 }
233 return -1;
234 }
235
setCompDefaults(struct jpeg_compress_struct * cinfo,int pixelFormat,int subsamp,int jpegQual,int flags)236 static int setCompDefaults(struct jpeg_compress_struct *cinfo, int pixelFormat,
237 int subsamp, int jpegQual, int flags)
238 {
239 int retval = 0;
240 char *env = NULL;
241
242 cinfo->in_color_space = pf2cs[pixelFormat];
243 cinfo->input_components = tjPixelSize[pixelFormat];
244 jpeg_set_defaults(cinfo);
245
246 #ifndef NO_GETENV
247 if ((env = getenv("TJ_OPTIMIZE")) != NULL && strlen(env) > 0 &&
248 !strcmp(env, "1"))
249 cinfo->optimize_coding = TRUE;
250 if ((env = getenv("TJ_ARITHMETIC")) != NULL && strlen(env) > 0 &&
251 !strcmp(env, "1"))
252 cinfo->arith_code = TRUE;
253 if ((env = getenv("TJ_RESTART")) != NULL && strlen(env) > 0) {
254 int temp = -1;
255 char tempc = 0;
256
257 if (sscanf(env, "%d%c", &temp, &tempc) >= 1 && temp >= 0 &&
258 temp <= 65535) {
259 if (toupper(tempc) == 'B') {
260 cinfo->restart_interval = temp;
261 cinfo->restart_in_rows = 0;
262 } else
263 cinfo->restart_in_rows = temp;
264 }
265 }
266 #endif
267
268 if (jpegQual >= 0) {
269 jpeg_set_quality(cinfo, jpegQual, TRUE);
270 if (jpegQual >= 96 || flags & TJFLAG_ACCURATEDCT)
271 cinfo->dct_method = JDCT_ISLOW;
272 else
273 cinfo->dct_method = JDCT_FASTEST;
274 }
275 if (subsamp == TJSAMP_GRAY)
276 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
277 else if (pixelFormat == TJPF_CMYK)
278 jpeg_set_colorspace(cinfo, JCS_YCCK);
279 else
280 jpeg_set_colorspace(cinfo, JCS_YCbCr);
281
282 if (flags & TJFLAG_PROGRESSIVE)
283 jpeg_simple_progression(cinfo);
284 #ifndef NO_GETENV
285 else if ((env = getenv("TJ_PROGRESSIVE")) != NULL && strlen(env) > 0 &&
286 !strcmp(env, "1"))
287 jpeg_simple_progression(cinfo);
288 #endif
289
290 cinfo->comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
291 cinfo->comp_info[1].h_samp_factor = 1;
292 cinfo->comp_info[2].h_samp_factor = 1;
293 if (cinfo->num_components > 3)
294 cinfo->comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8;
295 cinfo->comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8;
296 cinfo->comp_info[1].v_samp_factor = 1;
297 cinfo->comp_info[2].v_samp_factor = 1;
298 if (cinfo->num_components > 3)
299 cinfo->comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8;
300
301 return retval;
302 }
303
304
getSubsamp(j_decompress_ptr dinfo)305 static int getSubsamp(j_decompress_ptr dinfo)
306 {
307 int retval = -1, i, k;
308
309 /* The sampling factors actually have no meaning with grayscale JPEG files,
310 and in fact it's possible to generate grayscale JPEGs with sampling
311 factors > 1 (even though those sampling factors are ignored by the
312 decompressor.) Thus, we need to treat grayscale as a special case. */
313 if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
314 return TJSAMP_GRAY;
315
316 for (i = 0; i < NUMSUBOPT; i++) {
317 if (dinfo->num_components == pixelsize[i] ||
318 ((dinfo->jpeg_color_space == JCS_YCCK ||
319 dinfo->jpeg_color_space == JCS_CMYK) &&
320 pixelsize[i] == 3 && dinfo->num_components == 4)) {
321 if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
322 dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
323 int match = 0;
324
325 for (k = 1; k < dinfo->num_components; k++) {
326 int href = 1, vref = 1;
327
328 if ((dinfo->jpeg_color_space == JCS_YCCK ||
329 dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
330 href = tjMCUWidth[i] / 8; vref = tjMCUHeight[i] / 8;
331 }
332 if (dinfo->comp_info[k].h_samp_factor == href &&
333 dinfo->comp_info[k].v_samp_factor == vref)
334 match++;
335 }
336 if (match == dinfo->num_components - 1) {
337 retval = i; break;
338 }
339 }
340 /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
341 in non-standard ways. */
342 if (dinfo->comp_info[0].h_samp_factor == 2 &&
343 dinfo->comp_info[0].v_samp_factor == 2 &&
344 (i == TJSAMP_422 || i == TJSAMP_440)) {
345 int match = 0;
346
347 for (k = 1; k < dinfo->num_components; k++) {
348 int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
349
350 if ((dinfo->jpeg_color_space == JCS_YCCK ||
351 dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
352 href = vref = 2;
353 }
354 if (dinfo->comp_info[k].h_samp_factor == href &&
355 dinfo->comp_info[k].v_samp_factor == vref)
356 match++;
357 }
358 if (match == dinfo->num_components - 1) {
359 retval = i; break;
360 }
361 }
362 /* Handle 4:4:4 images whose sampling factors are specified in
363 non-standard ways. */
364 if (dinfo->comp_info[0].h_samp_factor *
365 dinfo->comp_info[0].v_samp_factor <=
366 D_MAX_BLOCKS_IN_MCU / pixelsize[i] && i == TJSAMP_444) {
367 int match = 0;
368 for (k = 1; k < dinfo->num_components; k++) {
369 if (dinfo->comp_info[i].h_samp_factor ==
370 dinfo->comp_info[0].h_samp_factor &&
371 dinfo->comp_info[i].v_samp_factor ==
372 dinfo->comp_info[0].v_samp_factor)
373 match++;
374 if (match == dinfo->num_components - 1) {
375 retval = i; break;
376 }
377 }
378 }
379 }
380 }
381 return retval;
382 }
383
384
385 /* General API functions */
386
tjGetErrorStr2(tjhandle handle)387 DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
388 {
389 tjinstance *this = (tjinstance *)handle;
390
391 if (this && this->isInstanceError) {
392 this->isInstanceError = FALSE;
393 return this->errStr;
394 } else
395 return errStr;
396 }
397
398
tjGetErrorStr(void)399 DLLEXPORT char *tjGetErrorStr(void)
400 {
401 return errStr;
402 }
403
404
tjGetErrorCode(tjhandle handle)405 DLLEXPORT int tjGetErrorCode(tjhandle handle)
406 {
407 tjinstance *this = (tjinstance *)handle;
408
409 if (this && this->jerr.warning) return TJERR_WARNING;
410 else return TJERR_FATAL;
411 }
412
413
tjDestroy(tjhandle handle)414 DLLEXPORT int tjDestroy(tjhandle handle)
415 {
416 getinstance(handle);
417
418 if (setjmp(this->jerr.setjmp_buffer)) return -1;
419 if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
420 if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
421 free(this);
422 return 0;
423 }
424
425
426 /* These are exposed mainly because Windows can't malloc() and free() across
427 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
428 with turbojpeg.dll for compatibility reasons. However, these functions
429 can potentially be used for other purposes by different implementations. */
430
tjFree(unsigned char * buf)431 DLLEXPORT void tjFree(unsigned char *buf)
432 {
433 if (buf) free(buf);
434 }
435
436
tjAlloc(int bytes)437 DLLEXPORT unsigned char *tjAlloc(int bytes)
438 {
439 return (unsigned char *)malloc(bytes);
440 }
441
442
443 /* Compressor */
444
_tjInitCompress(tjinstance * this)445 static tjhandle _tjInitCompress(tjinstance *this)
446 {
447 static unsigned char buffer[1];
448 unsigned char *buf = buffer;
449 unsigned long size = 1;
450
451 /* This is also straight out of example.txt */
452 this->cinfo.err = jpeg_std_error(&this->jerr.pub);
453 this->jerr.pub.error_exit = my_error_exit;
454 this->jerr.pub.output_message = my_output_message;
455 this->jerr.emit_message = this->jerr.pub.emit_message;
456 this->jerr.pub.emit_message = my_emit_message;
457 this->jerr.pub.addon_message_table = turbojpeg_message_table;
458 this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
459 this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
460
461 if (setjmp(this->jerr.setjmp_buffer)) {
462 /* If we get here, the JPEG code has signaled an error. */
463 if (this) free(this);
464 return NULL;
465 }
466
467 jpeg_create_compress(&this->cinfo);
468 /* Make an initial call so it will create the destination manager */
469 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
470
471 this->init |= COMPRESS;
472 return (tjhandle)this;
473 }
474
tjInitCompress(void)475 DLLEXPORT tjhandle tjInitCompress(void)
476 {
477 tjinstance *this = NULL;
478
479 if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
480 snprintf(errStr, JMSG_LENGTH_MAX,
481 "tjInitCompress(): Memory allocation failure");
482 return NULL;
483 }
484 MEMZERO(this, sizeof(tjinstance));
485 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
486 return _tjInitCompress(this);
487 }
488
489
tjBufSize(int width,int height,int jpegSubsamp)490 DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
491 {
492 unsigned long retval = 0;
493 int mcuw, mcuh, chromasf;
494
495 if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT)
496 _throwg("tjBufSize(): Invalid argument");
497
498 /* This allows for rare corner cases in which a JPEG image can actually be
499 larger than the uncompressed input (we wouldn't mention it if it hadn't
500 happened before.) */
501 mcuw = tjMCUWidth[jpegSubsamp];
502 mcuh = tjMCUHeight[jpegSubsamp];
503 chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
504 retval = PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
505
506 bailout:
507 return retval;
508 }
509
TJBUFSIZE(int width,int height)510 DLLEXPORT unsigned long TJBUFSIZE(int width, int height)
511 {
512 unsigned long retval = 0;
513
514 if (width < 1 || height < 1)
515 _throwg("TJBUFSIZE(): Invalid argument");
516
517 /* This allows for rare corner cases in which a JPEG image can actually be
518 larger than the uncompressed input (we wouldn't mention it if it hadn't
519 happened before.) */
520 retval = PAD(width, 16) * PAD(height, 16) * 6 + 2048;
521
522 bailout:
523 return retval;
524 }
525
526
tjBufSizeYUV2(int width,int pad,int height,int subsamp)527 DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height,
528 int subsamp)
529 {
530 int retval = 0, nc, i;
531
532 if (subsamp < 0 || subsamp >= NUMSUBOPT)
533 _throwg("tjBufSizeYUV2(): Invalid argument");
534
535 nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
536 for (i = 0; i < nc; i++) {
537 int pw = tjPlaneWidth(i, width, subsamp);
538 int stride = PAD(pw, pad);
539 int ph = tjPlaneHeight(i, height, subsamp);
540
541 if (pw < 0 || ph < 0) return -1;
542 else retval += stride * ph;
543 }
544
545 bailout:
546 return retval;
547 }
548
tjBufSizeYUV(int width,int height,int subsamp)549 DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp)
550 {
551 return tjBufSizeYUV2(width, 4, height, subsamp);
552 }
553
TJBUFSIZEYUV(int width,int height,int subsamp)554 DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
555 {
556 return tjBufSizeYUV(width, height, subsamp);
557 }
558
559
tjPlaneWidth(int componentID,int width,int subsamp)560 DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
561 {
562 int pw, nc, retval = 0;
563
564 if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
565 _throwg("tjPlaneWidth(): Invalid argument");
566 nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
567 if (componentID < 0 || componentID >= nc)
568 _throwg("tjPlaneWidth(): Invalid argument");
569
570 pw = PAD(width, tjMCUWidth[subsamp] / 8);
571 if (componentID == 0)
572 retval = pw;
573 else
574 retval = pw * 8 / tjMCUWidth[subsamp];
575
576 bailout:
577 return retval;
578 }
579
580
tjPlaneHeight(int componentID,int height,int subsamp)581 DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
582 {
583 int ph, nc, retval = 0;
584
585 if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
586 _throwg("tjPlaneHeight(): Invalid argument");
587 nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
588 if (componentID < 0 || componentID >= nc)
589 _throwg("tjPlaneHeight(): Invalid argument");
590
591 ph = PAD(height, tjMCUHeight[subsamp] / 8);
592 if (componentID == 0)
593 retval = ph;
594 else
595 retval = ph * 8 / tjMCUHeight[subsamp];
596
597 bailout:
598 return retval;
599 }
600
601
tjPlaneSizeYUV(int componentID,int width,int stride,int height,int subsamp)602 DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
603 int height, int subsamp)
604 {
605 unsigned long retval = 0;
606 int pw, ph;
607
608 if (width < 1 || height < 1 || subsamp < 0 || subsamp >= NUMSUBOPT)
609 _throwg("tjPlaneSizeYUV(): Invalid argument");
610
611 pw = tjPlaneWidth(componentID, width, subsamp);
612 ph = tjPlaneHeight(componentID, height, subsamp);
613 if (pw < 0 || ph < 0) return -1;
614
615 if (stride == 0) stride = pw;
616 else stride = abs(stride);
617
618 retval = stride * (ph - 1) + pw;
619
620 bailout:
621 return retval;
622 }
623
624
tjCompress2(tjhandle handle,const unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char ** jpegBuf,unsigned long * jpegSize,int jpegSubsamp,int jpegQual,int flags)625 DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
626 int width, int pitch, int height, int pixelFormat,
627 unsigned char **jpegBuf, unsigned long *jpegSize,
628 int jpegSubsamp, int jpegQual, int flags)
629 {
630 int i, retval = 0, alloc = 1;
631 JSAMPROW *row_pointer = NULL;
632
633 getcinstance(handle)
634 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
635 if ((this->init & COMPRESS) == 0)
636 _throw("tjCompress2(): Instance has not been initialized for compression");
637
638 if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
639 pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
640 jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT ||
641 jpegQual < 0 || jpegQual > 100)
642 _throw("tjCompress2(): Invalid argument");
643
644 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
645
646 if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * height)) == NULL)
647 _throw("tjCompress2(): Memory allocation failure");
648
649 if (setjmp(this->jerr.setjmp_buffer)) {
650 /* If we get here, the JPEG code has signaled an error. */
651 retval = -1; goto bailout;
652 }
653
654 cinfo->image_width = width;
655 cinfo->image_height = height;
656
657 #ifndef NO_PUTENV
658 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
659 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
660 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
661 #endif
662
663 if (flags & TJFLAG_NOREALLOC) {
664 alloc = 0; *jpegSize = tjBufSize(width, height, jpegSubsamp);
665 }
666 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
667 if (setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags) == -1)
668 return -1;
669
670 jpeg_start_compress(cinfo, TRUE);
671 for (i = 0; i < height; i++) {
672 if (flags & TJFLAG_BOTTOMUP)
673 row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * pitch];
674 else
675 row_pointer[i] = (JSAMPROW)&srcBuf[i * pitch];
676 }
677 while (cinfo->next_scanline < cinfo->image_height)
678 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
679 cinfo->image_height - cinfo->next_scanline);
680 jpeg_finish_compress(cinfo);
681
682 bailout:
683 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
684 if (row_pointer) free(row_pointer);
685 if (this->jerr.warning) retval = -1;
686 this->jerr.stopOnWarning = FALSE;
687 return retval;
688 }
689
tjCompress(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelSize,unsigned char * jpegBuf,unsigned long * jpegSize,int jpegSubsamp,int jpegQual,int flags)690 DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
691 int pitch, int height, int pixelSize,
692 unsigned char *jpegBuf, unsigned long *jpegSize,
693 int jpegSubsamp, int jpegQual, int flags)
694 {
695 int retval = 0;
696 unsigned long size;
697
698 if (flags & TJ_YUV) {
699 size = tjBufSizeYUV(width, height, jpegSubsamp);
700 retval = tjEncodeYUV2(handle, srcBuf, width, pitch, height,
701 getPixelFormat(pixelSize, flags), jpegBuf,
702 jpegSubsamp, flags);
703 } else {
704 retval = tjCompress2(handle, srcBuf, width, pitch, height,
705 getPixelFormat(pixelSize, flags), &jpegBuf, &size,
706 jpegSubsamp, jpegQual, flags | TJFLAG_NOREALLOC);
707 }
708 *jpegSize = size;
709 return retval;
710 }
711
712
tjEncodeYUVPlanes(tjhandle handle,const unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char ** dstPlanes,int * strides,int subsamp,int flags)713 DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
714 int width, int pitch, int height,
715 int pixelFormat, unsigned char **dstPlanes,
716 int *strides, int subsamp, int flags)
717 {
718 JSAMPROW *row_pointer = NULL;
719 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
720 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
721 JSAMPROW *outbuf[MAX_COMPONENTS];
722 int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
723 JSAMPLE *ptr;
724 jpeg_component_info *compptr;
725
726 getcinstance(handle);
727 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
728
729 for (i = 0; i < MAX_COMPONENTS; i++) {
730 tmpbuf[i] = NULL; _tmpbuf[i] = NULL;
731 tmpbuf2[i] = NULL; _tmpbuf2[i] = NULL; outbuf[i] = NULL;
732 }
733
734 if ((this->init & COMPRESS) == 0)
735 _throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
736
737 if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
738 pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
739 !dstPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT)
740 _throw("tjEncodeYUVPlanes(): Invalid argument");
741 if (subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
742 _throw("tjEncodeYUVPlanes(): Invalid argument");
743
744 if (pixelFormat == TJPF_CMYK)
745 _throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
746
747 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
748
749 if (setjmp(this->jerr.setjmp_buffer)) {
750 /* If we get here, the JPEG code has signaled an error. */
751 retval = -1; goto bailout;
752 }
753
754 cinfo->image_width = width;
755 cinfo->image_height = height;
756
757 #ifndef NO_PUTENV
758 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
759 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
760 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
761 #endif
762
763 if (setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags) == -1) return -1;
764
765 /* Execute only the parts of jpeg_start_compress() that we need. If we
766 were to call the whole jpeg_start_compress() function, then it would try
767 to write the file headers, which could overflow the output buffer if the
768 YUV image were very small. */
769 if (cinfo->global_state != CSTATE_START)
770 _throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
771 (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
772 jinit_c_master_control(cinfo, FALSE);
773 jinit_color_converter(cinfo);
774 jinit_downsampler(cinfo);
775 (*cinfo->cconvert->start_pass) (cinfo);
776
777 pw0 = PAD(width, cinfo->max_h_samp_factor);
778 ph0 = PAD(height, cinfo->max_v_samp_factor);
779
780 if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
781 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
782 for (i = 0; i < height; i++) {
783 if (flags & TJFLAG_BOTTOMUP)
784 row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * pitch];
785 else
786 row_pointer[i] = (JSAMPROW)&srcBuf[i * pitch];
787 }
788 if (height < ph0)
789 for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
790
791 for (i = 0; i < cinfo->num_components; i++) {
792 compptr = &cinfo->comp_info[i];
793 _tmpbuf[i] = (JSAMPLE *)malloc(
794 PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
795 compptr->h_samp_factor, 32) *
796 cinfo->max_v_samp_factor + 32);
797 if (!_tmpbuf[i])
798 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
799 tmpbuf[i] =
800 (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
801 if (!tmpbuf[i])
802 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
803 for (row = 0; row < cinfo->max_v_samp_factor; row++) {
804 unsigned char *_tmpbuf_aligned =
805 (unsigned char *)PAD((size_t)_tmpbuf[i], 32);
806
807 tmpbuf[i][row] = &_tmpbuf_aligned[
808 PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
809 compptr->h_samp_factor, 32) * row];
810 }
811 _tmpbuf2[i] =
812 (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
813 compptr->v_samp_factor + 32);
814 if (!_tmpbuf2[i])
815 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
816 tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
817 if (!tmpbuf2[i])
818 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
819 for (row = 0; row < compptr->v_samp_factor; row++) {
820 unsigned char *_tmpbuf2_aligned =
821 (unsigned char *)PAD((size_t)_tmpbuf2[i], 32);
822
823 tmpbuf2[i][row] =
824 &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
825 }
826 pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
827 ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
828 outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
829 if (!outbuf[i])
830 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
831 ptr = dstPlanes[i];
832 for (row = 0; row < ph[i]; row++) {
833 outbuf[i][row] = ptr;
834 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
835 }
836 }
837
838 if (setjmp(this->jerr.setjmp_buffer)) {
839 /* If we get here, the JPEG code has signaled an error. */
840 retval = -1; goto bailout;
841 }
842
843 for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
844 (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
845 cinfo->max_v_samp_factor);
846 (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
847 for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
848 i++, compptr++)
849 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
850 row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
851 compptr->v_samp_factor, pw[i]);
852 }
853 cinfo->next_scanline += height;
854 jpeg_abort_compress(cinfo);
855
856 bailout:
857 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
858 if (row_pointer) free(row_pointer);
859 for (i = 0; i < MAX_COMPONENTS; i++) {
860 if (tmpbuf[i] != NULL) free(tmpbuf[i]);
861 if (_tmpbuf[i] != NULL) free(_tmpbuf[i]);
862 if (tmpbuf2[i] != NULL) free(tmpbuf2[i]);
863 if (_tmpbuf2[i] != NULL) free(_tmpbuf2[i]);
864 if (outbuf[i] != NULL) free(outbuf[i]);
865 }
866 if (this->jerr.warning) retval = -1;
867 this->jerr.stopOnWarning = FALSE;
868 return retval;
869 }
870
tjEncodeYUV3(tjhandle handle,const unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char * dstBuf,int pad,int subsamp,int flags)871 DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
872 int width, int pitch, int height, int pixelFormat,
873 unsigned char *dstBuf, int pad, int subsamp,
874 int flags)
875 {
876 unsigned char *dstPlanes[3];
877 int pw0, ph0, strides[3], retval = -1;
878 tjinstance *this = (tjinstance *)handle;
879
880 if (!this) _throwg("tjEncodeYUV3(): Invalid handle");
881 this->isInstanceError = FALSE;
882
883 if (width <= 0 || height <= 0 || dstBuf == NULL || pad < 0 || !isPow2(pad) ||
884 subsamp < 0 || subsamp >= NUMSUBOPT)
885 _throw("tjEncodeYUV3(): Invalid argument");
886
887 pw0 = tjPlaneWidth(0, width, subsamp);
888 ph0 = tjPlaneHeight(0, height, subsamp);
889 dstPlanes[0] = dstBuf;
890 strides[0] = PAD(pw0, pad);
891 if (subsamp == TJSAMP_GRAY) {
892 strides[1] = strides[2] = 0;
893 dstPlanes[1] = dstPlanes[2] = NULL;
894 } else {
895 int pw1 = tjPlaneWidth(1, width, subsamp);
896 int ph1 = tjPlaneHeight(1, height, subsamp);
897
898 strides[1] = strides[2] = PAD(pw1, pad);
899 dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
900 dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
901 }
902
903 return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
904 dstPlanes, strides, subsamp, flags);
905
906 bailout:
907 return retval;
908 }
909
tjEncodeYUV2(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char * dstBuf,int subsamp,int flags)910 DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
911 int pitch, int height, int pixelFormat,
912 unsigned char *dstBuf, int subsamp, int flags)
913 {
914 return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
915 dstBuf, 4, subsamp, flags);
916 }
917
tjEncodeYUV(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelSize,unsigned char * dstBuf,int subsamp,int flags)918 DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
919 int pitch, int height, int pixelSize,
920 unsigned char *dstBuf, int subsamp, int flags)
921 {
922 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
923 getPixelFormat(pixelSize, flags), dstBuf, subsamp,
924 flags);
925 }
926
927
tjCompressFromYUVPlanes(tjhandle handle,const unsigned char ** srcPlanes,int width,const int * strides,int height,int subsamp,unsigned char ** jpegBuf,unsigned long * jpegSize,int jpegQual,int flags)928 DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
929 const unsigned char **srcPlanes,
930 int width, const int *strides,
931 int height, int subsamp,
932 unsigned char **jpegBuf,
933 unsigned long *jpegSize, int jpegQual,
934 int flags)
935 {
936 int i, row, retval = 0, alloc = 1;
937 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
938 tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
939 JSAMPLE *_tmpbuf = NULL, *ptr;
940 JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
941
942 getcinstance(handle)
943 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
944
945 for (i = 0; i < MAX_COMPONENTS; i++) {
946 tmpbuf[i] = NULL; inbuf[i] = NULL;
947 }
948
949 if ((this->init & COMPRESS) == 0)
950 _throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
951
952 if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
953 subsamp < 0 || subsamp >= NUMSUBOPT || jpegBuf == NULL ||
954 jpegSize == NULL || jpegQual < 0 || jpegQual > 100)
955 _throw("tjCompressFromYUVPlanes(): Invalid argument");
956 if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
957 _throw("tjCompressFromYUVPlanes(): Invalid argument");
958
959 if (setjmp(this->jerr.setjmp_buffer)) {
960 /* If we get here, the JPEG code has signaled an error. */
961 retval = -1; goto bailout;
962 }
963
964 cinfo->image_width = width;
965 cinfo->image_height = height;
966
967 #ifndef NO_PUTENV
968 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
969 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
970 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
971 #endif
972
973 if (flags & TJFLAG_NOREALLOC) {
974 alloc = 0; *jpegSize = tjBufSize(width, height, subsamp);
975 }
976 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
977 if (setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags) == -1)
978 return -1;
979 cinfo->raw_data_in = TRUE;
980
981 jpeg_start_compress(cinfo, TRUE);
982 for (i = 0; i < cinfo->num_components; i++) {
983 jpeg_component_info *compptr = &cinfo->comp_info[i];
984 int ih;
985
986 iw[i] = compptr->width_in_blocks * DCTSIZE;
987 ih = compptr->height_in_blocks * DCTSIZE;
988 pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
989 compptr->h_samp_factor / cinfo->max_h_samp_factor;
990 ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
991 compptr->v_samp_factor / cinfo->max_v_samp_factor;
992 if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
993 th[i] = compptr->v_samp_factor * DCTSIZE;
994 tmpbufsize += iw[i] * th[i];
995 if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
996 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
997 ptr = (JSAMPLE *)srcPlanes[i];
998 for (row = 0; row < ph[i]; row++) {
999 inbuf[i][row] = ptr;
1000 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1001 }
1002 }
1003 if (usetmpbuf) {
1004 if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1005 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1006 ptr = _tmpbuf;
1007 for (i = 0; i < cinfo->num_components; i++) {
1008 if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1009 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1010 for (row = 0; row < th[i]; row++) {
1011 tmpbuf[i][row] = ptr;
1012 ptr += iw[i];
1013 }
1014 }
1015 }
1016
1017 if (setjmp(this->jerr.setjmp_buffer)) {
1018 /* If we get here, the JPEG code has signaled an error. */
1019 retval = -1; goto bailout;
1020 }
1021
1022 for (row = 0; row < (int)cinfo->image_height;
1023 row += cinfo->max_v_samp_factor * DCTSIZE) {
1024 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1025 int crow[MAX_COMPONENTS];
1026
1027 for (i = 0; i < cinfo->num_components; i++) {
1028 jpeg_component_info *compptr = &cinfo->comp_info[i];
1029
1030 crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1031 if (usetmpbuf) {
1032 int j, k;
1033
1034 for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1035 memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1036 /* Duplicate last sample in row to fill out MCU */
1037 for (k = pw[i]; k < iw[i]; k++)
1038 tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1039 }
1040 /* Duplicate last row to fill out MCU */
1041 for (j = ph[i] - crow[i]; j < th[i]; j++)
1042 memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1043 yuvptr[i] = tmpbuf[i];
1044 } else
1045 yuvptr[i] = &inbuf[i][crow[i]];
1046 }
1047 jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1048 }
1049 jpeg_finish_compress(cinfo);
1050
1051 bailout:
1052 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1053 for (i = 0; i < MAX_COMPONENTS; i++) {
1054 if (tmpbuf[i]) free(tmpbuf[i]);
1055 if (inbuf[i]) free(inbuf[i]);
1056 }
1057 if (_tmpbuf) free(_tmpbuf);
1058 if (this->jerr.warning) retval = -1;
1059 this->jerr.stopOnWarning = FALSE;
1060 return retval;
1061 }
1062
tjCompressFromYUV(tjhandle handle,const unsigned char * srcBuf,int width,int pad,int height,int subsamp,unsigned char ** jpegBuf,unsigned long * jpegSize,int jpegQual,int flags)1063 DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
1064 int width, int pad, int height, int subsamp,
1065 unsigned char **jpegBuf,
1066 unsigned long *jpegSize, int jpegQual,
1067 int flags)
1068 {
1069 const unsigned char *srcPlanes[3];
1070 int pw0, ph0, strides[3], retval = -1;
1071 tjinstance *this = (tjinstance *)handle;
1072
1073 if (!this) _throwg("tjCompressFromYUV(): Invalid handle");
1074 this->isInstanceError = FALSE;
1075
1076 if (srcBuf == NULL || width <= 0 || pad < 1 || height <= 0 || subsamp < 0 ||
1077 subsamp >= NUMSUBOPT)
1078 _throw("tjCompressFromYUV(): Invalid argument");
1079
1080 pw0 = tjPlaneWidth(0, width, subsamp);
1081 ph0 = tjPlaneHeight(0, height, subsamp);
1082 srcPlanes[0] = srcBuf;
1083 strides[0] = PAD(pw0, pad);
1084 if (subsamp == TJSAMP_GRAY) {
1085 strides[1] = strides[2] = 0;
1086 srcPlanes[1] = srcPlanes[2] = NULL;
1087 } else {
1088 int pw1 = tjPlaneWidth(1, width, subsamp);
1089 int ph1 = tjPlaneHeight(1, height, subsamp);
1090
1091 strides[1] = strides[2] = PAD(pw1, pad);
1092 srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1093 srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1094 }
1095
1096 return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1097 subsamp, jpegBuf, jpegSize, jpegQual, flags);
1098
1099 bailout:
1100 return retval;
1101 }
1102
1103
1104 /* Decompressor */
1105
_tjInitDecompress(tjinstance * this)1106 static tjhandle _tjInitDecompress(tjinstance *this)
1107 {
1108 static unsigned char buffer[1];
1109
1110 /* This is also straight out of example.txt */
1111 this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1112 this->jerr.pub.error_exit = my_error_exit;
1113 this->jerr.pub.output_message = my_output_message;
1114 this->jerr.emit_message = this->jerr.pub.emit_message;
1115 this->jerr.pub.emit_message = my_emit_message;
1116 this->jerr.pub.addon_message_table = turbojpeg_message_table;
1117 this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1118 this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1119
1120 if (setjmp(this->jerr.setjmp_buffer)) {
1121 /* If we get here, the JPEG code has signaled an error. */
1122 if (this) free(this);
1123 return NULL;
1124 }
1125
1126 jpeg_create_decompress(&this->dinfo);
1127 /* Make an initial call so it will create the source manager */
1128 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1129
1130 this->init |= DECOMPRESS;
1131 return (tjhandle)this;
1132 }
1133
tjInitDecompress(void)1134 DLLEXPORT tjhandle tjInitDecompress(void)
1135 {
1136 tjinstance *this;
1137
1138 if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
1139 snprintf(errStr, JMSG_LENGTH_MAX,
1140 "tjInitDecompress(): Memory allocation failure");
1141 return NULL;
1142 }
1143 MEMZERO(this, sizeof(tjinstance));
1144 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
1145 return _tjInitDecompress(this);
1146 }
1147
1148
tjDecompressHeader3(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height,int * jpegSubsamp,int * jpegColorspace)1149 DLLEXPORT int tjDecompressHeader3(tjhandle handle,
1150 const unsigned char *jpegBuf,
1151 unsigned long jpegSize, int *width,
1152 int *height, int *jpegSubsamp,
1153 int *jpegColorspace)
1154 {
1155 int retval = 0;
1156
1157 getdinstance(handle);
1158 if ((this->init & DECOMPRESS) == 0)
1159 _throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
1160
1161 if (jpegBuf == NULL || jpegSize <= 0 || width == NULL || height == NULL ||
1162 jpegSubsamp == NULL || jpegColorspace == NULL)
1163 _throw("tjDecompressHeader3(): Invalid argument");
1164
1165 if (setjmp(this->jerr.setjmp_buffer)) {
1166 /* If we get here, the JPEG code has signaled an error. */
1167 return -1;
1168 }
1169
1170 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1171 jpeg_read_header(dinfo, TRUE);
1172
1173 *width = dinfo->image_width;
1174 *height = dinfo->image_height;
1175 *jpegSubsamp = getSubsamp(dinfo);
1176 switch (dinfo->jpeg_color_space) {
1177 case JCS_GRAYSCALE: *jpegColorspace = TJCS_GRAY; break;
1178 case JCS_RGB: *jpegColorspace = TJCS_RGB; break;
1179 case JCS_YCbCr: *jpegColorspace = TJCS_YCbCr; break;
1180 case JCS_CMYK: *jpegColorspace = TJCS_CMYK; break;
1181 case JCS_YCCK: *jpegColorspace = TJCS_YCCK; break;
1182 default: *jpegColorspace = -1; break;
1183 }
1184
1185 jpeg_abort_decompress(dinfo);
1186
1187 if (*jpegSubsamp < 0)
1188 _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1189 if (*jpegColorspace < 0)
1190 _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
1191 if (*width < 1 || *height < 1)
1192 _throw("tjDecompressHeader3(): Invalid data returned in header");
1193
1194 bailout:
1195 if (this->jerr.warning) retval = -1;
1196 return retval;
1197 }
1198
tjDecompressHeader2(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height,int * jpegSubsamp)1199 DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
1200 unsigned long jpegSize, int *width,
1201 int *height, int *jpegSubsamp)
1202 {
1203 int jpegColorspace;
1204
1205 return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1206 jpegSubsamp, &jpegColorspace);
1207 }
1208
tjDecompressHeader(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height)1209 DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
1210 unsigned long jpegSize, int *width,
1211 int *height)
1212 {
1213 int jpegSubsamp;
1214
1215 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1216 &jpegSubsamp);
1217 }
1218
1219
tjGetScalingFactors(int * numscalingfactors)1220 DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numscalingfactors)
1221 {
1222 if (numscalingfactors == NULL) {
1223 snprintf(errStr, JMSG_LENGTH_MAX,
1224 "tjGetScalingFactors(): Invalid argument");
1225 return NULL;
1226 }
1227
1228 *numscalingfactors = NUMSF;
1229 return (tjscalingfactor *)sf;
1230 }
1231
1232
tjDecompress2(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)1233 DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
1234 unsigned long jpegSize, unsigned char *dstBuf,
1235 int width, int pitch, int height, int pixelFormat,
1236 int flags)
1237 {
1238 JSAMPROW *row_pointer = NULL;
1239 int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
1240
1241 getdinstance(handle);
1242 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1243 if ((this->init & DECOMPRESS) == 0)
1244 _throw("tjDecompress2(): Instance has not been initialized for decompression");
1245
1246 if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1247 pitch < 0 || height < 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1248 _throw("tjDecompress2(): Invalid argument");
1249
1250 #ifndef NO_PUTENV
1251 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1252 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1253 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1254 #endif
1255
1256 if (setjmp(this->jerr.setjmp_buffer)) {
1257 /* If we get here, the JPEG code has signaled an error. */
1258 retval = -1; goto bailout;
1259 }
1260
1261 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1262 jpeg_read_header(dinfo, TRUE);
1263 this->dinfo.out_color_space = pf2cs[pixelFormat];
1264 if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1265 if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1266
1267 jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
1268 if (width == 0) width = jpegwidth;
1269 if (height == 0) height = jpegheight;
1270 for (i = 0; i < NUMSF; i++) {
1271 scaledw = TJSCALED(jpegwidth, sf[i]);
1272 scaledh = TJSCALED(jpegheight, sf[i]);
1273 if (scaledw <= width && scaledh <= height)
1274 break;
1275 }
1276 if (i >= NUMSF)
1277 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
1278 width = scaledw; height = scaledh;
1279 dinfo->scale_num = sf[i].num;
1280 dinfo->scale_denom = sf[i].denom;
1281
1282 jpeg_start_decompress(dinfo);
1283 if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1284
1285 if ((row_pointer =
1286 (JSAMPROW *)malloc(sizeof(JSAMPROW) * dinfo->output_height)) == NULL)
1287 _throw("tjDecompress2(): Memory allocation failure");
1288 if (setjmp(this->jerr.setjmp_buffer)) {
1289 /* If we get here, the JPEG code has signaled an error. */
1290 retval = -1; goto bailout;
1291 }
1292 for (i = 0; i < (int)dinfo->output_height; i++) {
1293 if (flags & TJFLAG_BOTTOMUP)
1294 row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * pitch];
1295 else
1296 row_pointer[i] = &dstBuf[i * pitch];
1297 }
1298 while (dinfo->output_scanline < dinfo->output_height)
1299 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1300 dinfo->output_height - dinfo->output_scanline);
1301 jpeg_finish_decompress(dinfo);
1302
1303 bailout:
1304 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1305 if (row_pointer) free(row_pointer);
1306 if (this->jerr.warning) retval = -1;
1307 this->jerr.stopOnWarning = FALSE;
1308 return retval;
1309 }
1310
tjDecompress(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelSize,int flags)1311 DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1312 unsigned long jpegSize, unsigned char *dstBuf,
1313 int width, int pitch, int height, int pixelSize,
1314 int flags)
1315 {
1316 if (flags & TJ_YUV)
1317 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1318 else
1319 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1320 height, getPixelFormat(pixelSize, flags), flags);
1321 }
1322
1323
setDecodeDefaults(struct jpeg_decompress_struct * dinfo,int pixelFormat,int subsamp,int flags)1324 static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
1325 int pixelFormat, int subsamp, int flags)
1326 {
1327 int i;
1328
1329 dinfo->scale_num = dinfo->scale_denom = 1;
1330
1331 if (subsamp == TJSAMP_GRAY) {
1332 dinfo->num_components = dinfo->comps_in_scan = 1;
1333 dinfo->jpeg_color_space = JCS_GRAYSCALE;
1334 } else {
1335 dinfo->num_components = dinfo->comps_in_scan = 3;
1336 dinfo->jpeg_color_space = JCS_YCbCr;
1337 }
1338
1339 dinfo->comp_info = (jpeg_component_info *)
1340 (*dinfo->mem->alloc_small) ((j_common_ptr)dinfo, JPOOL_IMAGE,
1341 dinfo->num_components *
1342 sizeof(jpeg_component_info));
1343
1344 for (i = 0; i < dinfo->num_components; i++) {
1345 jpeg_component_info *compptr = &dinfo->comp_info[i];
1346
1347 compptr->h_samp_factor = (i == 0) ? tjMCUWidth[subsamp] / 8 : 1;
1348 compptr->v_samp_factor = (i == 0) ? tjMCUHeight[subsamp] / 8 : 1;
1349 compptr->component_index = i;
1350 compptr->component_id = i + 1;
1351 compptr->quant_tbl_no = compptr->dc_tbl_no =
1352 compptr->ac_tbl_no = (i == 0) ? 0 : 1;
1353 dinfo->cur_comp_info[i] = compptr;
1354 }
1355 dinfo->data_precision = 8;
1356 for (i = 0; i < 2; i++) {
1357 if (dinfo->quant_tbl_ptrs[i] == NULL)
1358 dinfo->quant_tbl_ptrs[i] = jpeg_alloc_quant_table((j_common_ptr)dinfo);
1359 }
1360
1361 return 0;
1362 }
1363
1364
my_read_markers(j_decompress_ptr dinfo)1365 int my_read_markers(j_decompress_ptr dinfo)
1366 {
1367 return JPEG_REACHED_SOS;
1368 }
1369
my_reset_marker_reader(j_decompress_ptr dinfo)1370 void my_reset_marker_reader(j_decompress_ptr dinfo)
1371 {
1372 }
1373
tjDecodeYUVPlanes(tjhandle handle,const unsigned char ** srcPlanes,const int * strides,int subsamp,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)1374 DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
1375 const unsigned char **srcPlanes,
1376 const int *strides, int subsamp,
1377 unsigned char *dstBuf, int width, int pitch,
1378 int height, int pixelFormat, int flags)
1379 {
1380 JSAMPROW *row_pointer = NULL;
1381 JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1382 JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
1383 int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1384 JSAMPLE *ptr;
1385 jpeg_component_info *compptr;
1386 int (*old_read_markers) (j_decompress_ptr);
1387 void (*old_reset_marker_reader) (j_decompress_ptr);
1388
1389 getdinstance(handle);
1390 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1391
1392 for (i = 0; i < MAX_COMPONENTS; i++) {
1393 tmpbuf[i] = NULL; _tmpbuf[i] = NULL; inbuf[i] = NULL;
1394 }
1395
1396 if ((this->init & DECOMPRESS) == 0)
1397 _throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
1398
1399 if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT ||
1400 dstBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1401 pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1402 _throw("tjDecodeYUVPlanes(): Invalid argument");
1403 if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1404 _throw("tjDecodeYUVPlanes(): Invalid argument");
1405
1406 if (setjmp(this->jerr.setjmp_buffer)) {
1407 /* If we get here, the JPEG code has signaled an error. */
1408 retval = -1; goto bailout;
1409 }
1410
1411 if (pixelFormat == TJPF_CMYK)
1412 _throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
1413
1414 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1415 dinfo->image_width = width;
1416 dinfo->image_height = height;
1417
1418 #ifndef NO_PUTENV
1419 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1420 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1421 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1422 #endif
1423
1424 if (setDecodeDefaults(dinfo, pixelFormat, subsamp, flags) == -1) {
1425 retval = -1; goto bailout;
1426 }
1427 old_read_markers = dinfo->marker->read_markers;
1428 dinfo->marker->read_markers = my_read_markers;
1429 old_reset_marker_reader = dinfo->marker->reset_marker_reader;
1430 dinfo->marker->reset_marker_reader = my_reset_marker_reader;
1431 jpeg_read_header(dinfo, TRUE);
1432 dinfo->marker->read_markers = old_read_markers;
1433 dinfo->marker->reset_marker_reader = old_reset_marker_reader;
1434
1435 this->dinfo.out_color_space = pf2cs[pixelFormat];
1436 if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1437 dinfo->do_fancy_upsampling = FALSE;
1438 dinfo->Se = DCTSIZE2 - 1;
1439 jinit_master_decompress(dinfo);
1440 (*dinfo->upsample->start_pass) (dinfo);
1441
1442 pw0 = PAD(width, dinfo->max_h_samp_factor);
1443 ph0 = PAD(height, dinfo->max_v_samp_factor);
1444
1445 if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1446
1447 if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1448 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1449 for (i = 0; i < height; i++) {
1450 if (flags & TJFLAG_BOTTOMUP)
1451 row_pointer[i] = &dstBuf[(height - i - 1) * pitch];
1452 else
1453 row_pointer[i] = &dstBuf[i * pitch];
1454 }
1455 if (height < ph0)
1456 for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
1457
1458 for (i = 0; i < dinfo->num_components; i++) {
1459 compptr = &dinfo->comp_info[i];
1460 _tmpbuf[i] =
1461 (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1462 compptr->v_samp_factor + 32);
1463 if (!_tmpbuf[i])
1464 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1465 tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1466 if (!tmpbuf[i])
1467 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1468 for (row = 0; row < compptr->v_samp_factor; row++) {
1469 unsigned char *_tmpbuf_aligned =
1470 (unsigned char *)PAD((size_t)_tmpbuf[i], 32);
1471
1472 tmpbuf[i][row] =
1473 &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1474 }
1475 pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
1476 ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
1477 inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1478 if (!inbuf[i])
1479 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1480 ptr = (JSAMPLE *)srcPlanes[i];
1481 for (row = 0; row < ph[i]; row++) {
1482 inbuf[i][row] = ptr;
1483 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1484 }
1485 }
1486
1487 if (setjmp(this->jerr.setjmp_buffer)) {
1488 /* If we get here, the JPEG code has signaled an error. */
1489 retval = -1; goto bailout;
1490 }
1491
1492 for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
1493 JDIMENSION inrow = 0, outrow = 0;
1494
1495 for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
1496 i++, compptr++)
1497 jcopy_sample_rows(inbuf[i],
1498 row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
1499 compptr->v_samp_factor, pw[i]);
1500 (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
1501 dinfo->max_v_samp_factor, &row_pointer[row],
1502 &outrow, dinfo->max_v_samp_factor);
1503 }
1504 jpeg_abort_decompress(dinfo);
1505
1506 bailout:
1507 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1508 if (row_pointer) free(row_pointer);
1509 for (i = 0; i < MAX_COMPONENTS; i++) {
1510 if (tmpbuf[i] != NULL) free(tmpbuf[i]);
1511 if (_tmpbuf[i] != NULL) free(_tmpbuf[i]);
1512 if (inbuf[i] != NULL) free(inbuf[i]);
1513 }
1514 if (this->jerr.warning) retval = -1;
1515 this->jerr.stopOnWarning = FALSE;
1516 return retval;
1517 }
1518
tjDecodeYUV(tjhandle handle,const unsigned char * srcBuf,int pad,int subsamp,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)1519 DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
1520 int pad, int subsamp, unsigned char *dstBuf,
1521 int width, int pitch, int height, int pixelFormat,
1522 int flags)
1523 {
1524 const unsigned char *srcPlanes[3];
1525 int pw0, ph0, strides[3], retval = -1;
1526 tjinstance *this = (tjinstance *)handle;
1527
1528 if (!this) _throwg("tjDecodeYUV(): Invalid handle");
1529 this->isInstanceError = FALSE;
1530
1531 if (srcBuf == NULL || pad < 0 || !isPow2(pad) || subsamp < 0 ||
1532 subsamp >= NUMSUBOPT || width <= 0 || height <= 0)
1533 _throw("tjDecodeYUV(): Invalid argument");
1534
1535 pw0 = tjPlaneWidth(0, width, subsamp);
1536 ph0 = tjPlaneHeight(0, height, subsamp);
1537 srcPlanes[0] = srcBuf;
1538 strides[0] = PAD(pw0, pad);
1539 if (subsamp == TJSAMP_GRAY) {
1540 strides[1] = strides[2] = 0;
1541 srcPlanes[1] = srcPlanes[2] = NULL;
1542 } else {
1543 int pw1 = tjPlaneWidth(1, width, subsamp);
1544 int ph1 = tjPlaneHeight(1, height, subsamp);
1545
1546 strides[1] = strides[2] = PAD(pw1, pad);
1547 srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1548 srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1549 }
1550
1551 return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1552 pitch, height, pixelFormat, flags);
1553
1554 bailout:
1555 return retval;
1556 }
1557
tjDecompressToYUVPlanes(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,unsigned char ** dstPlanes,int width,int * strides,int height,int flags)1558 DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
1559 const unsigned char *jpegBuf,
1560 unsigned long jpegSize,
1561 unsigned char **dstPlanes, int width,
1562 int *strides, int height, int flags)
1563 {
1564 int i, sfi, row, retval = 0;
1565 int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
1566 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1567 tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1568 JSAMPLE *_tmpbuf = NULL, *ptr;
1569 JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1570 int dctsize;
1571
1572 getdinstance(handle);
1573 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1574
1575 for (i = 0; i < MAX_COMPONENTS; i++) {
1576 tmpbuf[i] = NULL; outbuf[i] = NULL;
1577 }
1578
1579 if ((this->init & DECOMPRESS) == 0)
1580 _throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
1581
1582 if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0] ||
1583 width < 0 || height < 0)
1584 _throw("tjDecompressToYUVPlanes(): Invalid argument");
1585
1586 #ifndef NO_PUTENV
1587 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1588 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1589 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1590 #endif
1591
1592 if (setjmp(this->jerr.setjmp_buffer)) {
1593 /* If we get here, the JPEG code has signaled an error. */
1594 retval = -1; goto bailout;
1595 }
1596
1597 if (!this->headerRead) {
1598 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1599 jpeg_read_header(dinfo, TRUE);
1600 }
1601 this->headerRead = 0;
1602 jpegSubsamp = getSubsamp(dinfo);
1603 if (jpegSubsamp < 0)
1604 _throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1605
1606 if (jpegSubsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1607 _throw("tjDecompressToYUVPlanes(): Invalid argument");
1608
1609 jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
1610 if (width == 0) width = jpegwidth;
1611 if (height == 0) height = jpegheight;
1612 for (i = 0; i < NUMSF; i++) {
1613 scaledw = TJSCALED(jpegwidth, sf[i]);
1614 scaledh = TJSCALED(jpegheight, sf[i]);
1615 if (scaledw <= width && scaledh <= height)
1616 break;
1617 }
1618 if (i >= NUMSF)
1619 _throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
1620 if (dinfo->num_components > 3)
1621 _throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
1622
1623 width = scaledw; height = scaledh;
1624 dinfo->scale_num = sf[i].num;
1625 dinfo->scale_denom = sf[i].denom;
1626 sfi = i;
1627 jpeg_calc_output_dimensions(dinfo);
1628
1629 dctsize = DCTSIZE * sf[sfi].num / sf[sfi].denom;
1630
1631 for (i = 0; i < dinfo->num_components; i++) {
1632 jpeg_component_info *compptr = &dinfo->comp_info[i];
1633 int ih;
1634
1635 iw[i] = compptr->width_in_blocks * dctsize;
1636 ih = compptr->height_in_blocks * dctsize;
1637 pw[i] = PAD(dinfo->output_width, dinfo->max_h_samp_factor) *
1638 compptr->h_samp_factor / dinfo->max_h_samp_factor;
1639 ph[i] = PAD(dinfo->output_height, dinfo->max_v_samp_factor) *
1640 compptr->v_samp_factor / dinfo->max_v_samp_factor;
1641 if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1642 th[i] = compptr->v_samp_factor * dctsize;
1643 tmpbufsize += iw[i] * th[i];
1644 if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1645 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1646 ptr = dstPlanes[i];
1647 for (row = 0; row < ph[i]; row++) {
1648 outbuf[i][row] = ptr;
1649 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1650 }
1651 }
1652 if (usetmpbuf) {
1653 if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1654 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1655 ptr = _tmpbuf;
1656 for (i = 0; i < dinfo->num_components; i++) {
1657 if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1658 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1659 for (row = 0; row < th[i]; row++) {
1660 tmpbuf[i][row] = ptr;
1661 ptr += iw[i];
1662 }
1663 }
1664 }
1665
1666 if (setjmp(this->jerr.setjmp_buffer)) {
1667 /* If we get here, the JPEG code has signaled an error. */
1668 retval = -1; goto bailout;
1669 }
1670
1671 if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1672 if (flags & TJFLAG_FASTDCT) dinfo->dct_method = JDCT_FASTEST;
1673 dinfo->raw_data_out = TRUE;
1674
1675 jpeg_start_decompress(dinfo);
1676 for (row = 0; row < (int)dinfo->output_height;
1677 row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
1678 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1679 int crow[MAX_COMPONENTS];
1680
1681 for (i = 0; i < dinfo->num_components; i++) {
1682 jpeg_component_info *compptr = &dinfo->comp_info[i];
1683
1684 if (jpegSubsamp == TJ_420) {
1685 /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1686 to be clever and use the IDCT to perform upsampling on the U and V
1687 planes. For instance, if the output image is to be scaled by 1/2
1688 relative to the JPEG image, then the scaling factor and upsampling
1689 effectively cancel each other, so a normal 8x8 IDCT can be used.
1690 However, this is not desirable when using the decompress-to-YUV
1691 functionality in TurboJPEG, since we want to output the U and V
1692 planes in their subsampled form. Thus, we have to override some
1693 internal libjpeg parameters to force it to use the "scaled" IDCT
1694 functions on the U and V planes. */
1695 compptr->_DCT_scaled_size = dctsize;
1696 compptr->MCU_sample_width = tjMCUWidth[jpegSubsamp] *
1697 sf[sfi].num / sf[sfi].denom *
1698 compptr->v_samp_factor / dinfo->max_v_samp_factor;
1699 dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1700 }
1701 crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
1702 if (usetmpbuf) yuvptr[i] = tmpbuf[i];
1703 else yuvptr[i] = &outbuf[i][crow[i]];
1704 }
1705 jpeg_read_raw_data(dinfo, yuvptr,
1706 dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
1707 if (usetmpbuf) {
1708 int j;
1709
1710 for (i = 0; i < dinfo->num_components; i++) {
1711 for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1712 memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
1713 }
1714 }
1715 }
1716 }
1717 jpeg_finish_decompress(dinfo);
1718
1719 bailout:
1720 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1721 for (i = 0; i < MAX_COMPONENTS; i++) {
1722 if (tmpbuf[i]) free(tmpbuf[i]);
1723 if (outbuf[i]) free(outbuf[i]);
1724 }
1725 if (_tmpbuf) free(_tmpbuf);
1726 if (this->jerr.warning) retval = -1;
1727 this->jerr.stopOnWarning = FALSE;
1728 return retval;
1729 }
1730
tjDecompressToYUV2(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pad,int height,int flags)1731 DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
1732 unsigned long jpegSize, unsigned char *dstBuf,
1733 int width, int pad, int height, int flags)
1734 {
1735 unsigned char *dstPlanes[3];
1736 int pw0, ph0, strides[3], retval = -1, jpegSubsamp = -1;
1737 int i, jpegwidth, jpegheight, scaledw, scaledh;
1738
1739 getdinstance(handle);
1740 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1741
1742 if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1743 pad < 1 || !isPow2(pad) || height < 0)
1744 _throw("tjDecompressToYUV2(): Invalid argument");
1745
1746 if (setjmp(this->jerr.setjmp_buffer)) {
1747 /* If we get here, the JPEG code has signaled an error. */
1748 return -1;
1749 }
1750
1751 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1752 jpeg_read_header(dinfo, TRUE);
1753 jpegSubsamp = getSubsamp(dinfo);
1754 if (jpegSubsamp < 0)
1755 _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1756
1757 jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
1758 if (width == 0) width = jpegwidth;
1759 if (height == 0) height = jpegheight;
1760
1761 for (i = 0; i < NUMSF; i++) {
1762 scaledw = TJSCALED(jpegwidth, sf[i]);
1763 scaledh = TJSCALED(jpegheight, sf[i]);
1764 if (scaledw <= width && scaledh <= height)
1765 break;
1766 }
1767 if (i >= NUMSF)
1768 _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1769
1770 pw0 = tjPlaneWidth(0, width, jpegSubsamp);
1771 ph0 = tjPlaneHeight(0, height, jpegSubsamp);
1772 dstPlanes[0] = dstBuf;
1773 strides[0] = PAD(pw0, pad);
1774 if (jpegSubsamp == TJSAMP_GRAY) {
1775 strides[1] = strides[2] = 0;
1776 dstPlanes[1] = dstPlanes[2] = NULL;
1777 } else {
1778 int pw1 = tjPlaneWidth(1, width, jpegSubsamp);
1779 int ph1 = tjPlaneHeight(1, height, jpegSubsamp);
1780
1781 strides[1] = strides[2] = PAD(pw1, pad);
1782 dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1783 dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1784 }
1785
1786 this->headerRead = 1;
1787 return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1788 strides, height, flags);
1789
1790 bailout:
1791 this->jerr.stopOnWarning = FALSE;
1792 return retval;
1793 }
1794
tjDecompressToYUV(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int flags)1795 DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
1796 unsigned long jpegSize, unsigned char *dstBuf,
1797 int flags)
1798 {
1799 return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1800 }
1801
1802
1803 /* Transformer */
1804
tjInitTransform(void)1805 DLLEXPORT tjhandle tjInitTransform(void)
1806 {
1807 tjinstance *this = NULL;
1808 tjhandle handle = NULL;
1809
1810 if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
1811 snprintf(errStr, JMSG_LENGTH_MAX,
1812 "tjInitTransform(): Memory allocation failure");
1813 return NULL;
1814 }
1815 MEMZERO(this, sizeof(tjinstance));
1816 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
1817 handle = _tjInitCompress(this);
1818 if (!handle) return NULL;
1819 handle = _tjInitDecompress(this);
1820 return handle;
1821 }
1822
1823
tjTransform(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,int n,unsigned char ** dstBufs,unsigned long * dstSizes,tjtransform * t,int flags)1824 DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
1825 unsigned long jpegSize, int n,
1826 unsigned char **dstBufs, unsigned long *dstSizes,
1827 tjtransform *t, int flags)
1828 {
1829 jpeg_transform_info *xinfo = NULL;
1830 jvirt_barray_ptr *srccoefs, *dstcoefs;
1831 int retval = 0, i, jpegSubsamp, saveMarkers = 0;
1832
1833 getinstance(handle);
1834 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1835 if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
1836 _throw("tjTransform(): Instance has not been initialized for transformation");
1837
1838 if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
1839 dstSizes == NULL || t == NULL || flags < 0)
1840 _throw("tjTransform(): Invalid argument");
1841
1842 #ifndef NO_PUTENV
1843 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1844 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1845 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1846 #endif
1847
1848 if ((xinfo =
1849 (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
1850 _throw("tjTransform(): Memory allocation failure");
1851 MEMZERO(xinfo, sizeof(jpeg_transform_info) * n);
1852
1853 if (setjmp(this->jerr.setjmp_buffer)) {
1854 /* If we get here, the JPEG code has signaled an error. */
1855 retval = -1; goto bailout;
1856 }
1857
1858 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1859
1860 for (i = 0; i < n; i++) {
1861 xinfo[i].transform = xformtypes[t[i].op];
1862 xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
1863 xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
1864 xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
1865 xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
1866 if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
1867 else xinfo[i].slow_hflip = 0;
1868
1869 if (xinfo[i].crop) {
1870 xinfo[i].crop_xoffset = t[i].r.x; xinfo[i].crop_xoffset_set = JCROP_POS;
1871 xinfo[i].crop_yoffset = t[i].r.y; xinfo[i].crop_yoffset_set = JCROP_POS;
1872 if (t[i].r.w != 0) {
1873 xinfo[i].crop_width = t[i].r.w; xinfo[i].crop_width_set = JCROP_POS;
1874 } else
1875 xinfo[i].crop_width = JCROP_UNSET;
1876 if (t[i].r.h != 0) {
1877 xinfo[i].crop_height = t[i].r.h; xinfo[i].crop_height_set = JCROP_POS;
1878 } else
1879 xinfo[i].crop_height = JCROP_UNSET;
1880 }
1881 if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
1882 }
1883
1884 jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
1885 jpeg_read_header(dinfo, TRUE);
1886 jpegSubsamp = getSubsamp(dinfo);
1887 if (jpegSubsamp < 0)
1888 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
1889
1890 for (i = 0; i < n; i++) {
1891 if (!jtransform_request_workspace(dinfo, &xinfo[i]))
1892 _throw("tjTransform(): Transform is not perfect");
1893
1894 if (xinfo[i].crop) {
1895 if ((t[i].r.x % xinfo[i].iMCU_sample_width) != 0 ||
1896 (t[i].r.y % xinfo[i].iMCU_sample_height) != 0) {
1897 snprintf(errStr, JMSG_LENGTH_MAX,
1898 "To crop this JPEG image, x must be a multiple of %d\n"
1899 "and y must be a multiple of %d.\n",
1900 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1901 retval = -1; goto bailout;
1902 }
1903 }
1904 }
1905
1906 srccoefs = jpeg_read_coefficients(dinfo);
1907
1908 for (i = 0; i < n; i++) {
1909 int w, h, alloc = 1;
1910
1911 if (!xinfo[i].crop) {
1912 w = dinfo->image_width; h = dinfo->image_height;
1913 } else {
1914 w = xinfo[i].crop_width; h = xinfo[i].crop_height;
1915 }
1916 if (flags & TJFLAG_NOREALLOC) {
1917 alloc = 0; dstSizes[i] = tjBufSize(w, h, jpegSubsamp);
1918 }
1919 if (!(t[i].options & TJXOPT_NOOUTPUT))
1920 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
1921 jpeg_copy_critical_parameters(dinfo, cinfo);
1922 dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
1923 if (flags & TJFLAG_PROGRESSIVE || t[i].options & TJXOPT_PROGRESSIVE)
1924 jpeg_simple_progression(cinfo);
1925 if (!(t[i].options & TJXOPT_NOOUTPUT)) {
1926 jpeg_write_coefficients(cinfo, dstcoefs);
1927 jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
1928 JCOPYOPT_NONE : JCOPYOPT_ALL);
1929 } else
1930 jinit_c_master_control(cinfo, TRUE);
1931 jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
1932 if (t[i].customFilter) {
1933 int ci, y;
1934 JDIMENSION by;
1935
1936 for (ci = 0; ci < cinfo->num_components; ci++) {
1937 jpeg_component_info *compptr = &cinfo->comp_info[ci];
1938 tjregion arrayRegion = {
1939 0, 0, compptr->width_in_blocks * DCTSIZE, DCTSIZE
1940 };
1941 tjregion planeRegion = {
1942 0, 0, compptr->width_in_blocks * DCTSIZE,
1943 compptr->height_in_blocks * DCTSIZE
1944 };
1945
1946 for (by = 0; by < compptr->height_in_blocks;
1947 by += compptr->v_samp_factor) {
1948 JBLOCKARRAY barray = (dinfo->mem->access_virt_barray)
1949 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1950 TRUE);
1951
1952 for (y = 0; y < compptr->v_samp_factor; y++) {
1953 if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci,
1954 i, &t[i]) == -1)
1955 _throw("tjTransform(): Error in custom filter");
1956 arrayRegion.y += DCTSIZE;
1957 }
1958 }
1959 }
1960 }
1961 if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
1962 }
1963
1964 jpeg_finish_decompress(dinfo);
1965
1966 bailout:
1967 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1968 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1969 if (xinfo) free(xinfo);
1970 if (this->jerr.warning) retval = -1;
1971 this->jerr.stopOnWarning = FALSE;
1972 return retval;
1973 }
1974
1975
tjLoadImage(const char * filename,int * width,int align,int * height,int * pixelFormat,int flags)1976 DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
1977 int align, int *height, int *pixelFormat,
1978 int flags)
1979 {
1980 int retval = 0, tempc;
1981 size_t pitch;
1982 tjhandle handle = NULL;
1983 tjinstance *this;
1984 j_compress_ptr cinfo = NULL;
1985 cjpeg_source_ptr src;
1986 unsigned char *dstBuf = NULL;
1987 FILE *file = NULL;
1988 boolean invert;
1989
1990 if (!filename || !width || align < 1 || !height || !pixelFormat ||
1991 *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF)
1992 _throwg("tjLoadImage(): Invalid argument");
1993 if ((align & (align - 1)) != 0)
1994 _throwg("tjLoadImage(): Alignment must be a power of 2");
1995
1996 if ((handle = tjInitCompress()) == NULL) return NULL;
1997 this = (tjinstance *)handle;
1998 cinfo = &this->cinfo;
1999
2000 if ((file = fopen(filename, "rb")) == NULL)
2001 _throwunix("tjLoadImage(): Cannot open input file");
2002
2003 if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF)
2004 _throwunix("tjLoadImage(): Could not read input file")
2005 else if (tempc == EOF)
2006 _throwg("tjLoadImage(): Input file contains no data");
2007
2008 if (setjmp(this->jerr.setjmp_buffer)) {
2009 /* If we get here, the JPEG code has signaled an error. */
2010 retval = -1; goto bailout;
2011 }
2012
2013 if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN;
2014 else cinfo->in_color_space = pf2cs[*pixelFormat];
2015 if (tempc == 'B') {
2016 if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL)
2017 _throwg("tjLoadImage(): Could not initialize bitmap loader");
2018 invert = (flags & TJFLAG_BOTTOMUP) == 0;
2019 } else if (tempc == 'P') {
2020 if ((src = jinit_read_ppm(cinfo)) == NULL)
2021 _throwg("tjLoadImage(): Could not initialize bitmap loader");
2022 invert = (flags & TJFLAG_BOTTOMUP) != 0;
2023 } else
2024 _throwg("tjLoadImage(): Unsupported file type");
2025
2026 src->input_file = file;
2027 (*src->start_input) (cinfo, src);
2028 (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
2029
2030 *width = cinfo->image_width; *height = cinfo->image_height;
2031 *pixelFormat = cs2pf[cinfo->in_color_space];
2032
2033 pitch = PAD((*width) * tjPixelSize[*pixelFormat], align);
2034 if ((unsigned long long)pitch * (unsigned long long)(*height) >
2035 (unsigned long long)((size_t)-1) ||
2036 (dstBuf = (unsigned char *)malloc(pitch * (*height))) == NULL)
2037 _throwg("tjLoadImage(): Memory allocation failure");
2038
2039 if (setjmp(this->jerr.setjmp_buffer)) {
2040 /* If we get here, the JPEG code has signaled an error. */
2041 retval = -1; goto bailout;
2042 }
2043
2044 while (cinfo->next_scanline < cinfo->image_height) {
2045 int i, nlines = (*src->get_pixel_rows) (cinfo, src);
2046
2047 for (i = 0; i < nlines; i++) {
2048 unsigned char *dstptr;
2049 int row;
2050
2051 row = cinfo->next_scanline + i;
2052 if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch];
2053 else dstptr = &dstBuf[row * pitch];
2054 memcpy(dstptr, src->buffer[i], (*width) * tjPixelSize[*pixelFormat]);
2055 }
2056 cinfo->next_scanline += nlines;
2057 }
2058
2059 (*src->finish_input) (cinfo, src);
2060
2061 bailout:
2062 if (handle) tjDestroy(handle);
2063 if (file) fclose(file);
2064 if (retval < 0 && dstBuf) { free(dstBuf); dstBuf = NULL; }
2065 return dstBuf;
2066 }
2067
2068
tjSaveImage(const char * filename,unsigned char * buffer,int width,int pitch,int height,int pixelFormat,int flags)2069 DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
2070 int width, int pitch, int height, int pixelFormat,
2071 int flags)
2072 {
2073 int retval = 0;
2074 tjhandle handle = NULL;
2075 tjinstance *this;
2076 j_decompress_ptr dinfo = NULL;
2077 djpeg_dest_ptr dst;
2078 FILE *file = NULL;
2079 char *ptr = NULL;
2080 boolean invert;
2081
2082 if (!filename || !buffer || width < 1 || pitch < 0 || height < 1 ||
2083 pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
2084 _throwg("tjSaveImage(): Invalid argument");
2085
2086 if ((handle = tjInitDecompress()) == NULL)
2087 return -1;
2088 this = (tjinstance *)handle;
2089 dinfo = &this->dinfo;
2090
2091 if ((file = fopen(filename, "wb")) == NULL)
2092 _throwunix("tjSaveImage(): Cannot open output file");
2093
2094 if (setjmp(this->jerr.setjmp_buffer)) {
2095 /* If we get here, the JPEG code has signaled an error. */
2096 retval = -1; goto bailout;
2097 }
2098
2099 this->dinfo.out_color_space = pf2cs[pixelFormat];
2100 dinfo->image_width = width; dinfo->image_height = height;
2101 dinfo->global_state = DSTATE_READY;
2102 dinfo->scale_num = dinfo->scale_denom = 1;
2103
2104 ptr = strrchr(filename, '.');
2105 if (ptr && !strcasecmp(ptr, ".bmp")) {
2106 if ((dst = jinit_write_bmp(dinfo, FALSE, FALSE)) == NULL)
2107 _throwg("tjSaveImage(): Could not initialize bitmap writer");
2108 invert = (flags & TJFLAG_BOTTOMUP) == 0;
2109 } else {
2110 if ((dst = jinit_write_ppm(dinfo)) == NULL)
2111 _throwg("tjSaveImage(): Could not initialize PPM writer");
2112 invert = (flags & TJFLAG_BOTTOMUP) != 0;
2113 }
2114
2115 dst->output_file = file;
2116 (*dst->start_output) (dinfo, dst);
2117 (*dinfo->mem->realize_virt_arrays) ((j_common_ptr)dinfo);
2118
2119 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
2120
2121 while (dinfo->output_scanline < dinfo->output_height) {
2122 unsigned char *rowptr;
2123
2124 if (invert)
2125 rowptr = &buffer[(height - dinfo->output_scanline - 1) * pitch];
2126 else
2127 rowptr = &buffer[dinfo->output_scanline * pitch];
2128 memcpy(dst->buffer[0], rowptr, width * tjPixelSize[pixelFormat]);
2129 (*dst->put_pixel_rows) (dinfo, dst, 1);
2130 dinfo->output_scanline++;
2131 }
2132
2133 (*dst->finish_output) (dinfo, dst);
2134
2135 bailout:
2136 if (handle) tjDestroy(handle);
2137 if (file) fclose(file);
2138 return retval;
2139 }
2140