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