Back to index

php5  5.3.10
gd_jpeg.c
Go to the documentation of this file.
00001 /*
00002  * gd_jpeg.c: Read and write JPEG (JFIF) format image files using the
00003  * gd graphics library (http://www.boutell.com/gd/).
00004  *
00005  * This software is based in part on the work of the Independent JPEG
00006  * Group.  For more information on the IJG JPEG software (and JPEG
00007  * documentation, etc.), see ftp://ftp.uu.net/graphics/jpeg/.
00008  *
00009  * NOTE: IJG 12-bit JSAMPLE (BITS_IN_JSAMPLE == 12) mode is not
00010  * supported at all on read in gd 2.0, and is not supported on write
00011  * except for palette images, which is sort of pointless (TBB). Even that
00012  * has never been tested according to DB.
00013  *
00014  * Copyright 2000 Doug Becker, mailto:thebeckers@home.com
00015  *
00016  * Modification 4/18/00 TBB: JPEG_DEBUG rather than just DEBUG,
00017  * so VC++ builds don't spew to standard output, causing
00018  * major CGI brain damage
00019  *
00020  * 2.0.10: more efficient gdImageCreateFromJpegCtx, thanks to
00021  * Christian Aberger
00022  */
00023 
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <setjmp.h>
00027 #include <limits.h>
00028 #include <string.h>
00029 
00030 #include "gd.h"
00031 /* TBB: move this up so include files are not brought in */
00032 /* JCE: arrange HAVE_LIBJPEG so that it can be set in gd.h */
00033 #ifdef HAVE_LIBJPEG
00034 #include "gdhelpers.h"
00035 #undef HAVE_STDLIB_H
00036 
00037 /* 1.8.1: remove dependency on jinclude.h */
00038 #include "jpeglib.h"
00039 #include "jerror.h"
00040 
00041 static const char *const GD_JPEG_VERSION = "1.0";
00042 
00043 typedef struct _jmpbuf_wrapper
00044 {
00045        jmp_buf jmpbuf;
00046        int ignore_warning;
00047 } jmpbuf_wrapper;
00048 
00049 static long php_jpeg_emit_message(j_common_ptr jpeg_info, int level)
00050 {
00051        char message[JMSG_LENGTH_MAX];
00052        jmpbuf_wrapper *jmpbufw;
00053        int ignore_warning = 0;
00054 
00055        jmpbufw = (jmpbuf_wrapper *) jpeg_info->client_data;
00056 
00057        if (jmpbufw != 0) {
00058               ignore_warning = jmpbufw->ignore_warning;
00059        }
00060 
00061        (jpeg_info->err->format_message)(jpeg_info,message);
00062 
00063        /* It is a warning message */
00064        if (level < 0) {
00065               /* display only the 1st warning, as would do a default libjpeg
00066                * unless strace_level >= 3
00067                */
00068               if ((jpeg_info->err->num_warnings == 0) || (jpeg_info->err->trace_level >= 3)) {
00069                      php_gd_error_ex(ignore_warning ? E_NOTICE : E_WARNING, "gd-jpeg, libjpeg: recoverable error: %s\n", message);
00070               }
00071 
00072               jpeg_info->err->num_warnings++;
00073        } else {
00074               /* strace msg, Show it if trace_level >= level. */
00075               if (jpeg_info->err->trace_level >= level) {
00076                      php_gd_error_ex(E_NOTICE, "gd-jpeg, libjpeg: strace message: %s\n", message);
00077               }
00078        }
00079        return 1;
00080 }
00081 
00082 
00083 
00084 /* Called by the IJG JPEG library upon encountering a fatal error */
00085 static void fatal_jpeg_error (j_common_ptr cinfo)
00086 {
00087        jmpbuf_wrapper *jmpbufw;
00088 
00089        php_gd_error("gd-jpeg: JPEG library reports unrecoverable error: ");
00090        (*cinfo->err->output_message) (cinfo);
00091 
00092        jmpbufw = (jmpbuf_wrapper *) cinfo->client_data;
00093        jpeg_destroy (cinfo);
00094 
00095        if (jmpbufw != 0) {
00096               longjmp (jmpbufw->jmpbuf, 1);
00097               php_gd_error_ex(E_ERROR, "gd-jpeg: EXTREMELY fatal error: longjmp returned control; terminating");
00098        } else {
00099               php_gd_error_ex(E_ERROR, "gd-jpeg: EXTREMELY fatal error: jmpbuf unrecoverable; terminating");
00100        }
00101 
00102        exit (99);
00103 }
00104 
00105 int gdJpegGetVersionInt()
00106 {
00107        return JPEG_LIB_VERSION;
00108 }
00109 
00110 const char * gdJpegGetVersionString()
00111 {
00112        switch(JPEG_LIB_VERSION) {
00113               case 62:
00114                      return "6b";
00115                      break;
00116 
00117               case 70:
00118                      return "7";
00119                      break;
00120 
00121               case 80:
00122                      return "8";
00123                      break;
00124 
00125               default:
00126                      return "unknown";
00127        }
00128 }
00129 
00130 
00131 /*
00132  * Write IM to OUTFILE as a JFIF-formatted JPEG image, using quality
00133  * QUALITY.  If QUALITY is in the range 0-100, increasing values
00134  * represent higher quality but also larger image size.  If QUALITY is
00135  * negative, the IJG JPEG library's default quality is used (which
00136  * should be near optimal for many applications).  See the IJG JPEG
00137  * library documentation for more details.
00138  */
00139 
00140 void gdImageJpeg (gdImagePtr im, FILE * outFile, int quality)
00141 {
00142        gdIOCtx *out = gdNewFileCtx (outFile);
00143        gdImageJpegCtx (im, out, quality);
00144        out->gd_free (out);
00145 }
00146 
00147 void *gdImageJpegPtr (gdImagePtr im, int *size, int quality)
00148 {
00149        void *rv;
00150        gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
00151        gdImageJpegCtx (im, out, quality);
00152        rv = gdDPExtractData (out, size);
00153        out->gd_free (out);
00154 
00155        return rv;
00156 }
00157 
00158 void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile);
00159 
00160 void gdImageJpegCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
00161 {
00162        struct jpeg_compress_struct cinfo;
00163        struct jpeg_error_mgr jerr;
00164        int i, j, jidx;
00165        /* volatile so we can gdFree it on return from longjmp */
00166        volatile JSAMPROW row = 0;
00167        JSAMPROW rowptr[1];
00168        jmpbuf_wrapper jmpbufw;
00169        JDIMENSION nlines;
00170        char comment[255];
00171 
00172        memset (&cinfo, 0, sizeof (cinfo));
00173        memset (&jerr, 0, sizeof (jerr));
00174 
00175        cinfo.err = jpeg_std_error (&jerr);
00176        cinfo.client_data = &jmpbufw;
00177        if (setjmp (jmpbufw.jmpbuf) != 0) {
00178               /* we're here courtesy of longjmp */
00179               if (row) {
00180                      gdFree (row);
00181               }
00182               return;
00183        }
00184 
00185        cinfo.err->error_exit = fatal_jpeg_error;
00186 
00187        jpeg_create_compress (&cinfo);
00188 
00189        cinfo.image_width = im->sx;
00190        cinfo.image_height = im->sy;
00191        cinfo.input_components = 3; /* # of color components per pixel */
00192        cinfo.in_color_space = JCS_RGB;    /* colorspace of input image */
00193        jpeg_set_defaults (&cinfo);
00194        if (quality >= 0) {
00195               jpeg_set_quality (&cinfo, quality, TRUE);
00196        }
00197 
00198        /* If user requests interlace, translate that to progressive JPEG */
00199        if (gdImageGetInterlaced (im)) {
00200               jpeg_simple_progression (&cinfo);
00201        }
00202 
00203        jpeg_gdIOCtx_dest (&cinfo, outfile);
00204 
00205        row = (JSAMPROW) safe_emalloc(cinfo.image_width * cinfo.input_components, sizeof(JSAMPLE), 0);
00206        memset(row, 0, cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE));
00207        rowptr[0] = row;
00208 
00209        jpeg_start_compress (&cinfo, TRUE);
00210 
00211        if (quality >= 0) {
00212               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);
00213        } else {
00214               snprintf(comment, sizeof(comment)-1, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d), default quality\n", GD_JPEG_VERSION, JPEG_LIB_VERSION);
00215        }
00216        jpeg_write_marker (&cinfo, JPEG_COM, (unsigned char *) comment, (unsigned int) strlen (comment));
00217        if (im->trueColor) {
00218 
00219 #if BITS_IN_JSAMPLE == 12
00220               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");
00221               goto error;
00222 #endif /* BITS_IN_JSAMPLE == 12 */
00223 
00224               for (i = 0; i < im->sy; i++) {
00225                      for (jidx = 0, j = 0; j < im->sx; j++) {
00226                             int val = im->tpixels[i][j];
00227 
00228                             row[jidx++] = gdTrueColorGetRed (val);
00229                             row[jidx++] = gdTrueColorGetGreen (val);
00230                             row[jidx++] = gdTrueColorGetBlue (val);
00231                      }
00232 
00233                      nlines = jpeg_write_scanlines (&cinfo, rowptr, 1);
00234                      if (nlines != 1) {
00235                             php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1", nlines);
00236                      }
00237               }
00238        } else {
00239               for (i = 0; i < im->sy; i++) {
00240                      for (jidx = 0, j = 0; j < im->sx; j++) {
00241                             int idx = im->pixels[i][j];
00242 
00243                             /* NB: Although gd RGB values are ints, their max value is
00244                              * 255 (see the documentation for gdImageColorAllocate())
00245                              * -- perfect for 8-bit JPEG encoding (which is the norm)
00246                              */
00247 #if BITS_IN_JSAMPLE == 8
00248                             row[jidx++] = im->red[idx];
00249                             row[jidx++] = im->green[idx];
00250                             row[jidx++] = im->blue[idx];
00251 #elif BITS_IN_JSAMPLE == 12
00252                             row[jidx++] = im->red[idx] << 4;
00253                             row[jidx++] = im->green[idx] << 4;
00254                             row[jidx++] = im->blue[idx] << 4;
00255 #else
00256 #error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12
00257 #endif
00258                      }
00259 
00260                      nlines = jpeg_write_scanlines (&cinfo, rowptr, 1);
00261                      if (nlines != 1) {
00262                             php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1", nlines);
00263                      }
00264               }
00265        }
00266 
00267        jpeg_finish_compress (&cinfo);
00268        jpeg_destroy_compress (&cinfo);
00269        gdFree (row);
00270 }
00271 
00272 gdImagePtr gdImageCreateFromJpeg (FILE * inFile, int ignore_warning)
00273 {
00274        gdImagePtr im;
00275        gdIOCtx *in = gdNewFileCtx(inFile);
00276        im = gdImageCreateFromJpegCtx(in, ignore_warning);
00277        in->gd_free (in);
00278 
00279        return im;
00280 }
00281 
00282 gdImagePtr gdImageCreateFromJpegPtr (int size, void *data, int ignore_warning)
00283 {
00284        gdImagePtr im;
00285        gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
00286        im = gdImageCreateFromJpegCtx(in, ignore_warning);
00287        in->gd_free(in);
00288 
00289        return im;
00290 }
00291 
00292 void jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile);
00293 
00294 static int CMYKToRGB(int c, int m, int y, int k, int inverted);
00295 
00296 
00297 /*
00298  * Create a gd-format image from the JPEG-format INFILE.  Returns the
00299  * image, or NULL upon error.
00300  */
00301 gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile, int ignore_warning)
00302 {
00303        struct jpeg_decompress_struct cinfo;
00304        struct jpeg_error_mgr jerr;
00305        jmpbuf_wrapper jmpbufw;
00306        /* volatile so we can gdFree them after longjmp */
00307        volatile JSAMPROW row = 0;
00308        volatile gdImagePtr im = 0;
00309        JSAMPROW rowptr[1];
00310        unsigned int i, j;
00311        int retval;
00312        JDIMENSION nrows;
00313        int channels = 3;
00314        int inverted = 0;
00315 
00316        memset (&cinfo, 0, sizeof (cinfo));
00317        memset (&jerr, 0, sizeof (jerr));
00318 
00319        jmpbufw.ignore_warning = ignore_warning;
00320 
00321        cinfo.err = jpeg_std_error (&jerr);
00322        cinfo.client_data = &jmpbufw;
00323 
00324        cinfo.err->emit_message = (void (*)(j_common_ptr,int)) php_jpeg_emit_message;
00325 
00326        if (setjmp (jmpbufw.jmpbuf) != 0) {
00327               /* we're here courtesy of longjmp */
00328               if (row) {
00329                      gdFree (row);
00330               }
00331               if (im) {
00332                      gdImageDestroy (im);
00333               }
00334               return 0;
00335        }
00336 
00337        cinfo.err->error_exit = fatal_jpeg_error;
00338 
00339        jpeg_create_decompress (&cinfo);
00340 
00341        jpeg_gdIOCtx_src (&cinfo, infile);
00342 
00343        /* 2.0.22: save the APP14 marker to check for Adobe Photoshop CMYK files with inverted components. */
00344        jpeg_save_markers(&cinfo, JPEG_APP0 + 14, 256);
00345 
00346        retval = jpeg_read_header (&cinfo, TRUE);
00347        if (retval != JPEG_HEADER_OK) {
00348               php_gd_error_ex(E_WARNING, "gd-jpeg: warning: jpeg_read_header returned %d, expected %d", retval, JPEG_HEADER_OK);
00349        }
00350 
00351        if (cinfo.image_height > INT_MAX) {
00352               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);
00353        }
00354 
00355        if (cinfo.image_width > INT_MAX) {
00356               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);
00357        }
00358 
00359        im = gdImageCreateTrueColor ((int) cinfo.image_width, (int) cinfo.image_height);
00360        if (im == 0) {
00361               php_gd_error("gd-jpeg error: cannot allocate gdImage struct");
00362               goto error;
00363        }
00364 
00365        /* 2.0.22: very basic support for reading CMYK colorspace files. Nice for
00366         * thumbnails but there's no support for fussy adjustment of the
00367         * assumed properties of inks and paper. */
00368        if ((cinfo.jpeg_color_space == JCS_CMYK) || (cinfo.jpeg_color_space == JCS_YCCK)) {
00369               cinfo.out_color_space = JCS_CMYK;
00370        } else {
00371               cinfo.out_color_space = JCS_RGB;
00372        }
00373 
00374        if (jpeg_start_decompress (&cinfo) != TRUE) {
00375               php_gd_error("gd-jpeg: warning: jpeg_start_decompress reports suspended data source");
00376        }
00377 
00378        /* REMOVED by TBB 2/12/01. This field of the structure is
00379         * documented as private, and sure enough it's gone in the
00380         * latest libjpeg, replaced by something else. Unfortunately
00381         * there is still no right way to find out if the file was
00382         * progressive or not; just declare your intent before you
00383         * write one by calling gdImageInterlace(im, 1) yourself.
00384         * After all, we're not really supposed to rework JPEGs and
00385         * write them out again anyway. Lossy compression, remember?
00386         */
00387 #if 0
00388   gdImageInterlace (im, cinfo.progressive_mode != 0);
00389 #endif
00390 
00391        if (cinfo.out_color_space == JCS_RGB) {
00392               if (cinfo.output_components != 3) {
00393                      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);
00394                      goto error;
00395               }
00396               channels = 3;
00397        } else if (cinfo.out_color_space == JCS_CMYK) {
00398               jpeg_saved_marker_ptr marker;
00399               if (cinfo.output_components != 4)  {
00400                      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);
00401                      goto error;
00402               }
00403               channels = 4;
00404               marker = cinfo.marker_list;
00405               while (marker) {
00406                      if ((marker->marker == (JPEG_APP0 + 14)) && (marker->data_length >= 12) && (!strncmp((const char *) marker->data, "Adobe", 5))) {
00407                             inverted = 1;
00408                             break;
00409                      }
00410                      marker = marker->next;
00411               }
00412        } else {
00413               php_gd_error_ex(E_WARNING, "gd-jpeg: error: unexpected colorspace.");
00414               goto error;
00415        }
00416 
00417 #if BITS_IN_JSAMPLE == 12
00418        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.");
00419        goto error;
00420 #endif /* BITS_IN_JSAMPLE == 12 */
00421 
00422        row = safe_emalloc(cinfo.output_width * channels, sizeof(JSAMPLE), 0);
00423        memset(row, 0, cinfo.output_width * channels * sizeof(JSAMPLE));
00424        rowptr[0] = row;
00425 
00426        if (cinfo.out_color_space == JCS_CMYK) {
00427               for (i = 0; i < cinfo.output_height; i++) {
00428                      register JSAMPROW currow = row;
00429                      register int *tpix = im->tpixels[i];
00430                      nrows = jpeg_read_scanlines (&cinfo, rowptr, 1);
00431                      if (nrows != 1) {
00432                             php_gd_error_ex(E_WARNING, "gd-jpeg: error: jpeg_read_scanlines returns %u, expected 1", nrows);
00433                             goto error;
00434                      }
00435                      for (j = 0; j < cinfo.output_width; j++, currow += 4, tpix++) {
00436                             *tpix = CMYKToRGB (currow[0], currow[1], currow[2], currow[3], inverted);
00437                      }
00438               }
00439        } else {
00440               for (i = 0; i < cinfo.output_height; i++) {
00441                      register JSAMPROW currow = row;
00442                      register int *tpix = im->tpixels[i];
00443                      nrows = jpeg_read_scanlines (&cinfo, rowptr, 1);
00444                      if (nrows != 1) {
00445                             php_gd_error_ex(E_WARNING, "gd-jpeg: error: jpeg_read_scanlines returns %u, expected 1", nrows);
00446                             goto error;
00447                      }
00448                      for (j = 0; j < cinfo.output_width; j++, currow += 3, tpix++) {
00449                             *tpix = gdTrueColor (currow[0], currow[1], currow[2]);
00450                      }
00451               }
00452        } 
00453 
00454        if (jpeg_finish_decompress (&cinfo) != TRUE) {
00455               php_gd_error("gd-jpeg: warning: jpeg_finish_decompress reports suspended data source");
00456        }
00457        if (!ignore_warning) {
00458               if (cinfo.err->num_warnings > 0) {
00459                      goto error;
00460               }
00461        }
00462        
00463        jpeg_destroy_decompress (&cinfo);
00464        gdFree (row);
00465 
00466        return im;
00467 
00468 error:
00469        jpeg_destroy_decompress (&cinfo);
00470        if (row) {
00471               gdFree (row);
00472        }
00473        if (im) {
00474               gdImageDestroy (im);
00475        }
00476        return 0;
00477 }
00478 
00479 /* A very basic conversion approach, TBB */
00480 static int CMYKToRGB(int c, int m, int y, int k, int inverted)
00481 {
00482        if (inverted) {
00483               c = 255 - c;
00484               m = 255 - m;
00485               y = 255 - y;
00486               k = 255 - k;
00487        }
00488        return gdTrueColor((255 - c) * (255 - k) / 255, (255 - m) * (255 - k) / 255, (255 - y) * (255 - k) / 255);
00489 }
00490 
00491 /*
00492  * gdIOCtx JPEG data sources and sinks, T. Boutell
00493  * almost a simple global replace from T. Lane's stdio versions.
00494  *
00495  */
00496 
00497 /* Different versions of libjpeg use either 'jboolean' or 'boolean', and
00498    some platforms define 'boolean', and so forth. Deal with this
00499    madness by typedeffing 'safeboolean' to 'boolean' if HAVE_BOOLEAN
00500    is already set, because this is the test that libjpeg uses.
00501    Otherwise, typedef it to int, because that's what libjpeg does
00502    if HAVE_BOOLEAN is not defined. -TBB */
00503 
00504 #ifdef HAVE_BOOLEAN
00505 typedef boolean safeboolean;
00506 #else
00507 typedef int safeboolean;
00508 #endif /* HAVE_BOOLEAN */
00509 
00510 /* Expanded data source object for gdIOCtx input */
00511 
00512 typedef struct
00513 {
00514        struct jpeg_source_mgr pub; /* public fields */
00515 
00516        gdIOCtx *infile;            /* source stream */
00517        unsigned char *buffer;      /* start of buffer */
00518        safeboolean start_of_file;  /* have we gotten any data yet? */
00519 } my_source_mgr;
00520 
00521 typedef my_source_mgr *my_src_ptr;
00522 
00523 #define INPUT_BUF_SIZE  4096       /* choose an efficiently fread'able size */
00524 
00525 /*
00526  * Initialize source --- called by jpeg_read_header
00527  * before any data is actually read.
00528  */
00529 
00530 void init_source (j_decompress_ptr cinfo)
00531 {
00532        my_src_ptr src = (my_src_ptr) cinfo->src;
00533 
00534        /* We reset the empty-input-file flag for each image,
00535         * but we don't clear the input buffer.
00536         * This is correct behavior for reading a series of images from one source.
00537         */
00538        src->start_of_file = TRUE;
00539 }
00540 
00541 
00542 /*
00543  * Fill the input buffer --- called whenever buffer is emptied.
00544  *
00545  * In typical applications, this should read fresh data into the buffer
00546  * (ignoring the current state of next_input_byte & bytes_in_buffer),
00547  * reset the pointer & count to the start of the buffer, and return TRUE
00548  * indicating that the buffer has been reloaded.  It is not necessary to
00549  * fill the buffer entirely, only to obtain at least one more byte.
00550  *
00551  * There is no such thing as an EOF return.  If the end of the file has been
00552  * reached, the routine has a choice of ERREXIT() or inserting fake data into
00553  * the buffer.  In most cases, generating a warning message and inserting a
00554  * fake EOI marker is the best course of action --- this will allow the
00555  * decompressor to output however much of the image is there.  However,
00556  * the resulting error message is misleading if the real problem is an empty
00557  * input file, so we handle that case specially.
00558  *
00559  * In applications that need to be able to suspend compression due to input
00560  * not being available yet, a FALSE return indicates that no more data can be
00561  * obtained right now, but more may be forthcoming later.  In this situation,
00562  * the decompressor will return to its caller (with an indication of the
00563  * number of scanlines it has read, if any).  The application should resume
00564  * decompression after it has loaded more data into the input buffer.  Note
00565  * that there are substantial restrictions on the use of suspension --- see
00566  * the documentation.
00567  *
00568  * When suspending, the decompressor will back up to a convenient restart point
00569  * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
00570  * indicate where the restart point will be if the current call returns FALSE.
00571  * Data beyond this point must be rescanned after resumption, so move it to
00572  * the front of the buffer rather than discarding it.
00573  */
00574 
00575 #define END_JPEG_SEQUENCE "\r\n[*]--:END JPEG:--[*]\r\n"
00576 
00577 safeboolean fill_input_buffer (j_decompress_ptr cinfo)
00578 {
00579        my_src_ptr src = (my_src_ptr) cinfo->src;
00580        /* 2.0.12: signed size. Thanks to Geert Jansen */
00581        ssize_t nbytes = 0;
00582 
00583        /* ssize_t got; */
00584        /* char *s; */
00585        memset(src->buffer, 0, INPUT_BUF_SIZE);
00586 
00587        while (nbytes < INPUT_BUF_SIZE) {
00588               int got = gdGetBuf(src->buffer + nbytes, INPUT_BUF_SIZE - nbytes, src->infile);
00589 
00590               if (got == EOF || got == 0) {
00591                      /* EOF or error. If we got any data, don't worry about it. If we didn't, then this is unexpected. */
00592                      if (!nbytes) {
00593                             nbytes = -1;
00594                      }
00595                      break;
00596               }
00597               nbytes += got;
00598        }
00599 
00600        if (nbytes <= 0) {
00601               if (src->start_of_file)     { /* Treat empty input file as fatal error */
00602                      ERREXIT (cinfo, JERR_INPUT_EMPTY);
00603               }
00604               WARNMS (cinfo, JWRN_JPEG_EOF);
00605               /* Insert a fake EOI marker */
00606               src->buffer[0] = (unsigned char) 0xFF;
00607               src->buffer[1] = (unsigned char) JPEG_EOI;
00608               nbytes = 2;
00609        }
00610 
00611        src->pub.next_input_byte = src->buffer;
00612        src->pub.bytes_in_buffer = nbytes;
00613        src->start_of_file = FALSE;
00614 
00615        return TRUE;
00616 }
00617 
00618 
00619 /*
00620  * Skip data --- used to skip over a potentially large amount of
00621  * uninteresting data (such as an APPn marker).
00622  *
00623  * Writers of suspendable-input applications must note that skip_input_data
00624  * is not granted the right to give a suspension return.  If the skip extends
00625  * beyond the data currently in the buffer, the buffer can be marked empty so
00626  * that the next read will cause a fill_input_buffer call that can suspend.
00627  * Arranging for additional bytes to be discarded before reloading the input
00628  * buffer is the application writer's problem.
00629  */
00630 
00631 void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
00632 {
00633        my_src_ptr src = (my_src_ptr) cinfo->src;
00634 
00635        /* Just a dumb implementation for now. Not clear that being smart is worth
00636         * any trouble anyway --- large skips are infrequent.
00637         */
00638        if (num_bytes > 0) {
00639               while (num_bytes > (long) src->pub.bytes_in_buffer) {
00640                      num_bytes -= (long) src->pub.bytes_in_buffer;
00641                      (void) fill_input_buffer (cinfo);
00642                      /* note we assume that fill_input_buffer will never return FALSE,
00643                       * so suspension need not be handled.
00644                       */
00645               }
00646               src->pub.next_input_byte += (size_t) num_bytes;
00647               src->pub.bytes_in_buffer -= (size_t) num_bytes;
00648        }
00649 }
00650 
00651 
00652 /*
00653  * An additional method that can be provided by data source modules is the
00654  * resync_to_restart method for error recovery in the presence of RST markers.
00655  * For the moment, this source module just uses the default resync method
00656  * provided by the JPEG library.  That method assumes that no backtracking
00657  * is possible.
00658  */
00659 
00660 
00661 /*
00662  * Terminate source --- called by jpeg_finish_decompress
00663  * after all data has been read.  Often a no-op.
00664  *
00665  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
00666  * application must deal with any cleanup that should happen even
00667  * for error exit.
00668  */
00669 
00670 void term_source (j_decompress_ptr cinfo)
00671 {
00672 #if 0
00673        * never used */
00674        my_src_ptr src = (my_src_ptr) cinfo->src;
00675 #endif
00676 }
00677 
00678 
00679 /*
00680  * Prepare for input from a gdIOCtx stream.
00681  * The caller must have already opened the stream, and is responsible
00682  * for closing it after finishing decompression.
00683  */
00684 
00685 void jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile)
00686 {
00687        my_src_ptr src;
00688 
00689        /* The source object and input buffer are made permanent so that a series
00690         * of JPEG images can be read from the same file by calling jpeg_gdIOCtx_src
00691         * only before the first one.  (If we discarded the buffer at the end of
00692         * one image, we'd likely lose the start of the next one.)
00693         * This makes it unsafe to use this manager and a different source
00694         * manager serially with the same JPEG object.  Caveat programmer.
00695         */
00696        if (cinfo->src == NULL) { /* first time for this JPEG object? */
00697               cinfo->src = (struct jpeg_source_mgr *)
00698               (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof (my_source_mgr));
00699               src = (my_src_ptr) cinfo->src;
00700               src->buffer = (unsigned char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * sizeof (unsigned char));
00701 
00702        }
00703 
00704        src = (my_src_ptr) cinfo->src;
00705        src->pub.init_source = init_source;
00706        src->pub.fill_input_buffer = fill_input_buffer;
00707        src->pub.skip_input_data = skip_input_data;
00708        src->pub.resync_to_restart = jpeg_resync_to_restart;    /* use default method */
00709        src->pub.term_source = term_source;
00710        src->infile = infile;
00711        src->pub.bytes_in_buffer = 0;      /* forces fill_input_buffer on first read */
00712        src->pub.next_input_byte = NULL;   /* until buffer loaded */
00713 }
00714 
00715 /* Expanded data destination object for stdio output */
00716 
00717 typedef struct
00718 {
00719        struct jpeg_destination_mgr pub; /* public fields */
00720        gdIOCtx *outfile;            /* target stream */
00721        unsigned char *buffer;              /* start of buffer */
00722 } my_destination_mgr;
00723 
00724 typedef my_destination_mgr *my_dest_ptr;
00725 
00726 #define OUTPUT_BUF_SIZE  4096      /* choose an efficiently fwrite'able size */
00727 
00728 /*
00729  * Initialize destination --- called by jpeg_start_compress
00730  * before any data is actually written.
00731  */
00732 
00733 void init_destination (j_compress_ptr cinfo)
00734 {
00735        my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
00736 
00737        /* Allocate the output buffer --- it will be released when done with image */
00738        dest->buffer = (unsigned char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof (unsigned char));
00739 
00740        dest->pub.next_output_byte = dest->buffer;
00741        dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
00742 }
00743 
00744 
00745 /*
00746  * Empty the output buffer --- called whenever buffer fills up.
00747  *
00748  * In typical applications, this should write the entire output buffer
00749  * (ignoring the current state of next_output_byte & free_in_buffer),
00750  * reset the pointer & count to the start of the buffer, and return TRUE
00751  * indicating that the buffer has been dumped.
00752  *
00753  * In applications that need to be able to suspend compression due to output
00754  * overrun, a FALSE return indicates that the buffer cannot be emptied now.
00755  * In this situation, the compressor will return to its caller (possibly with
00756  * an indication that it has not accepted all the supplied scanlines).  The
00757  * application should resume compression after it has made more room in the
00758  * output buffer.  Note that there are substantial restrictions on the use of
00759  * suspension --- see the documentation.
00760  *
00761  * When suspending, the compressor will back up to a convenient restart point
00762  * (typically the start of the current MCU). next_output_byte & free_in_buffer
00763  * indicate where the restart point will be if the current call returns FALSE.
00764  * Data beyond this point will be regenerated after resumption, so do not
00765  * write it out when emptying the buffer externally.
00766  */
00767 
00768 safeboolean empty_output_buffer (j_compress_ptr cinfo)
00769 {
00770        my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
00771 
00772        if (gdPutBuf (dest->buffer, OUTPUT_BUF_SIZE, dest->outfile) != (size_t) OUTPUT_BUF_SIZE) {
00773               ERREXIT (cinfo, JERR_FILE_WRITE);
00774        }
00775 
00776        dest->pub.next_output_byte = dest->buffer;
00777        dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
00778 
00779        return TRUE;
00780 }
00781 
00782 
00783 /*
00784  * Terminate destination --- called by jpeg_finish_compress
00785  * after all data has been written.  Usually needs to flush buffer.
00786  *
00787  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
00788  * application must deal with any cleanup that should happen even
00789  * for error exit.
00790  */
00791 
00792 void term_destination (j_compress_ptr cinfo)
00793 {
00794        my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
00795        size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
00796 
00797        /* Write any data remaining in the buffer */
00798        if (datacount > 0 && ((size_t)gdPutBuf (dest->buffer, datacount, dest->outfile) != datacount)) {
00799               ERREXIT (cinfo, JERR_FILE_WRITE);
00800        }
00801 }
00802 
00803 
00804 /*
00805  * Prepare for output to a stdio stream.
00806  * The caller must have already opened the stream, and is responsible
00807  * for closing it after finishing compression.
00808  */
00809 
00810 void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile)
00811 {
00812        my_dest_ptr dest;
00813 
00814        /* The destination object is made permanent so that multiple JPEG images
00815         * can be written to the same file without re-executing jpeg_stdio_dest.
00816         * This makes it dangerous to use this manager and a different destination
00817         * manager serially with the same JPEG object, because their private object
00818         * sizes may be different.  Caveat programmer.
00819         */
00820        if (cinfo->dest == NULL) { /* first time for this JPEG object? */
00821               cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof (my_destination_mgr));
00822        }
00823 
00824        dest = (my_dest_ptr) cinfo->dest;
00825        dest->pub.init_destination = init_destination;
00826        dest->pub.empty_output_buffer = empty_output_buffer;
00827        dest->pub.term_destination = term_destination;
00828        dest->outfile = outfile;
00829 }
00830 
00831 #endif /* HAVE_JPEG */