Back to index

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