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