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