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