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