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