1 /*
2 * gd_jpeg.c: Read and write JPEG (JFIF) format image files using the
3 * gd graphics library (http://www.boutell.com/gd/).
4 *
5 * This software is based in part on the work of the Independent JPEG
6 * Group. For more information on the IJG JPEG software (and JPEG
7 * documentation, etc.), see ftp://ftp.uu.net/graphics/jpeg/.
8 *
9 * NOTE: IJG 12-bit JSAMPLE (BITS_IN_JSAMPLE == 12) mode is not
10 * supported at all on read in gd 2.0, and is not supported on write
11 * except for palette images, which is sort of pointless (TBB). Even that
12 * has never been tested according to DB.
13 *
14 * Copyright 2000 Doug Becker, mailto:thebeckers@home.com
15 *
16 * Modification 4/18/00 TBB: JPEG_DEBUG rather than just DEBUG,
17 * so VC++ builds don't spew to standard output, causing
18 * major CGI brain damage
19 *
20 * 2.0.10: more efficient gdImageCreateFromJpegCtx, thanks to
21 * Christian Aberger
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <setjmp.h>
27 #include <limits.h>
28 #include <string.h>
29
30 #include "gd.h"
31 #include "gd_errors.h"
32 /* TBB: move this up so include files are not brought in */
33 /* JCE: arrange HAVE_LIBJPEG so that it can be set in gd.h */
34 #ifdef HAVE_LIBJPEG
35 #include "gdhelpers.h"
36 #undef HAVE_STDLIB_H
37
38 /* 1.8.1: remove dependency on jinclude.h */
39 #include "jpeglib.h"
40 #include "jerror.h"
41
42 static const char *const GD_JPEG_VERSION = "1.0";
43
44 typedef struct _jmpbuf_wrapper
45 {
46 jmp_buf jmpbuf;
47 int ignore_warning;
48 } jmpbuf_wrapper;
49
php_jpeg_emit_message(j_common_ptr jpeg_info,int level)50 static long php_jpeg_emit_message(j_common_ptr jpeg_info, int level)
51 {
52 char message[JMSG_LENGTH_MAX];
53 jmpbuf_wrapper *jmpbufw;
54 int ignore_warning = 0;
55
56 jmpbufw = (jmpbuf_wrapper *) jpeg_info->client_data;
57
58 if (jmpbufw != 0) {
59 ignore_warning = jmpbufw->ignore_warning;
60 }
61
62 (jpeg_info->err->format_message)(jpeg_info,message);
63
64 /* It is a warning message */
65 if (level < 0) {
66 /* display only the 1st warning, as would do a default libjpeg
67 * unless strace_level >= 3
68 */
69 if ((jpeg_info->err->num_warnings == 0) || (jpeg_info->err->trace_level >= 3)) {
70 if (!ignore_warning) {
71 gd_error("gd-jpeg, libjpeg: recoverable error: %s\n", message);
72 }
73 }
74
75 jpeg_info->err->num_warnings++;
76 } else {
77 /* strace msg, Show it if trace_level >= level. */
78 if (jpeg_info->err->trace_level >= level) {
79 if (!ignore_warning) {
80 gd_error("gd-jpeg, libjpeg: strace message: %s\n", message);
81 }
82 }
83 }
84 return 1;
85 }
86
87
88
89 /* Called by the IJG JPEG library upon encountering a fatal error */
fatal_jpeg_error(j_common_ptr cinfo)90 static void fatal_jpeg_error (j_common_ptr cinfo)
91 {
92 jmpbuf_wrapper *jmpbufw;
93 char buffer[JMSG_LENGTH_MAX];
94
95 (*cinfo->err->format_message)(cinfo, buffer);
96 gd_error_ex(GD_WARNING, "gd-jpeg: JPEG library reports unrecoverable error: %s", buffer);
97
98 jmpbufw = (jmpbuf_wrapper *) cinfo->client_data;
99 jpeg_destroy (cinfo);
100
101 if (jmpbufw != 0) {
102 longjmp (jmpbufw->jmpbuf, 1);
103 gd_error_ex(GD_ERROR, "gd-jpeg: EXTREMELY fatal error: longjmp returned control; terminating");
104 } else {
105 gd_error_ex(GD_ERROR, "gd-jpeg: EXTREMELY fatal error: jmpbuf unrecoverable; terminating");
106 }
107
108 exit (99);
109 }
110
gdJpegGetVersionInt()111 int gdJpegGetVersionInt()
112 {
113 return JPEG_LIB_VERSION;
114 }
115
gdJpegGetVersionString()116 const char * gdJpegGetVersionString()
117 {
118 switch(JPEG_LIB_VERSION) {
119 case 62:
120 return "6b";
121 break;
122
123 case 70:
124 return "7";
125 break;
126
127 case 80:
128 return "8";
129 break;
130
131 case 90:
132 return "9 compatible";
133 break;
134
135 default:
136 return "unknown";
137 }
138 }
139
140
141 /*
142 * Write IM to OUTFILE as a JFIF-formatted JPEG image, using quality
143 * QUALITY. If QUALITY is in the range 0-100, increasing values
144 * represent higher quality but also larger image size. If QUALITY is
145 * negative, the IJG JPEG library's default quality is used (which
146 * should be near optimal for many applications). See the IJG JPEG
147 * library documentation for more details.
148 */
149
gdImageJpeg(gdImagePtr im,FILE * outFile,int quality)150 void gdImageJpeg (gdImagePtr im, FILE * outFile, int quality)
151 {
152 gdIOCtx *out = gdNewFileCtx (outFile);
153 gdImageJpegCtx (im, out, quality);
154 out->gd_free (out);
155 }
156
gdImageJpegPtr(gdImagePtr im,int * size,int quality)157 void *gdImageJpegPtr (gdImagePtr im, int *size, int quality)
158 {
159 void *rv;
160 gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
161 gdImageJpegCtx (im, out, quality);
162 rv = gdDPExtractData (out, size);
163 out->gd_free (out);
164
165 return rv;
166 }
167
168 void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile);
169
gdImageJpegCtx(gdImagePtr im,gdIOCtx * outfile,int quality)170 void gdImageJpegCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
171 {
172 struct jpeg_compress_struct cinfo;
173 struct jpeg_error_mgr jerr;
174 int i, j, jidx;
175 /* volatile so we can gdFree it on return from longjmp */
176 volatile JSAMPROW row = 0;
177 JSAMPROW rowptr[1];
178 jmpbuf_wrapper jmpbufw;
179 JDIMENSION nlines;
180 char comment[255];
181
182 memset (&cinfo, 0, sizeof (cinfo));
183 memset (&jerr, 0, sizeof (jerr));
184
185 cinfo.err = jpeg_std_error (&jerr);
186 cinfo.client_data = &jmpbufw;
187 if (setjmp (jmpbufw.jmpbuf) != 0) {
188 /* we're here courtesy of longjmp */
189 if (row) {
190 gdFree (row);
191 }
192 return;
193 }
194
195 cinfo.err->error_exit = fatal_jpeg_error;
196
197 jpeg_create_compress (&cinfo);
198
199 cinfo.image_width = im->sx;
200 cinfo.image_height = im->sy;
201 cinfo.input_components = 3; /* # of color components per pixel */
202 cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
203 jpeg_set_defaults (&cinfo);
204
205 cinfo.density_unit = 1;
206 cinfo.X_density = im->res_x;
207 cinfo.Y_density = im->res_y;
208
209 if (quality >= 0) {
210 jpeg_set_quality (&cinfo, quality, TRUE);
211 }
212
213 /* If user requests interlace, translate that to progressive JPEG */
214 if (gdImageGetInterlaced (im)) {
215 jpeg_simple_progression (&cinfo);
216 }
217
218 jpeg_gdIOCtx_dest (&cinfo, outfile);
219
220 row = (JSAMPROW) safe_emalloc(cinfo.image_width * cinfo.input_components, sizeof(JSAMPLE), 0);
221 memset(row, 0, cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE));
222 rowptr[0] = row;
223
224 jpeg_start_compress (&cinfo, TRUE);
225
226 if (quality >= 0) {
227 snprintf(comment, sizeof(comment)-1, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d), quality = %d\n", GD_JPEG_VERSION, JPEG_LIB_VERSION, quality);
228 } else {
229 snprintf(comment, sizeof(comment)-1, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d), default quality\n", GD_JPEG_VERSION, JPEG_LIB_VERSION);
230 }
231 jpeg_write_marker (&cinfo, JPEG_COM, (unsigned char *) comment, (unsigned int) strlen (comment));
232 if (im->trueColor) {
233
234 #if BITS_IN_JSAMPLE == 12
235 gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit precision. This is mostly useless, because JPEGs on the web are 8-bit and such versions of the jpeg library won't read or write them. GD doesn't support these unusual images. Edit your jmorecfg.h file to specify the correct precision and completely 'make clean' and 'make install' libjpeg again. Sorry");
236 goto error;
237 #endif /* BITS_IN_JSAMPLE == 12 */
238
239 for (i = 0; i < im->sy; i++) {
240 for (jidx = 0, j = 0; j < im->sx; j++) {
241 int val = im->tpixels[i][j];
242
243 row[jidx++] = gdTrueColorGetRed (val);
244 row[jidx++] = gdTrueColorGetGreen (val);
245 row[jidx++] = gdTrueColorGetBlue (val);
246 }
247
248 nlines = jpeg_write_scanlines (&cinfo, rowptr, 1);
249 if (nlines != 1) {
250 gd_error_ex(GD_WARNING, "gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1", nlines);
251 }
252 }
253 } else {
254 for (i = 0; i < im->sy; i++) {
255 for (jidx = 0, j = 0; j < im->sx; j++) {
256 int idx = im->pixels[i][j];
257
258 /* NB: Although gd RGB values are ints, their max value is
259 * 255 (see the documentation for gdImageColorAllocate())
260 * -- perfect for 8-bit JPEG encoding (which is the norm)
261 */
262 #if BITS_IN_JSAMPLE == 8
263 row[jidx++] = im->red[idx];
264 row[jidx++] = im->green[idx];
265 row[jidx++] = im->blue[idx];
266 #elif BITS_IN_JSAMPLE == 12
267 row[jidx++] = im->red[idx] << 4;
268 row[jidx++] = im->green[idx] << 4;
269 row[jidx++] = im->blue[idx] << 4;
270 #else
271 #error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12
272 #endif
273 }
274
275 nlines = jpeg_write_scanlines (&cinfo, rowptr, 1);
276 if (nlines != 1) {
277 gd_error_ex(GD_WARNING, "gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1", nlines);
278 }
279 }
280 }
281
282 jpeg_finish_compress (&cinfo);
283 jpeg_destroy_compress (&cinfo);
284 gdFree (row);
285 }
286
gdImageCreateFromJpeg(FILE * inFile)287 gdImagePtr gdImageCreateFromJpeg (FILE * inFile)
288 {
289 return gdImageCreateFromJpegEx(inFile, 1);
290 }
291
gdImageCreateFromJpegEx(FILE * inFile,int ignore_warning)292 gdImagePtr gdImageCreateFromJpegEx (FILE * inFile, int ignore_warning)
293 {
294 gdImagePtr im;
295 gdIOCtx *in = gdNewFileCtx(inFile);
296 im = gdImageCreateFromJpegCtxEx(in, ignore_warning);
297 in->gd_free (in);
298
299 return im;
300 }
301
gdImageCreateFromJpegPtr(int size,void * data)302 gdImagePtr gdImageCreateFromJpegPtr (int size, void *data)
303 {
304 return gdImageCreateFromJpegPtrEx(size, data, 1);
305 }
306
gdImageCreateFromJpegPtrEx(int size,void * data,int ignore_warning)307 gdImagePtr gdImageCreateFromJpegPtrEx (int size, void *data, int ignore_warning)
308 {
309 gdImagePtr im;
310 gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
311 im = gdImageCreateFromJpegCtxEx(in, ignore_warning);
312 in->gd_free(in);
313
314 return im;
315 }
316
317 void jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile);
318
319 static int CMYKToRGB(int c, int m, int y, int k, int inverted);
320
321
322 /*
323 * Create a gd-format image from the JPEG-format INFILE. Returns the
324 * image, or NULL upon error.
325 */
gdImageCreateFromJpegCtx(gdIOCtx * infile)326 gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile)
327 {
328 return gdImageCreateFromJpegCtxEx(infile, 1);
329 }
330
gdImageCreateFromJpegCtxEx(gdIOCtx * infile,int ignore_warning)331 gdImagePtr gdImageCreateFromJpegCtxEx (gdIOCtx * infile, int ignore_warning)
332 {
333 struct jpeg_decompress_struct cinfo;
334 struct jpeg_error_mgr jerr;
335 jmpbuf_wrapper jmpbufw;
336 /* volatile so we can gdFree them after longjmp */
337 volatile JSAMPROW row = 0;
338 volatile gdImagePtr im = 0;
339 JSAMPROW rowptr[1];
340 unsigned int i, j;
341 int retval;
342 JDIMENSION nrows;
343 int channels = 3;
344 int inverted = 0;
345
346 memset (&cinfo, 0, sizeof (cinfo));
347 memset (&jerr, 0, sizeof (jerr));
348
349 jmpbufw.ignore_warning = ignore_warning;
350
351 cinfo.err = jpeg_std_error (&jerr);
352 cinfo.client_data = &jmpbufw;
353
354 cinfo.err->emit_message = (void (*)(j_common_ptr,int)) php_jpeg_emit_message;
355
356 if (setjmp (jmpbufw.jmpbuf) != 0) {
357 /* we're here courtesy of longjmp */
358 if (row) {
359 gdFree (row);
360 }
361 if (im) {
362 gdImageDestroy (im);
363 }
364 return 0;
365 }
366
367 cinfo.err->error_exit = fatal_jpeg_error;
368
369 jpeg_create_decompress (&cinfo);
370
371 jpeg_gdIOCtx_src (&cinfo, infile);
372
373 /* 2.0.22: save the APP14 marker to check for Adobe Photoshop CMYK files with inverted components. */
374 jpeg_save_markers(&cinfo, JPEG_APP0 + 14, 256);
375
376 retval = jpeg_read_header (&cinfo, TRUE);
377 if (retval != JPEG_HEADER_OK) {
378 gd_error_ex(GD_WARNING, "gd-jpeg: warning: jpeg_read_header returned %d, expected %d", retval, JPEG_HEADER_OK);
379 }
380
381 if (cinfo.image_height > INT_MAX) {
382 gd_error_ex(GD_WARNING, "gd-jpeg: warning: JPEG image height (%u) is greater than INT_MAX (%d) (and thus greater than gd can handle)", cinfo.image_height, INT_MAX);
383 }
384
385 if (cinfo.image_width > INT_MAX) {
386 gd_error_ex(GD_WARNING, "gd-jpeg: warning: JPEG image width (%u) is greater than INT_MAX (%d) (and thus greater than gd can handle)", cinfo.image_width, INT_MAX);
387 }
388
389 im = gdImageCreateTrueColor ((int) cinfo.image_width, (int) cinfo.image_height);
390 if (im == 0) {
391 gd_error("gd-jpeg error: cannot allocate gdImage struct");
392 goto error;
393 }
394
395 /* check if the resolution is specified */
396 switch (cinfo.density_unit) {
397 case 1:
398 im->res_x = cinfo.X_density;
399 im->res_y = cinfo.Y_density;
400 break;
401 case 2:
402 im->res_x = DPCM2DPI(cinfo.X_density);
403 im->res_y = DPCM2DPI(cinfo.Y_density);
404 break;
405 }
406
407 /* 2.0.22: very basic support for reading CMYK colorspace files. Nice for
408 * thumbnails but there's no support for fussy adjustment of the
409 * assumed properties of inks and paper. */
410 if ((cinfo.jpeg_color_space == JCS_CMYK) || (cinfo.jpeg_color_space == JCS_YCCK)) {
411 cinfo.out_color_space = JCS_CMYK;
412 } else {
413 cinfo.out_color_space = JCS_RGB;
414 }
415
416 if (jpeg_start_decompress (&cinfo) != TRUE) {
417 gd_error("gd-jpeg: warning: jpeg_start_decompress reports suspended data source");
418 }
419
420 /* REMOVED by TBB 2/12/01. This field of the structure is
421 * documented as private, and sure enough it's gone in the
422 * latest libjpeg, replaced by something else. Unfortunately
423 * there is still no right way to find out if the file was
424 * progressive or not; just declare your intent before you
425 * write one by calling gdImageInterlace(im, 1) yourself.
426 * After all, we're not really supposed to rework JPEGs and
427 * write them out again anyway. Lossy compression, remember?
428 */
429 #if 0
430 gdImageInterlace (im, cinfo.progressive_mode != 0);
431 #endif
432
433 if (cinfo.out_color_space == JCS_RGB) {
434 if (cinfo.output_components != 3) {
435 gd_error_ex(GD_WARNING, "gd-jpeg: error: JPEG color quantization request resulted in output_components == %d (expected 3 for RGB)", cinfo.output_components);
436 goto error;
437 }
438 channels = 3;
439 } else if (cinfo.out_color_space == JCS_CMYK) {
440 jpeg_saved_marker_ptr marker;
441 if (cinfo.output_components != 4) {
442 gd_error_ex(GD_WARNING, "gd-jpeg: error: JPEG color quantization request resulted in output_components == %d (expected 4 for CMYK)", cinfo.output_components);
443 goto error;
444 }
445 channels = 4;
446 marker = cinfo.marker_list;
447 while (marker) {
448 if ((marker->marker == (JPEG_APP0 + 14)) && (marker->data_length >= 12) && (!strncmp((const char *) marker->data, "Adobe", 5))) {
449 inverted = 1;
450 break;
451 }
452 marker = marker->next;
453 }
454 } else {
455 gd_error_ex(GD_WARNING, "gd-jpeg: error: unexpected colorspace.");
456 goto error;
457 }
458
459 #if BITS_IN_JSAMPLE == 12
460 gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit precision. This is mostly useless, because JPEGs on the web are 8-bit and such versions of the jpeg library won't read or write them. GD doesn't support these unusual images. Edit your jmorecfg.h file to specify the correct precision and completely 'make clean' and 'make install' libjpeg again. Sorry.");
461 goto error;
462 #endif /* BITS_IN_JSAMPLE == 12 */
463
464 row = safe_emalloc(cinfo.output_width * channels, sizeof(JSAMPLE), 0);
465 memset(row, 0, cinfo.output_width * channels * sizeof(JSAMPLE));
466 rowptr[0] = row;
467
468 if (cinfo.out_color_space == JCS_CMYK) {
469 for (i = 0; i < cinfo.output_height; i++) {
470 register JSAMPROW currow = row;
471 register int *tpix = im->tpixels[i];
472 nrows = jpeg_read_scanlines (&cinfo, rowptr, 1);
473 if (nrows != 1) {
474 gd_error_ex(GD_WARNING, "gd-jpeg: error: jpeg_read_scanlines returns %u, expected 1", nrows);
475 goto error;
476 }
477 for (j = 0; j < cinfo.output_width; j++, currow += 4, tpix++) {
478 *tpix = CMYKToRGB (currow[0], currow[1], currow[2], currow[3], inverted);
479 }
480 }
481 } else {
482 for (i = 0; i < cinfo.output_height; i++) {
483 register JSAMPROW currow = row;
484 register int *tpix = im->tpixels[i];
485 nrows = jpeg_read_scanlines (&cinfo, rowptr, 1);
486 if (nrows != 1) {
487 gd_error_ex(GD_WARNING, "gd-jpeg: error: jpeg_read_scanlines returns %u, expected 1", nrows);
488 goto error;
489 }
490 for (j = 0; j < cinfo.output_width; j++, currow += 3, tpix++) {
491 *tpix = gdTrueColor (currow[0], currow[1], currow[2]);
492 }
493 }
494 }
495
496 if (jpeg_finish_decompress (&cinfo) != TRUE) {
497 gd_error("gd-jpeg: warning: jpeg_finish_decompress reports suspended data source");
498 }
499 if (!ignore_warning) {
500 if (cinfo.err->num_warnings > 0) {
501 goto error;
502 }
503 }
504
505 jpeg_destroy_decompress (&cinfo);
506 gdFree (row);
507
508 return im;
509
510 error:
511 jpeg_destroy_decompress (&cinfo);
512 if (row) {
513 gdFree (row);
514 }
515 if (im) {
516 gdImageDestroy (im);
517 }
518 return 0;
519 }
520
521 /* A very basic conversion approach, TBB */
CMYKToRGB(int c,int m,int y,int k,int inverted)522 static int CMYKToRGB(int c, int m, int y, int k, int inverted)
523 {
524 if (inverted) {
525 c = 255 - c;
526 m = 255 - m;
527 y = 255 - y;
528 k = 255 - k;
529 }
530 return gdTrueColor((255 - c) * (255 - k) / 255, (255 - m) * (255 - k) / 255, (255 - y) * (255 - k) / 255);
531 }
532
533 /*
534 * gdIOCtx JPEG data sources and sinks, T. Boutell
535 * almost a simple global replace from T. Lane's stdio versions.
536 *
537 */
538
539 /* Different versions of libjpeg use either 'jboolean' or 'boolean', and
540 some platforms define 'boolean', and so forth. Deal with this
541 madness by typedeffing 'safeboolean' to 'boolean' if HAVE_BOOLEAN
542 is already set, because this is the test that libjpeg uses.
543 Otherwise, typedef it to int, because that's what libjpeg does
544 if HAVE_BOOLEAN is not defined. -TBB */
545
546 #ifdef HAVE_BOOLEAN
547 typedef boolean safeboolean;
548 #else
549 typedef int safeboolean;
550 #endif /* HAVE_BOOLEAN */
551
552 /* Expanded data source object for gdIOCtx input */
553
554 typedef struct
555 {
556 struct jpeg_source_mgr pub; /* public fields */
557
558 gdIOCtx *infile; /* source stream */
559 unsigned char *buffer; /* start of buffer */
560 safeboolean start_of_file; /* have we gotten any data yet? */
561 } my_source_mgr;
562
563 typedef my_source_mgr *my_src_ptr;
564
565 #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
566
567 /*
568 * Initialize source --- called by jpeg_read_header
569 * before any data is actually read.
570 */
571
init_source(j_decompress_ptr cinfo)572 void init_source (j_decompress_ptr cinfo)
573 {
574 my_src_ptr src = (my_src_ptr) cinfo->src;
575
576 /* We reset the empty-input-file flag for each image,
577 * but we don't clear the input buffer.
578 * This is correct behavior for reading a series of images from one source.
579 */
580 src->start_of_file = TRUE;
581 }
582
583
584 /*
585 * Fill the input buffer --- called whenever buffer is emptied.
586 *
587 * In typical applications, this should read fresh data into the buffer
588 * (ignoring the current state of next_input_byte & bytes_in_buffer),
589 * reset the pointer & count to the start of the buffer, and return TRUE
590 * indicating that the buffer has been reloaded. It is not necessary to
591 * fill the buffer entirely, only to obtain at least one more byte.
592 *
593 * There is no such thing as an EOF return. If the end of the file has been
594 * reached, the routine has a choice of ERREXIT() or inserting fake data into
595 * the buffer. In most cases, generating a warning message and inserting a
596 * fake EOI marker is the best course of action --- this will allow the
597 * decompressor to output however much of the image is there. However,
598 * the resulting error message is misleading if the real problem is an empty
599 * input file, so we handle that case specially.
600 *
601 * In applications that need to be able to suspend compression due to input
602 * not being available yet, a FALSE return indicates that no more data can be
603 * obtained right now, but more may be forthcoming later. In this situation,
604 * the decompressor will return to its caller (with an indication of the
605 * number of scanlines it has read, if any). The application should resume
606 * decompression after it has loaded more data into the input buffer. Note
607 * that there are substantial restrictions on the use of suspension --- see
608 * the documentation.
609 *
610 * When suspending, the decompressor will back up to a convenient restart point
611 * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
612 * indicate where the restart point will be if the current call returns FALSE.
613 * Data beyond this point must be rescanned after resumption, so move it to
614 * the front of the buffer rather than discarding it.
615 */
616
617 #define END_JPEG_SEQUENCE "\r\n[*]--:END JPEG:--[*]\r\n"
618
fill_input_buffer(j_decompress_ptr cinfo)619 safeboolean fill_input_buffer (j_decompress_ptr cinfo)
620 {
621 my_src_ptr src = (my_src_ptr) cinfo->src;
622 /* 2.0.12: signed size. Thanks to Geert Jansen */
623 ssize_t nbytes = 0;
624
625 /* ssize_t got; */
626 /* char *s; */
627 memset(src->buffer, 0, INPUT_BUF_SIZE);
628
629 while (nbytes < INPUT_BUF_SIZE) {
630 int got = gdGetBuf(src->buffer + nbytes, INPUT_BUF_SIZE - nbytes, src->infile);
631
632 if (got == EOF || got == 0) {
633 /* EOF or error. If we got any data, don't worry about it. If we didn't, then this is unexpected. */
634 if (!nbytes) {
635 nbytes = -1;
636 }
637 break;
638 }
639 nbytes += got;
640 }
641
642 if (nbytes <= 0) {
643 if (src->start_of_file) { /* Treat empty input file as fatal error */
644 ERREXIT (cinfo, JERR_INPUT_EMPTY);
645 }
646 WARNMS (cinfo, JWRN_JPEG_EOF);
647 /* Insert a fake EOI marker */
648 src->buffer[0] = (unsigned char) 0xFF;
649 src->buffer[1] = (unsigned char) JPEG_EOI;
650 nbytes = 2;
651 }
652
653 src->pub.next_input_byte = src->buffer;
654 src->pub.bytes_in_buffer = nbytes;
655 src->start_of_file = FALSE;
656
657 return TRUE;
658 }
659
660
661 /*
662 * Skip data --- used to skip over a potentially large amount of
663 * uninteresting data (such as an APPn marker).
664 *
665 * Writers of suspendable-input applications must note that skip_input_data
666 * is not granted the right to give a suspension return. If the skip extends
667 * beyond the data currently in the buffer, the buffer can be marked empty so
668 * that the next read will cause a fill_input_buffer call that can suspend.
669 * Arranging for additional bytes to be discarded before reloading the input
670 * buffer is the application writer's problem.
671 */
672
skip_input_data(j_decompress_ptr cinfo,long num_bytes)673 void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
674 {
675 my_src_ptr src = (my_src_ptr) cinfo->src;
676
677 /* Just a dumb implementation for now. Not clear that being smart is worth
678 * any trouble anyway --- large skips are infrequent.
679 */
680 if (num_bytes > 0) {
681 while (num_bytes > (long) src->pub.bytes_in_buffer) {
682 num_bytes -= (long) src->pub.bytes_in_buffer;
683 (void) fill_input_buffer (cinfo);
684 /* note we assume that fill_input_buffer will never return FALSE,
685 * so suspension need not be handled.
686 */
687 }
688 src->pub.next_input_byte += (size_t) num_bytes;
689 src->pub.bytes_in_buffer -= (size_t) num_bytes;
690 }
691 }
692
693
694 /*
695 * An additional method that can be provided by data source modules is the
696 * resync_to_restart method for error recovery in the presence of RST markers.
697 * For the moment, this source module just uses the default resync method
698 * provided by the JPEG library. That method assumes that no backtracking
699 * is possible.
700 */
701
702
703 /*
704 * Terminate source --- called by jpeg_finish_decompress
705 * after all data has been read. Often a no-op.
706 *
707 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
708 * application must deal with any cleanup that should happen even
709 * for error exit.
710 */
711
term_source(j_decompress_ptr cinfo)712 void term_source (j_decompress_ptr cinfo)
713 {
714 #if 0
715 * never used */
716 my_src_ptr src = (my_src_ptr) cinfo->src;
717 #endif
718 }
719
720
721 /*
722 * Prepare for input from a gdIOCtx stream.
723 * The caller must have already opened the stream, and is responsible
724 * for closing it after finishing decompression.
725 */
726
jpeg_gdIOCtx_src(j_decompress_ptr cinfo,gdIOCtx * infile)727 void jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile)
728 {
729 my_src_ptr src;
730
731 /* The source object and input buffer are made permanent so that a series
732 * of JPEG images can be read from the same file by calling jpeg_gdIOCtx_src
733 * only before the first one. (If we discarded the buffer at the end of
734 * one image, we'd likely lose the start of the next one.)
735 * This makes it unsafe to use this manager and a different source
736 * manager serially with the same JPEG object. Caveat programmer.
737 */
738 if (cinfo->src == NULL) { /* first time for this JPEG object? */
739 cinfo->src = (struct jpeg_source_mgr *)
740 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof (my_source_mgr));
741 src = (my_src_ptr) cinfo->src;
742 src->buffer = (unsigned char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * sizeof (unsigned char));
743
744 }
745
746 src = (my_src_ptr) cinfo->src;
747 src->pub.init_source = init_source;
748 src->pub.fill_input_buffer = fill_input_buffer;
749 src->pub.skip_input_data = skip_input_data;
750 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
751 src->pub.term_source = term_source;
752 src->infile = infile;
753 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
754 src->pub.next_input_byte = NULL; /* until buffer loaded */
755 }
756
757 /* Expanded data destination object for stdio output */
758
759 typedef struct
760 {
761 struct jpeg_destination_mgr pub; /* public fields */
762 gdIOCtx *outfile; /* target stream */
763 unsigned char *buffer; /* start of buffer */
764 } my_destination_mgr;
765
766 typedef my_destination_mgr *my_dest_ptr;
767
768 #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
769
770 /*
771 * Initialize destination --- called by jpeg_start_compress
772 * before any data is actually written.
773 */
774
init_destination(j_compress_ptr cinfo)775 void init_destination (j_compress_ptr cinfo)
776 {
777 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
778
779 /* Allocate the output buffer --- it will be released when done with image */
780 dest->buffer = (unsigned char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof (unsigned char));
781
782 dest->pub.next_output_byte = dest->buffer;
783 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
784 }
785
786
787 /*
788 * Empty the output buffer --- called whenever buffer fills up.
789 *
790 * In typical applications, this should write the entire output buffer
791 * (ignoring the current state of next_output_byte & free_in_buffer),
792 * reset the pointer & count to the start of the buffer, and return TRUE
793 * indicating that the buffer has been dumped.
794 *
795 * In applications that need to be able to suspend compression due to output
796 * overrun, a FALSE return indicates that the buffer cannot be emptied now.
797 * In this situation, the compressor will return to its caller (possibly with
798 * an indication that it has not accepted all the supplied scanlines). The
799 * application should resume compression after it has made more room in the
800 * output buffer. Note that there are substantial restrictions on the use of
801 * suspension --- see the documentation.
802 *
803 * When suspending, the compressor will back up to a convenient restart point
804 * (typically the start of the current MCU). next_output_byte & free_in_buffer
805 * indicate where the restart point will be if the current call returns FALSE.
806 * Data beyond this point will be regenerated after resumption, so do not
807 * write it out when emptying the buffer externally.
808 */
809
empty_output_buffer(j_compress_ptr cinfo)810 safeboolean empty_output_buffer (j_compress_ptr cinfo)
811 {
812 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
813
814 if (gdPutBuf (dest->buffer, OUTPUT_BUF_SIZE, dest->outfile) != (size_t) OUTPUT_BUF_SIZE) {
815 ERREXIT (cinfo, JERR_FILE_WRITE);
816 }
817
818 dest->pub.next_output_byte = dest->buffer;
819 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
820
821 return TRUE;
822 }
823
824
825 /*
826 * Terminate destination --- called by jpeg_finish_compress
827 * after all data has been written. Usually needs to flush buffer.
828 *
829 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
830 * application must deal with any cleanup that should happen even
831 * for error exit.
832 */
833
term_destination(j_compress_ptr cinfo)834 void term_destination (j_compress_ptr cinfo)
835 {
836 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
837 size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
838
839 /* Write any data remaining in the buffer */
840 if (datacount > 0 && ((size_t)gdPutBuf (dest->buffer, datacount, dest->outfile) != datacount)) {
841 ERREXIT (cinfo, JERR_FILE_WRITE);
842 }
843 }
844
845
846 /*
847 * Prepare for output to a stdio stream.
848 * The caller must have already opened the stream, and is responsible
849 * for closing it after finishing compression.
850 */
851
jpeg_gdIOCtx_dest(j_compress_ptr cinfo,gdIOCtx * outfile)852 void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile)
853 {
854 my_dest_ptr dest;
855
856 /* The destination object is made permanent so that multiple JPEG images
857 * can be written to the same file without re-executing jpeg_stdio_dest.
858 * This makes it dangerous to use this manager and a different destination
859 * manager serially with the same JPEG object, because their private object
860 * sizes may be different. Caveat programmer.
861 */
862 if (cinfo->dest == NULL) { /* first time for this JPEG object? */
863 cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof (my_destination_mgr));
864 }
865
866 dest = (my_dest_ptr) cinfo->dest;
867 dest->pub.init_destination = init_destination;
868 dest->pub.empty_output_buffer = empty_output_buffer;
869 dest->pub.term_destination = term_destination;
870 dest->outfile = outfile;
871 }
872
873 #endif /* HAVE_JPEG */
874