root/ext/gd/libgd/gd_jpeg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_jpeg_emit_message
  2. fatal_jpeg_error
  3. gdJpegGetVersionInt
  4. gdJpegGetVersionString
  5. gdImageJpeg
  6. gdImageJpegPtr
  7. gdImageJpegCtx
  8. gdImageCreateFromJpeg
  9. gdImageCreateFromJpegEx
  10. gdImageCreateFromJpegPtr
  11. gdImageCreateFromJpegPtrEx
  12. gdImageCreateFromJpegCtx
  13. gdImageCreateFromJpegCtxEx
  14. CMYKToRGB
  15. init_source
  16. fill_input_buffer
  17. skip_input_data
  18. term_source
  19. jpeg_gdIOCtx_src
  20. init_destination
  21. empty_output_buffer
  22. term_destination
  23. jpeg_gdIOCtx_dest

   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 
  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 */
  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 
 105 int gdJpegGetVersionInt()
 106 {
 107         return JPEG_LIB_VERSION;
 108 }
 109 
 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 
 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 
 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 
 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 
 276 gdImagePtr gdImageCreateFromJpeg (FILE * inFile)
 277 {
 278         return gdImageCreateFromJpegEx(inFile, 1);
 279 }
 280 
 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 
 291 gdImagePtr gdImageCreateFromJpegPtr (int size, void *data)
 292 {
 293         return gdImageCreateFromJpegPtrEx(size, data, 1);
 294 }
 295 
 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  */
 315 gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile)
 316 {
 317         return gdImageCreateFromJpegCtxEx(infile, 1);
 318 }
 319 
 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 */
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 */

/* [<][>][^][v][top][bottom][index][help] */