Blame src/gd_jpeg.c

Packit Service df60bb
/*
Packit Service df60bb
 * gd_jpeg.c: Read and write JPEG (JFIF) format image files using the
Packit Service df60bb
 * gd graphics library (http://www.libgd.org).
Packit Service df60bb
 *
Packit Service df60bb
 * This software is based in part on the work of the Independent JPEG
Packit Service df60bb
 * Group.  For more information on the IJG JPEG software (and JPEG
Packit Service df60bb
 * documentation, etc.), see ftp://ftp.uu.net/graphics/jpeg/.
Packit Service df60bb
 *
Packit Service df60bb
 * NOTE: IJG 12-bit JSAMPLE (BITS_IN_JSAMPLE == 12) mode is not
Packit Service df60bb
 * supported at all on read in gd 2.0, and is not supported on write
Packit Service df60bb
 * except for palette images, which is sort of pointless (TBB). Even that
Packit Service df60bb
 * has never been tested according to DB.
Packit Service df60bb
 *
Packit Service df60bb
 * Copyright 2000 Doug Becker, mailto:thebeckers@home.com
Packit Service df60bb
 *
Packit Service df60bb
 * Modification 4/18/00 TBB: JPEG_DEBUG rather than just DEBUG,
Packit Service df60bb
 * so VC++ builds don't spew to standard output, causing
Packit Service df60bb
 * major CGI brain damage
Packit Service df60bb
 *
Packit Service df60bb
 * 2.0.10: more efficient gdImageCreateFromJpegCtx, thanks to
Packit Service df60bb
 * Christian Aberger
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
/**
Packit Service df60bb
 * File: JPEG IO
Packit Service df60bb
 *
Packit Service df60bb
 * Read and write JPEG images.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
#ifdef HAVE_CONFIG_H
Packit Service df60bb
#	include "config.h"
Packit Service df60bb
#endif
Packit Service df60bb
Packit Service df60bb
#include <stdlib.h>
Packit Service df60bb
#include <setjmp.h>
Packit Service df60bb
#include <limits.h>
Packit Service df60bb
#include <string.h>
Packit Service df60bb
Packit Service df60bb
#include "gd.h"
Packit Service df60bb
#include "gd_errors.h"
Packit Service df60bb
/* TBB: move this up so include files are not brought in */
Packit Service df60bb
/* JCE: arrange HAVE_LIBJPEG so that it can be set in gd.h */
Packit Service df60bb
#ifdef HAVE_LIBJPEG
Packit Service df60bb
#include "gdhelpers.h"
Packit Service df60bb
Packit Service df60bb
#if defined(_WIN32) && defined(__MINGW32__)
Packit Service df60bb
# define HAVE_BOOLEAN
Packit Service df60bb
#endif
Packit Service df60bb
Packit Service df60bb
/* JCE undef two symbols that we don't need anymore but which are
Packit Service df60bb
   may be defined in config.h from ./configure but which are
Packit Service df60bb
   redefined incompatibly in jpeglib.h */
Packit Service df60bb
#undef HAVE_STDDEF_H
Packit Service df60bb
#undef HAVE_STDLIB_H
Packit Service df60bb
Packit Service df60bb
/* 1.8.1: remove dependency on jinclude.h */
Packit Service df60bb
#include "jpeglib.h"
Packit Service df60bb
#include "jerror.h"
Packit Service df60bb
Packit Service df60bb
static const char *const GD_JPEG_VERSION = "1.0";
Packit Service df60bb
Packit Service df60bb
typedef struct _jmpbuf_wrapper {
Packit Service df60bb
	jmp_buf jmpbuf;
Packit Service df60bb
        int ignore_warning;
Packit Service df60bb
}
Packit Service df60bb
jmpbuf_wrapper;
Packit Service df60bb
Packit Service df60bb
static void jpeg_emit_message(j_common_ptr jpeg_info, int level)
Packit Service df60bb
{
Packit Service df60bb
	char message[JMSG_LENGTH_MAX];
Packit Service df60bb
	jmpbuf_wrapper *jmpbufw;
Packit Service df60bb
	int ignore_warning = 0;
Packit Service df60bb
Packit Service df60bb
	jmpbufw = (jmpbuf_wrapper *) jpeg_info->client_data;
Packit Service df60bb
Packit Service df60bb
	if (jmpbufw != 0) {
Packit Service df60bb
		ignore_warning = jmpbufw->ignore_warning;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	(jpeg_info->err->format_message)(jpeg_info,message);
Packit Service df60bb
Packit Service df60bb
	/* It is a warning message */
Packit Service df60bb
	if (level < 0) {
Packit Service df60bb
		/* display only the 1st warning, as would do a default libjpeg
Packit Service df60bb
		 * unless strace_level >= 3
Packit Service df60bb
		 */
Packit Service df60bb
		if ((jpeg_info->err->num_warnings == 0) || (jpeg_info->err->trace_level >= 3)) {
Packit Service df60bb
			if (!ignore_warning) {
Packit Service df60bb
				gd_error("gd-jpeg, libjpeg: recoverable error: %s\n", message);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		jpeg_info->err->num_warnings++;
Packit Service df60bb
	} else {
Packit Service df60bb
		/* strace msg, Show it if trace_level >= level. */
Packit Service df60bb
		if (jpeg_info->err->trace_level >= level) {
Packit Service df60bb
			if (!ignore_warning) {
Packit Service df60bb
				gd_error("gd-jpeg, libjpeg: strace message: %s\n", message);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* Called by the IJG JPEG library upon encountering a fatal error */
Packit Service df60bb
static void fatal_jpeg_error(j_common_ptr cinfo)
Packit Service df60bb
{
Packit Service df60bb
	jmpbuf_wrapper *jmpbufw;
Packit Service df60bb
	char buffer[JMSG_LENGTH_MAX];
Packit Service df60bb
Packit Service df60bb
	(*cinfo->err->format_message)(cinfo, buffer);
Packit Service df60bb
	gd_error_ex(GD_WARNING, "gd-jpeg: JPEG library reports unrecoverable error: %s", buffer);
Packit Service df60bb
Packit Service df60bb
	jmpbufw = (jmpbuf_wrapper *)cinfo->client_data;
Packit Service df60bb
	jpeg_destroy(cinfo);
Packit Service df60bb
Packit Service df60bb
	if(jmpbufw != 0) {
Packit Service df60bb
		longjmp(jmpbufw->jmpbuf, 1);
Packit Service df60bb
		gd_error_ex(GD_ERROR, "gd-jpeg: EXTREMELY fatal error: longjmp returned control; terminating\n");
Packit Service df60bb
	} else {
Packit Service df60bb
		gd_error_ex(GD_ERROR, "gd-jpeg: EXTREMELY fatal error: jmpbuf unrecoverable; terminating\n");
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	exit(99);
Packit Service df60bb
}
Packit Service df60bb
Packit Service 176cb2
static int _gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality);
Packit Service 176cb2
Packit Service df60bb
/*
Packit Service df60bb
 * Write IM to OUTFILE as a JFIF-formatted JPEG image, using quality
Packit Service df60bb
 * QUALITY.  If QUALITY is in the range 0-100, increasing values
Packit Service df60bb
 * represent higher quality but also larger image size.  If QUALITY is
Packit Service df60bb
 * negative, the IJG JPEG library's default quality is used (which
Packit Service df60bb
 * should be near optimal for many applications).  See the IJG JPEG
Packit Service df60bb
 * library documentation for more details.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageJpeg
Packit Service df60bb
Packit Service df60bb
    <gdImageJpeg> outputs the specified image to the specified file in
Packit Service df60bb
    JPEG format. The file must be open for writing. Under MSDOS and
Packit Service df60bb
    all versions of Windows, it is important to use "wb" as opposed to
Packit Service df60bb
    simply "w" as the mode when opening the file, and under Unix there
Packit Service df60bb
    is no penalty for doing so. <gdImageJpeg> does not close the file;
Packit Service df60bb
    your code must do so.
Packit Service df60bb
Packit Service df60bb
    If _quality_ is negative, the default IJG JPEG quality value (which
Packit Service df60bb
    should yield a good general quality / size tradeoff for most
Packit Service df60bb
    situations) is used. Otherwise, for practical purposes, _quality_
Packit Service df60bb
    should be a value in the range 0-95, higher quality values usually
Packit Service df60bb
    implying both higher quality and larger image sizes.
Packit Service df60bb
Packit Service df60bb
    If you have set image interlacing using <gdImageInterlace>, this
Packit Service df60bb
    function will interpret that to mean you wish to output a
Packit Service df60bb
    progressive JPEG. Some programs (e.g., Web browsers) can display
Packit Service df60bb
    progressive JPEGs incrementally; this can be useful when browsing
Packit Service df60bb
    over a relatively slow communications link, for
Packit Service df60bb
    example. Progressive JPEGs can also be slightly smaller than
Packit Service df60bb
    sequential (non-progressive) JPEGs.
Packit Service df60bb
Packit Service df60bb
  Variants:
Packit Service df60bb
Packit Service df60bb
    <gdImageJpegCtx> stores the image using a <gdIOCtx> struct.
Packit Service df60bb
Packit Service df60bb
    <gdImageJpegPtr> stores the image to RAM.
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    im      - The image to save
Packit Service df60bb
    outFile - The FILE pointer to write to.
Packit Service df60bb
    quality - Compression quality (0-95, 0 means use the default).
Packit Service df60bb
Packit Service df60bb
  Returns:
Packit Service df60bb
Packit Service df60bb
    Nothing.
Packit Service df60bb
Packit Service df60bb
  Example:
Packit Service df60bb
    (start code)
Packit Service df60bb
Packit Service df60bb
    gdImagePtr im;
Packit Service df60bb
    int black, white;
Packit Service df60bb
    FILE *out;
Packit Service df60bb
    // Create the image
Packit Service df60bb
    im = gdImageCreate(100, 100);
Packit Service df60bb
    // Allocate background
Packit Service df60bb
    white = gdImageColorAllocate(im, 255, 255, 255);
Packit Service df60bb
    // Allocate drawing color
Packit Service df60bb
    black = gdImageColorAllocate(im, 0, 0, 0);
Packit Service df60bb
    // Draw rectangle
Packit Service df60bb
    gdImageRectangle(im, 0, 0, 99, 99, black);
Packit Service df60bb
    // Open output file in binary mode
Packit Service df60bb
    out = fopen("rect.jpg", "wb");
Packit Service df60bb
    // Write JPEG using default quality
Packit Service df60bb
    gdImageJpeg(im, out, -1);
Packit Service df60bb
    // Close file
Packit Service df60bb
    fclose(out);
Packit Service df60bb
    // Destroy image
Packit Service df60bb
    gdImageDestroy(im);
Packit Service df60bb
Packit Service df60bb
    (end code)
Packit Service df60bb
*/
Packit Service df60bb
Packit Service df60bb
BGD_DECLARE(void) gdImageJpeg(gdImagePtr im, FILE *outFile, int quality)
Packit Service df60bb
{
Packit Service df60bb
	gdIOCtx *out = gdNewFileCtx(outFile);
Packit Service df60bb
	if (out == NULL) return;
Packit Service df60bb
	gdImageJpegCtx(im, out, quality);
Packit Service df60bb
	out->gd_free(out);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageJpegPtr
Packit Service df60bb
Packit Service df60bb
    Identical to <gdImageJpeg> except that it returns a pointer to a
Packit Service df60bb
    memory area with the JPEG data. This memory must be freed by the
Packit Service df60bb
    caller when it is no longer needed.
Packit Service df60bb
Packit Service df60bb
    The caller *must* invoke <gdFree>, not free().  This is because it
Packit Service df60bb
    is not guaranteed that libgd will use the same implementation of
Packit Service df60bb
    malloc, free, etc. as your proggram.
Packit Service df60bb
Packit Service df60bb
    The 'size' parameter receives the total size of the block of
Packit Service df60bb
    memory.
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    im      - The image to write
Packit Service df60bb
    size    - Output: the size of the resulting image.
Packit Service df60bb
    quality - Compression quality.
Packit Service df60bb
Packit Service df60bb
  Returns:
Packit Service df60bb
Packit Service df60bb
    A pointer to the JPEG data or NULL if an error occurred.
Packit Service df60bb
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void *) gdImageJpegPtr(gdImagePtr im, int *size, int quality)
Packit Service df60bb
{
Packit Service df60bb
	void *rv;
Packit Service df60bb
	gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
Packit Service df60bb
	if (out == NULL) return NULL;
Packit Service 176cb2
	if (!_gdImageJpegCtx(im, out, quality)) {
Packit Service 176cb2
		rv = gdDPExtractData(out, size);
Packit Service 176cb2
	} else {
Packit Service 176cb2
		rv = NULL;
Packit Service 176cb2
	}
Packit Service df60bb
	out->gd_free(out);
Packit Service df60bb
	return rv;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
void jpeg_gdIOCtx_dest(j_compress_ptr cinfo, gdIOCtx *outfile);
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageJpegCtx
Packit Service df60bb
Packit Service df60bb
    Write the image as JPEG data via a <gdIOCtx>. See <gdImageJpeg>
Packit Service df60bb
    for more details.
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    im      - The image to write.
Packit Service df60bb
    outfile - The output sink.
Packit Service df60bb
    quality - Image quality. 
Packit Service df60bb
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
Packit Service df60bb
{
Packit Service 176cb2
	_gdImageJpegCtx(im, outfile, quality);
Packit Service 176cb2
}
Packit Service 176cb2
Packit Service 176cb2
/* returns 0 on success, 1 on failure */
Packit Service 176cb2
static int _gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
Packit Service 176cb2
{
Packit Service df60bb
	struct jpeg_compress_struct cinfo;
Packit Service df60bb
	struct jpeg_error_mgr jerr;
Packit Service df60bb
	int i, j, jidx;
Packit Service df60bb
	/* volatile so we can gdFree it on return from longjmp */
Packit Service df60bb
	volatile JSAMPROW row = 0;
Packit Service df60bb
	JSAMPROW rowptr[1];
Packit Service df60bb
	jmpbuf_wrapper jmpbufw;
Packit Service df60bb
	JDIMENSION nlines;
Packit Service df60bb
	char comment[255];
Packit Service df60bb
Packit Service df60bb
#ifdef JPEG_DEBUG
Packit Service df60bb
	gd_error_ex(GD_DEBUG, "gd-jpeg: gd JPEG version %s\n", GD_JPEG_VERSION);
Packit Service df60bb
	gd_error_ex(GD_DEBUG, "gd-jpeg: JPEG library version %d, %d-bit sample values\n", JPEG_LIB_VERSION, BITS_IN_JSAMPLE);
Packit Service df60bb
	if (!im->trueColor) {
Packit Service df60bb
		for(i = 0; i < im->colorsTotal; i++) {
Packit Service df60bb
			if(!im->open[i]) {
Packit Service df60bb
				gd_error_ex(GD_DEBUG, "gd-jpeg: gd colormap index %d: (%d, %d, %d)\n", i, im->red[i], im->green[i], im->blue[i]);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
#endif /* JPEG_DEBUG */
Packit Service df60bb
Packit Service df60bb
	memset(&cinfo, 0, sizeof(cinfo));
Packit Service df60bb
	memset(&jerr, 0, sizeof(jerr));
Packit Service df60bb
Packit Service df60bb
	cinfo.err = jpeg_std_error(&jerr);
Packit Service df60bb
	cinfo.client_data = &jmpbufw;
Packit Service df60bb
Packit Service df60bb
	if(setjmp(jmpbufw.jmpbuf) != 0) {
Packit Service df60bb
		/* we're here courtesy of longjmp */
Packit Service df60bb
		if(row) {
Packit Service df60bb
			gdFree(row);
Packit Service df60bb
		}
Packit Service 176cb2
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	cinfo.err->emit_message = jpeg_emit_message;
Packit Service df60bb
	cinfo.err->error_exit = fatal_jpeg_error;
Packit Service df60bb
Packit Service df60bb
	jpeg_create_compress(&cinfo);
Packit Service df60bb
Packit Service df60bb
	cinfo.image_width = im->sx;
Packit Service df60bb
	cinfo.image_height = im->sy;
Packit Service df60bb
	cinfo.input_components = 3; /* # of color components per pixel */
Packit Service df60bb
	cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
Packit Service df60bb
Packit Service df60bb
	jpeg_set_defaults(&cinfo);
Packit Service df60bb
Packit Service df60bb
	cinfo.density_unit = 1;
Packit Service df60bb
	cinfo.X_density = im->res_x;
Packit Service df60bb
	cinfo.Y_density = im->res_y;
Packit Service df60bb
Packit Service df60bb
	if(quality >= 0) {
Packit Service df60bb
		jpeg_set_quality(&cinfo, quality, TRUE);
Packit Service df60bb
		if (quality >= 90) {
Packit Service df60bb
			cinfo.comp_info[0].h_samp_factor = 1;
Packit Service df60bb
			cinfo.comp_info[0].v_samp_factor = 1;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* If user requests interlace, translate that to progressive JPEG */
Packit Service df60bb
	if(gdImageGetInterlaced(im)) {
Packit Service df60bb
#ifdef JPEG_DEBUG
Packit Service df60bb
		gd_error_ex(GD_DEBUG, "gd-jpeg: interlace set, outputting progressive JPEG image\n");
Packit Service df60bb
#endif
Packit Service df60bb
		jpeg_simple_progression(&cinfo);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	jpeg_gdIOCtx_dest(&cinfo, outfile);
Packit Service df60bb
Packit Service df60bb
	row = (JSAMPROW)gdCalloc(1, cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE));
Packit Service df60bb
	if(row == 0) {
Packit Service df60bb
		gd_error("gd-jpeg: error: unable to allocate JPEG row structure: gdCalloc returns NULL\n");
Packit Service df60bb
		jpeg_destroy_compress(&cinfo);
Packit Service 176cb2
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	rowptr[0] = row;
Packit Service df60bb
Packit Service df60bb
	jpeg_start_compress(&cinfo, TRUE);
Packit Service df60bb
Packit Service df60bb
	sprintf(comment, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d),", GD_JPEG_VERSION, JPEG_LIB_VERSION);
Packit Service df60bb
Packit Service df60bb
	if(quality >= 0) {
Packit Service df60bb
		sprintf (comment + strlen(comment), " quality = %d\n", quality);
Packit Service df60bb
	} else {
Packit Service df60bb
		strcat(comment + strlen(comment), " default quality\n");
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	jpeg_write_marker(&cinfo, JPEG_COM, (unsigned char *) comment, (unsigned int)strlen(comment));
Packit Service df60bb
Packit Service df60bb
	if(im->trueColor) {
Packit Service df60bb
#if BITS_IN_JSAMPLE == 12
Packit Service df60bb
		gd_error(
Packit Service df60bb
		        "gd-jpeg: error: jpeg library was compiled for 12-bit\n"
Packit Service df60bb
		        "precision. This is mostly useless, because JPEGs on the web are\n"
Packit Service df60bb
		        "8-bit and such versions of the jpeg library won't read or write\n"
Packit Service df60bb
		        "them. GD doesn't support these unusual images. Edit your\n"
Packit Service df60bb
		        "jmorecfg.h file to specify the correct precision and completely\n"
Packit Service df60bb
		        "'make clean' and 'make install' libjpeg again. Sorry.\n"
Packit Service df60bb
		       );
Packit Service df60bb
		goto error;
Packit Service df60bb
#endif /* BITS_IN_JSAMPLE == 12 */
Packit Service df60bb
		for(i = 0; i < im->sy; i++) {
Packit Service df60bb
			for(jidx = 0, j = 0; j < im->sx; j++) {
Packit Service df60bb
				int val = im->tpixels[i][j];
Packit Service df60bb
				row[jidx++] = gdTrueColorGetRed(val);
Packit Service df60bb
				row[jidx++] = gdTrueColorGetGreen(val);
Packit Service df60bb
				row[jidx++] = gdTrueColorGetBlue(val);
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			nlines = jpeg_write_scanlines(&cinfo, rowptr, 1);
Packit Service df60bb
Packit Service df60bb
			if(nlines != 1) {
Packit Service df60bb
				gd_error("gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1\n", nlines);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	} else {
Packit Service df60bb
		for(i = 0; i < im->sy; i++) {
Packit Service df60bb
			for(jidx = 0, j = 0; j < im->sx; j++) {
Packit Service df60bb
				int idx = im->pixels[i][j];
Packit Service df60bb
Packit Service df60bb
				/*
Packit Service df60bb
				 * NB: Although gd RGB values are ints, their max value is
Packit Service df60bb
				 * 255 (see the documentation for gdImageColorAllocate())
Packit Service df60bb
				 * -- perfect for 8-bit JPEG encoding (which is the norm)
Packit Service df60bb
				 */
Packit Service df60bb
#if BITS_IN_JSAMPLE == 8
Packit Service df60bb
				row[jidx++] = im->red[idx];
Packit Service df60bb
				row[jidx++] = im->green[idx];
Packit Service df60bb
				row[jidx++] = im->blue[idx];
Packit Service df60bb
#elif BITS_IN_JSAMPLE == 12
Packit Service df60bb
				row[jidx++] = im->red[idx] << 4;
Packit Service df60bb
				row[jidx++] = im->green[idx] << 4;
Packit Service df60bb
				row[jidx++] = im->blue[idx] << 4;
Packit Service df60bb
#else
Packit Service df60bb
#error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12
Packit Service df60bb
#endif
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			nlines = jpeg_write_scanlines(&cinfo, rowptr, 1);
Packit Service df60bb
			if(nlines != 1) {
Packit Service df60bb
				gd_error("gd_jpeg: warning: jpeg_write_scanlines"
Packit Service df60bb
				         " returns %u -- expected 1\n", nlines);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	jpeg_finish_compress(&cinfo);
Packit Service df60bb
	jpeg_destroy_compress(&cinfo);
Packit Service df60bb
	gdFree(row);
Packit Service 176cb2
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromJpeg
Packit Service df60bb
Packit Service df60bb
  See <gdImageCreateFromJpegEx>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpeg(FILE *inFile)
Packit Service df60bb
{
Packit Service df60bb
	return gdImageCreateFromJpegEx(inFile, 1);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromJpegEx
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromJpegEx> is called to load truecolor images from
Packit Service df60bb
    JPEG format files. Invoke <gdImageCreateFromJpegEx> with an
Packit Service df60bb
    already opened pointer to a file containing the desired
Packit Service df60bb
    image. <gdImageCreateFromJpegEx> returns a <gdImagePtr> to the new
Packit Service df60bb
    truecolor image, or NULL if unable to load the image (most often
Packit Service df60bb
    because the file is corrupt or does not contain a JPEG
Packit Service df60bb
    image). <gdImageCreateFromJpegEx> does not close the file.
Packit Service df60bb
Packit Service df60bb
    You can inspect the sx and sy members of the image to determine
Packit Service df60bb
    its size. The image must eventually be destroyed using
Packit Service df60bb
    <gdImageDestroy>.
Packit Service df60bb
Packit Service df60bb
    *The returned image is always a truecolor image.*
Packit Service df60bb
Packit Service df60bb
  Variants:
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromJpegPtrEx> creates an image from JPEG data
Packit Service df60bb
    already in memory.
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromJpegCtxEx> reads its data via the function
Packit Service df60bb
    pointers in a <gdIOCtx> structure.
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromJpeg>, <gdImageCreateFromJpegPtr> and
Packit Service df60bb
    <gdImageCreateFromJpegCtx> are equivalent to calling their
Packit Service df60bb
    _Ex_-named counterparts with an ignore_warning set to 1
Packit Service df60bb
    (i.e. TRUE).
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    infile          - The input FILE pointer.
Packit Service df60bb
    ignore_warning  - Flag.  If true, ignores recoverable warnings.
Packit Service df60bb
Packit Service df60bb
  Returns:
Packit Service df60bb
Packit Service df60bb
    A pointer to the new *truecolor* image.  This will need to be
Packit Service df60bb
    destroyed with <gdImageDestroy> once it is no longer needed.
Packit Service df60bb
Packit Service df60bb
    On error, returns NULL.
Packit Service df60bb
Packit Service df60bb
  Example:
Packit Service df60bb
    (start code)
Packit Service df60bb
Packit Service df60bb
    gdImagePtr im;
Packit Service df60bb
    FILE *in;
Packit Service df60bb
    in = fopen("myjpeg.jpg", "rb");
Packit Service df60bb
    im = gdImageCreateFromJpegEx(in, GD_TRUE);
Packit Service df60bb
    fclose(in);
Packit Service df60bb
    // ... Use the image ...
Packit Service df60bb
    gdImageDestroy(im);
Packit Service df60bb
Packit Service df60bb
    (end code)
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegEx(FILE *inFile, int ignore_warning)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	gdIOCtx *in = gdNewFileCtx(inFile);
Packit Service df60bb
	if (in == NULL) return NULL;
Packit Service df60bb
	im = gdImageCreateFromJpegCtxEx(in, ignore_warning);
Packit Service df60bb
	in->gd_free(in);
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromJpegPtr
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
  
Packit Service df60bb
    size    - size of JPEG data in bytes.
Packit Service df60bb
    data    - pointer to JPEG data.
Packit Service df60bb
Packit Service df60bb
  See <gdImageCreateFromJpegEx>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtr(int size, void *data)
Packit Service df60bb
{
Packit Service df60bb
	return gdImageCreateFromJpegPtrEx(size, data, 1);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromJpegPtrEx
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
  
Packit Service df60bb
    size            - size of JPEG data in bytes.
Packit Service df60bb
    data            - pointer to JPEG data.
Packit Service df60bb
    ignore_warning  - if true, ignore recoverable warnings
Packit Service df60bb
Packit Service df60bb
  See <gdImageCreateFromJpegEx>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtrEx(int size, void *data, int ignore_warning)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
Packit Service df60bb
	if(!in) {
Packit Service df60bb
		return 0;
Packit Service df60bb
	}
Packit Service df60bb
	im = gdImageCreateFromJpegCtxEx(in, ignore_warning);
Packit Service df60bb
	in->gd_free(in);
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
void jpeg_gdIOCtx_src(j_decompress_ptr cinfo, gdIOCtx *infile);
Packit Service df60bb
Packit Service df60bb
static int CMYKToRGB(int c, int m, int y, int k, int inverted);
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromJpegCtx
Packit Service df60bb
Packit Service df60bb
  See <gdImageCreateFromJpeg>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtx(gdIOCtx *infile)
Packit Service df60bb
{
Packit Service df60bb
	return gdImageCreateFromJpegCtxEx(infile, 1);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromJpegCtxEx
Packit Service df60bb
Packit Service df60bb
  See <gdImageCreateFromJpeg>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtxEx(gdIOCtx *infile, int ignore_warning)
Packit Service df60bb
{
Packit Service df60bb
	struct jpeg_decompress_struct cinfo;
Packit Service df60bb
	struct jpeg_error_mgr jerr;
Packit Service df60bb
	jmpbuf_wrapper jmpbufw;
Packit Service df60bb
	/* volatile so we can gdFree them after longjmp */
Packit Service df60bb
	volatile JSAMPROW row = 0;
Packit Service df60bb
	volatile gdImagePtr im = 0;
Packit Service df60bb
	JSAMPROW rowptr[1];
Packit Service df60bb
	JDIMENSION i, j;
Packit Service df60bb
	int retval;
Packit Service df60bb
	JDIMENSION nrows;
Packit Service df60bb
	int channels = 3;
Packit Service df60bb
	int inverted = 0;
Packit Service df60bb
Packit Service df60bb
#ifdef JPEG_DEBUG
Packit Service df60bb
	gd_error_ex(GD_DEBUG, "gd-jpeg: gd JPEG version %s\n", GD_JPEG_VERSION);
Packit Service df60bb
	gd_error_ex(GD_DEBUG, "gd-jpeg: JPEG library version %d, %d-bit sample values\n", JPEG_LIB_VERSION, BITS_IN_JSAMPLE);
Packit Service df60bb
	gd_error_ex(GD_DEBUG, "sizeof: %d\n", sizeof(struct jpeg_decompress_struct));
Packit Service df60bb
#endif
Packit Service df60bb
Packit Service df60bb
	memset(&cinfo, 0, sizeof(cinfo));
Packit Service df60bb
	memset(&jerr, 0, sizeof(jerr));
Packit Service df60bb
Packit Service df60bb
	jmpbufw.ignore_warning = ignore_warning;
Packit Service df60bb
Packit Service df60bb
	cinfo.err = jpeg_std_error(&jerr);
Packit Service df60bb
	cinfo.client_data = &jmpbufw;
Packit Service df60bb
Packit Service df60bb
	cinfo.err->emit_message = jpeg_emit_message;
Packit Service df60bb
Packit Service df60bb
	if(setjmp(jmpbufw.jmpbuf) != 0) {
Packit Service df60bb
		/* we're here courtesy of longjmp */
Packit Service df60bb
		if(row) {
Packit Service df60bb
			gdFree(row);
Packit Service df60bb
		}
Packit Service df60bb
		if(im) {
Packit Service df60bb
			gdImageDestroy(im);
Packit Service df60bb
		}
Packit Service df60bb
		return 0;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	cinfo.err->error_exit = fatal_jpeg_error;
Packit Service df60bb
Packit Service df60bb
	jpeg_create_decompress(&cinfo);
Packit Service df60bb
Packit Service df60bb
	jpeg_gdIOCtx_src(&cinfo, infile);
Packit Service df60bb
Packit Service df60bb
	/* 2.0.22: save the APP14 marker to check for Adobe Photoshop CMYK
Packit Service df60bb
	 * files with inverted components.
Packit Service df60bb
	 */
Packit Service df60bb
	jpeg_save_markers(&cinfo, JPEG_APP0 + 14, 256);
Packit Service df60bb
Packit Service df60bb
	retval = jpeg_read_header(&cinfo, TRUE);
Packit Service df60bb
	if(retval != JPEG_HEADER_OK) {
Packit Service df60bb
		gd_error("gd-jpeg: warning: jpeg_read_header returns"
Packit Service df60bb
		         " %d, expected %d\n", retval, JPEG_HEADER_OK);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if(cinfo.image_height > INT_MAX) {
Packit Service df60bb
		gd_error("gd-jpeg: warning: JPEG image height (%u) is"
Packit Service df60bb
		         " greater than INT_MAX (%d) (and thus greater than"
Packit Service df60bb
		         " gd can handle)", cinfo.image_height, INT_MAX);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if(cinfo.image_width > INT_MAX) {
Packit Service df60bb
		gd_error("gd-jpeg: warning: JPEG image width (%u) is"
Packit Service df60bb
		         " greater than INT_MAX (%d) (and thus greater than"
Packit Service df60bb
		         " gd can handle)\n", cinfo.image_width, INT_MAX);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	im = gdImageCreateTrueColor((int)cinfo.image_width, (int)cinfo.image_height);
Packit Service df60bb
	if(im == 0) {
Packit Service df60bb
		gd_error("gd-jpeg error: cannot allocate gdImage struct\n");
Packit Service df60bb
		goto error;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* check if the resolution is specified */
Packit Service df60bb
	switch (cinfo.density_unit) {
Packit Service df60bb
	case 1:
Packit Service df60bb
		im->res_x = cinfo.X_density;
Packit Service df60bb
		im->res_y = cinfo.Y_density;
Packit Service df60bb
		break;
Packit Service df60bb
	case 2:
Packit Service df60bb
		im->res_x = DPCM2DPI(cinfo.X_density);
Packit Service df60bb
		im->res_y = DPCM2DPI(cinfo.Y_density);
Packit Service df60bb
		break;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* 2.0.22: very basic support for reading CMYK colorspace files. Nice for
Packit Service df60bb
	 * thumbnails but there's no support for fussy adjustment of the
Packit Service df60bb
	 * assumed properties of inks and paper.
Packit Service df60bb
	 */
Packit Service df60bb
	if((cinfo.jpeg_color_space == JCS_CMYK) || (cinfo.jpeg_color_space == JCS_YCCK)) {
Packit Service df60bb
		cinfo.out_color_space = JCS_CMYK;
Packit Service df60bb
	} else {
Packit Service df60bb
		cinfo.out_color_space = JCS_RGB;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if(jpeg_start_decompress(&cinfo) != TRUE) {
Packit Service df60bb
		gd_error("gd-jpeg: warning: jpeg_start_decompress"
Packit Service df60bb
		        " reports suspended data source\n");
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
#ifdef JPEG_DEBUG
Packit Service df60bb
	gd_error_ex(GD_DEBUG, "gd-jpeg: JPEG image information:");
Packit Service df60bb
	if(cinfo.saw_JFIF_marker) {
Packit Service df60bb
		gd_error_ex(GD_DEBUG, " JFIF version %d.%.2d", (int)cinfo.JFIF_major_version, (int)cinfo.JFIF_minor_version);
Packit Service df60bb
	} else if(cinfo.saw_Adobe_marker) {
Packit Service df60bb
		gd_error_ex(GD_DEBUG, " Adobe format");
Packit Service df60bb
	} else {
Packit Service df60bb
		gd_error_ex(GD_DEBUG, " UNKNOWN format");
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	gd_error_ex(GD_DEBUG, " %ux%u (raw) / %ux%u (scaled) %d-bit", cinfo.image_width,
Packit Service df60bb
		    cinfo.image_height, cinfo.output_width,
Packit Service df60bb
		    cinfo.output_height, cinfo.data_precision
Packit Service df60bb
		);
Packit Service df60bb
	gd_error_ex(GD_DEBUG, " %s", (cinfo.progressive_mode ? "progressive" : "baseline"));
Packit Service df60bb
	gd_error_ex(GD_DEBUG, " image, %d quantized colors, ", cinfo.actual_number_of_colors);
Packit Service df60bb
Packit Service df60bb
	switch(cinfo.jpeg_color_space) {
Packit Service df60bb
	case JCS_GRAYSCALE:
Packit Service df60bb
		gd_error_ex(GD_DEBUG, "grayscale");
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case JCS_RGB:
Packit Service df60bb
		gd_error_ex(GD_DEBUG, "RGB");
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case JCS_YCbCr:
Packit Service df60bb
		gd_error_ex(GD_DEBUG, "YCbCr (a.k.a. YUV)");
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case JCS_CMYK:
Packit Service df60bb
		gd_error_ex(GD_DEBUG, "CMYK");
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case JCS_YCCK:
Packit Service df60bb
		gd_error_ex(GD_DEBUG, "YCbCrK");
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	default:
Packit Service df60bb
		gd_error_ex(GD_DEBUG, "UNKNOWN (value: %d)", (int)cinfo.jpeg_color_space);
Packit Service df60bb
		break;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	gd_error_ex(GD_DEBUG, " colorspace\n");
Packit Service df60bb
	fflush(stdout);
Packit Service df60bb
#endif /* JPEG_DEBUG */
Packit Service df60bb
Packit Service df60bb
	/* REMOVED by TBB 2/12/01. This field of the structure is
Packit Service df60bb
	 * documented as private, and sure enough it's gone in the
Packit Service df60bb
	 * latest libjpeg, replaced by something else. Unfortunately
Packit Service df60bb
	 * there is still no right way to find out if the file was
Packit Service df60bb
	 * progressive or not; just declare your intent before you
Packit Service df60bb
	 * write one by calling gdImageInterlace(im, 1) yourself.
Packit Service df60bb
	 * After all, we're not really supposed to rework JPEGs and
Packit Service df60bb
	 * write them out again anyway. Lossy compression, remember? */
Packit Service df60bb
#if 0
Packit Service df60bb
	gdImageInterlace (im, cinfo.progressive_mode != 0);
Packit Service df60bb
#endif
Packit Service df60bb
	if(cinfo.out_color_space == JCS_RGB) {
Packit Service df60bb
		if(cinfo.output_components != 3) {
Packit Service df60bb
			gd_error("gd-jpeg: error: JPEG color quantization"
Packit Service df60bb
			         " request resulted in output_components == %d"
Packit Service df60bb
			         " (expected 3 for RGB)\n", cinfo.output_components);
Packit Service df60bb
			goto error;
Packit Service df60bb
		}
Packit Service df60bb
		channels = 3;
Packit Service df60bb
	} else if(cinfo.out_color_space == JCS_CMYK) {
Packit Service df60bb
		jpeg_saved_marker_ptr marker;
Packit Service df60bb
		if(cinfo.output_components != 4) {
Packit Service df60bb
			gd_error("gd-jpeg: error: JPEG color quantization"
Packit Service df60bb
			         " request resulted in output_components == %d"
Packit Service df60bb
			         " (expected 4 for CMYK)\n", cinfo.output_components);
Packit Service df60bb
			goto error;
Packit Service df60bb
		}
Packit Service df60bb
		channels = 4;
Packit Service df60bb
Packit Service df60bb
		marker = cinfo.marker_list;
Packit Service df60bb
		while(marker) {
Packit Service df60bb
			if(	(marker->marker == (JPEG_APP0 + 14)) &&
Packit Service df60bb
			        (marker->data_length >= 12) &&
Packit Service df60bb
			        (!strncmp((const char *)marker->data, "Adobe", 5))) {
Packit Service df60bb
				inverted = 1;
Packit Service df60bb
				break;
Packit Service df60bb
			}
Packit Service df60bb
			marker = marker->next;
Packit Service df60bb
		}
Packit Service df60bb
	} else {
Packit Service df60bb
		gd_error("gd-jpeg: error: unexpected colorspace\n");
Packit Service df60bb
		goto error;
Packit Service df60bb
	}
Packit Service df60bb
#if BITS_IN_JSAMPLE == 12
Packit Service df60bb
	gd_error_ex(GD_ERROR,
Packit Service df60bb
		    "gd-jpeg: error: jpeg library was compiled for 12-bit\n"
Packit Service df60bb
		    "precision. This is mostly useless, because JPEGs on the web are\n"
Packit Service df60bb
		    "8-bit and such versions of the jpeg library won't read or write\n"
Packit Service df60bb
		    "them. GD doesn't support these unusual images. Edit your\n"
Packit Service df60bb
		    "jmorecfg.h file to specify the correct precision and completely\n"
Packit Service df60bb
		    "'make clean' and 'make install' libjpeg again. Sorry.\n");
Packit Service df60bb
	goto error;
Packit Service df60bb
#endif /* BITS_IN_JSAMPLE == 12 */
Packit Service df60bb
Packit Service df60bb
	row = gdCalloc(cinfo.output_width *channels, sizeof(JSAMPLE));
Packit Service df60bb
	if(row == 0) {
Packit Service df60bb
		gd_error("gd-jpeg: error: unable to allocate row for"
Packit Service df60bb
		         " JPEG scanline: gdCalloc returns NULL\n");
Packit Service df60bb
		goto error;
Packit Service df60bb
	}
Packit Service df60bb
	rowptr[0] = row;
Packit Service df60bb
	if(cinfo.out_color_space == JCS_CMYK) {
Packit Service df60bb
		for(i = 0; i < cinfo.output_height; i++) {
Packit Service df60bb
			register JSAMPROW currow = row;
Packit Service df60bb
			register int *tpix = im->tpixels[i];
Packit Service df60bb
			nrows = jpeg_read_scanlines(&cinfo, rowptr, 1);
Packit Service df60bb
			if(nrows != 1) {
Packit Service df60bb
				gd_error("gd-jpeg: error: jpeg_read_scanlines"
Packit Service df60bb
				         " returns %u, expected 1\n", nrows);
Packit Service df60bb
				goto error;
Packit Service df60bb
			}
Packit Service df60bb
			for(j = 0; j < cinfo.output_width; j++, currow += 4, tpix++) {
Packit Service df60bb
				*tpix = CMYKToRGB(currow[0], currow[1], currow[2], currow[3], inverted);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	} else {
Packit Service df60bb
		for(i = 0; i < cinfo.output_height; i++) {
Packit Service df60bb
			register JSAMPROW currow = row;
Packit Service df60bb
			register int *tpix = im->tpixels[i];
Packit Service df60bb
			nrows = jpeg_read_scanlines(&cinfo, rowptr, 1);
Packit Service df60bb
			if(nrows != 1) {
Packit Service df60bb
				gd_error("gd-jpeg: error: jpeg_read_scanlines"
Packit Service df60bb
				         " returns %u, expected 1\n", nrows);
Packit Service df60bb
				goto error;
Packit Service df60bb
			}
Packit Service df60bb
			for(j = 0; j < cinfo.output_width; j++, currow += 3, tpix++) {
Packit Service df60bb
				*tpix = gdTrueColor(currow[0], currow[1], currow[2]);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if(jpeg_finish_decompress (&cinfo) != TRUE) {
Packit Service df60bb
		gd_error("gd-jpeg: warning: jpeg_finish_decompress"
Packit Service df60bb
		         " reports suspended data source\n");
Packit Service df60bb
	}
Packit Service df60bb
	/* TBB 2.0.29: we should do our best to read whatever we can read, and a
Packit Service df60bb
	 * warning is a warning. A fatal error on warnings doesn't make sense. */
Packit Service df60bb
#if 0
Packit Service df60bb
	/* This was originally added by Truxton Fulton */
Packit Service df60bb
	if (cinfo.err->num_warnings > 0)
Packit Service df60bb
		goto error;
Packit Service df60bb
#endif
Packit Service df60bb
Packit Service df60bb
	jpeg_destroy_decompress(&cinfo);
Packit Service df60bb
	gdFree(row);
Packit Service df60bb
	return im;
Packit Service df60bb
Packit Service df60bb
error:
Packit Service df60bb
	jpeg_destroy_decompress(&cinfo);
Packit Service df60bb
Packit Service df60bb
	if(row) {
Packit Service df60bb
		gdFree(row);
Packit Service df60bb
	}
Packit Service df60bb
	if(im) {
Packit Service df60bb
		gdImageDestroy(im);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* A very basic conversion approach, TBB */
Packit Service df60bb
Packit Service df60bb
static int CMYKToRGB(int c, int m, int y, int k, int inverted)
Packit Service df60bb
{
Packit Service df60bb
	if(inverted) {
Packit Service df60bb
		c = 255 - c;
Packit Service df60bb
		m = 255 - m;
Packit Service df60bb
		y = 255 - y;
Packit Service df60bb
		k = 255 - k;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	return gdTrueColor(
Packit Service df60bb
	           (255 - c) * (255 - k) / 255,
Packit Service df60bb
	           (255 - m) * (255 - k) / 255,
Packit Service df60bb
	           (255 - y) * (255 - k) / 255
Packit Service df60bb
	       );
Packit Service df60bb
#if 0
Packit Service df60bb
	if (inverted) {
Packit Service df60bb
		c = 255 - c;
Packit Service df60bb
		m = 255 - m;
Packit Service df60bb
		y = 255 - y;
Packit Service df60bb
		k = 255 - k;
Packit Service df60bb
	}
Packit Service df60bb
	c = c * (255 - k) / 255 + k;
Packit Service df60bb
	if (c > 255) {
Packit Service df60bb
		c = 255;
Packit Service df60bb
	}
Packit Service df60bb
	if (c < 0) {
Packit Service df60bb
		c = 0;
Packit Service df60bb
	}
Packit Service df60bb
	m = m * (255 - k) / 255 + k;
Packit Service df60bb
	if (m > 255) {
Packit Service df60bb
		m = 255;
Packit Service df60bb
	}
Packit Service df60bb
	if (m < 0) {
Packit Service df60bb
		m = 0;
Packit Service df60bb
	}
Packit Service df60bb
	y = y * (255 - k) / 255 + k;
Packit Service df60bb
	if (y > 255) {
Packit Service df60bb
		y = 255;
Packit Service df60bb
	}
Packit Service df60bb
	if (y < 0) {
Packit Service df60bb
		y = 0;
Packit Service df60bb
	}
Packit Service df60bb
	c = 255 - c;
Packit Service df60bb
	m = 255 - m;
Packit Service df60bb
	y = 255 - y;
Packit Service df60bb
	return gdTrueColor (c, m, y);
Packit Service df60bb
#endif
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * gdIOCtx JPEG data sources and sinks, T. Boutell
Packit Service df60bb
 * almost a simple global replace from T. Lane's stdio versions.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
/* Expanded data source object for gdIOCtx input */
Packit Service df60bb
typedef struct {
Packit Service df60bb
	struct jpeg_source_mgr pub;	/* public fields */
Packit Service df60bb
	gdIOCtx *infile;			/* source stream */
Packit Service df60bb
	unsigned char *buffer;		/* start of buffer */
Packit Service df60bb
	boolean start_of_file;	/* have we gotten any data yet? */
Packit Service df60bb
}
Packit Service df60bb
my_source_mgr;
Packit Service df60bb
Packit Service df60bb
typedef my_source_mgr *my_src_ptr;
Packit Service df60bb
Packit Service df60bb
#define INPUT_BUF_SIZE	4096 /* choose an efficiently fread'able size */
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * Initialize source --- called by jpeg_read_header
Packit Service df60bb
 * before any data is actually read.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
void init_source(j_decompress_ptr cinfo)
Packit Service df60bb
{
Packit Service df60bb
	my_src_ptr src = (my_src_ptr)cinfo->src;
Packit Service df60bb
Packit Service df60bb
	/* We reset the empty-input-file flag for each image,
Packit Service df60bb
	 * but we don't clear the input buffer.
Packit Service df60bb
	 * This is correct behavior for reading a series of images from one source.
Packit Service df60bb
	 */
Packit Service df60bb
	src->start_of_file = TRUE;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * Fill the input buffer --- called whenever buffer is emptied.
Packit Service df60bb
 *
Packit Service df60bb
 * In typical applications, this should read fresh data into the buffer
Packit Service df60bb
 * (ignoring the current state of next_input_byte & bytes_in_buffer),
Packit Service df60bb
 * reset the pointer & count to the start of the buffer, and return TRUE
Packit Service df60bb
 * indicating that the buffer has been reloaded.  It is not necessary to
Packit Service df60bb
 * fill the buffer entirely, only to obtain at least one more byte.
Packit Service df60bb
 *
Packit Service df60bb
 * There is no such thing as an EOF return.  If the end of the file has been
Packit Service df60bb
 * reached, the routine has a choice of ERREXIT() or inserting fake data into
Packit Service df60bb
 * the buffer.  In most cases, generating a warning message and inserting a
Packit Service df60bb
 * fake EOI marker is the best course of action --- this will allow the
Packit Service df60bb
 * decompressor to output however much of the image is there.  However,
Packit Service df60bb
 * the resulting error message is misleading if the real problem is an empty
Packit Service df60bb
 * input file, so we handle that case specially.
Packit Service df60bb
 *
Packit Service df60bb
 * In applications that need to be able to suspend compression due to input
Packit Service df60bb
 * not being available yet, a FALSE return indicates that no more data can be
Packit Service df60bb
 * obtained right now, but more may be forthcoming later.  In this situation,
Packit Service df60bb
 * the decompressor will return to its caller (with an indication of the
Packit Service df60bb
 * number of scanlines it has read, if any).  The application should resume
Packit Service df60bb
 * decompression after it has loaded more data into the input buffer.  Note
Packit Service df60bb
 * that there are substantial restrictions on the use of suspension --- see
Packit Service df60bb
 * the documentation.
Packit Service df60bb
 *
Packit Service df60bb
 * When suspending, the decompressor will back up to a convenient restart point
Packit Service df60bb
 * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
Packit Service df60bb
 * indicate where the restart point will be if the current call returns FALSE.
Packit Service df60bb
 * Data beyond this point must be rescanned after resumption, so move it to
Packit Service df60bb
 * the front of the buffer rather than discarding it.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
#define END_JPEG_SEQUENCE "\r\n[*]--:END JPEG:--[*]\r\n"
Packit Service df60bb
Packit Service df60bb
boolean fill_input_buffer(j_decompress_ptr cinfo)
Packit Service df60bb
{
Packit Service df60bb
	my_src_ptr src = (my_src_ptr)cinfo->src;
Packit Service df60bb
	/* 2.0.12: signed size. Thanks to Geert Jansen */
Packit Service df60bb
	/* 2.0.14: some platforms (mingw-msys) don't have ssize_t. Call
Packit Service df60bb
	 * an int an int.
Packit Service df60bb
	 */
Packit Service df60bb
	int nbytes = 0;
Packit Service df60bb
	memset(src->buffer, 0, INPUT_BUF_SIZE);
Packit Service df60bb
Packit Service df60bb
	while(nbytes < INPUT_BUF_SIZE) {
Packit Service df60bb
		int got = gdGetBuf(src->buffer + nbytes, INPUT_BUF_SIZE - nbytes, src->infile);
Packit Service df60bb
Packit Service df60bb
		if((got == EOF) || (got == 0)) {
Packit Service df60bb
			/* EOF or error. If we got any data, don't worry about it.
Packit Service df60bb
			 * If we didn't, then this is unexpected. */
Packit Service df60bb
			if(!nbytes) {
Packit Service df60bb
				nbytes = -1;
Packit Service df60bb
			}
Packit Service df60bb
			break;
Packit Service df60bb
		}
Packit Service df60bb
		nbytes += got;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if(nbytes <= 0) {
Packit Service df60bb
		if(src->start_of_file) {
Packit Service df60bb
			/* Treat empty input file as fatal error */
Packit Service df60bb
			ERREXIT(cinfo, JERR_INPUT_EMPTY);
Packit Service df60bb
		}
Packit Service df60bb
		WARNMS(cinfo, JWRN_JPEG_EOF);
Packit Service df60bb
		/* Insert a fake EOI marker */
Packit Service df60bb
		src->buffer[0] = (unsigned char)0xFF;
Packit Service df60bb
		src->buffer[1] = (unsigned char)JPEG_EOI;
Packit Service df60bb
		nbytes = 2;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	src->pub.next_input_byte = src->buffer;
Packit Service df60bb
	src->pub.bytes_in_buffer = nbytes;
Packit Service df60bb
	src->start_of_file = FALSE;
Packit Service df60bb
Packit Service df60bb
	return TRUE;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * Skip data --- used to skip over a potentially large amount of
Packit Service df60bb
 * uninteresting data (such as an APPn marker).
Packit Service df60bb
 *
Packit Service df60bb
 * Writers of suspendable-input applications must note that skip_input_data
Packit Service df60bb
 * is not granted the right to give a suspension return.  If the skip extends
Packit Service df60bb
 * beyond the data currently in the buffer, the buffer can be marked empty so
Packit Service df60bb
 * that the next read will cause a fill_input_buffer call that can suspend.
Packit Service df60bb
 * Arranging for additional bytes to be discarded before reloading the input
Packit Service df60bb
 * buffer is the application writer's problem.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
Packit Service df60bb
{
Packit Service df60bb
	my_src_ptr src = (my_src_ptr)cinfo->src;
Packit Service df60bb
Packit Service df60bb
	/* Just a dumb implementation for now. Not clear that being smart is worth
Packit Service df60bb
	 * any trouble anyway --- large skips are infrequent.
Packit Service df60bb
	 */
Packit Service df60bb
	if(num_bytes > 0) {
Packit Service df60bb
		while(num_bytes > (long)src->pub.bytes_in_buffer) {
Packit Service df60bb
			num_bytes -= (long)src->pub.bytes_in_buffer;
Packit Service df60bb
			(void)fill_input_buffer(cinfo);
Packit Service df60bb
			/* note we assume that fill_input_buffer will never return FALSE,
Packit Service df60bb
			 * so suspension need not be handled.
Packit Service df60bb
			 */
Packit Service df60bb
		}
Packit Service df60bb
		src->pub.next_input_byte += (size_t)num_bytes;
Packit Service df60bb
		src->pub.bytes_in_buffer -= (size_t)num_bytes;
Packit Service df60bb
	}
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * An additional method that can be provided by data source modules is the
Packit Service df60bb
 * resync_to_restart method for error recovery in the presence of RST markers.
Packit Service df60bb
 * For the moment, this source module just uses the default resync method
Packit Service df60bb
 * provided by the JPEG library.  That method assumes that no backtracking
Packit Service df60bb
 * is possible.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * Terminate source --- called by jpeg_finish_decompress
Packit Service df60bb
 * after all data has been read.  Often a no-op.
Packit Service df60bb
 *
Packit Service df60bb
 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
Packit Service df60bb
 * application must deal with any cleanup that should happen even
Packit Service df60bb
 * for error exit.
Packit Service df60bb
 */
Packit Service df60bb
void term_source(j_decompress_ptr cinfo)
Packit Service df60bb
{
Packit Service df60bb
	(void)cinfo;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * Prepare for input from a gdIOCtx stream.
Packit Service df60bb
 * The caller must have already opened the stream, and is responsible
Packit Service df60bb
 * for closing it after finishing decompression.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
void jpeg_gdIOCtx_src(j_decompress_ptr cinfo, gdIOCtx *infile)
Packit Service df60bb
{
Packit Service df60bb
	my_src_ptr src;
Packit Service df60bb
Packit Service df60bb
	/* The source object and input buffer are made permanent so that a series
Packit Service df60bb
	 * of JPEG images can be read from the same file by calling jpeg_gdIOCtx_src
Packit Service df60bb
	 * only before the first one.  (If we discarded the buffer at the end of
Packit Service df60bb
	 * one image, we'd likely lose the start of the next one.)
Packit Service df60bb
	 * This makes it unsafe to use this manager and a different source
Packit Service df60bb
	 * manager serially with the same JPEG object.  Caveat programmer.
Packit Service df60bb
	 */
Packit Service df60bb
	if(cinfo->src == NULL) {
Packit Service df60bb
		/* first time for this JPEG object? */
Packit Service df60bb
		cinfo->src = (struct jpeg_source_mgr *)
Packit Service df60bb
		             (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT,
Packit Service df60bb
		                                        sizeof(my_source_mgr));
Packit Service df60bb
		src = (my_src_ptr)cinfo->src;
Packit Service df60bb
		src->buffer = (unsigned char *)
Packit Service df60bb
		              (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT,
Packit Service df60bb
		                      INPUT_BUF_SIZE * sizeof(unsigned char));
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	src = (my_src_ptr)cinfo->src;
Packit Service df60bb
	src->pub.init_source = init_source;
Packit Service df60bb
	src->pub.fill_input_buffer = fill_input_buffer;
Packit Service df60bb
	src->pub.skip_input_data = skip_input_data;
Packit Service df60bb
	src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
Packit Service df60bb
	src->pub.term_source = term_source;
Packit Service df60bb
	src->infile = infile;
Packit Service df60bb
	src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
Packit Service df60bb
	src->pub.next_input_byte = NULL; /* until buffer loaded */
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* Expanded data destination object for stdio output */
Packit Service df60bb
typedef struct {
Packit Service df60bb
	struct jpeg_destination_mgr pub; /* public fields */
Packit Service df60bb
	gdIOCtx *outfile; /* target stream */
Packit Service df60bb
	unsigned char *buffer; /* start of buffer */
Packit Service df60bb
}
Packit Service df60bb
my_destination_mgr;
Packit Service df60bb
Packit Service df60bb
typedef my_destination_mgr *my_dest_ptr;
Packit Service df60bb
Packit Service df60bb
#define OUTPUT_BUF_SIZE	4096 /* choose an efficiently fwrite'able size */
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * Initialize destination --- called by jpeg_start_compress
Packit Service df60bb
 * before any data is actually written.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
void init_destination(j_compress_ptr cinfo)
Packit Service df60bb
{
Packit Service df60bb
	my_dest_ptr dest = (my_dest_ptr)cinfo->dest;
Packit Service df60bb
Packit Service df60bb
	/* Allocate the output buffer --- it will be released when done with image */
Packit Service df60bb
	dest->buffer = (unsigned char *)
Packit Service df60bb
	               (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_IMAGE,
Packit Service df60bb
	                       OUTPUT_BUF_SIZE * sizeof(unsigned char));
Packit Service df60bb
Packit Service df60bb
	dest->pub.next_output_byte = dest->buffer;
Packit Service df60bb
	dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * Empty the output buffer --- called whenever buffer fills up.
Packit Service df60bb
 *
Packit Service df60bb
 * In typical applications, this should write the entire output buffer
Packit Service df60bb
 * (ignoring the current state of next_output_byte & free_in_buffer),
Packit Service df60bb
 * reset the pointer & count to the start of the buffer, and return TRUE
Packit Service df60bb
 * indicating that the buffer has been dumped.
Packit Service df60bb
 *
Packit Service df60bb
 * In applications that need to be able to suspend compression due to output
Packit Service df60bb
 * overrun, a FALSE return indicates that the buffer cannot be emptied now.
Packit Service df60bb
 * In this situation, the compressor will return to its caller (possibly with
Packit Service df60bb
 * an indication that it has not accepted all the supplied scanlines).  The
Packit Service df60bb
 * application should resume compression after it has made more room in the
Packit Service df60bb
 * output buffer.  Note that there are substantial restrictions on the use of
Packit Service df60bb
 * suspension --- see the documentation.
Packit Service df60bb
 *
Packit Service df60bb
 * When suspending, the compressor will back up to a convenient restart point
Packit Service df60bb
 * (typically the start of the current MCU). next_output_byte & free_in_buffer
Packit Service df60bb
 * indicate where the restart point will be if the current call returns FALSE.
Packit Service df60bb
 * Data beyond this point will be regenerated after resumption, so do not
Packit Service df60bb
 * write it out when emptying the buffer externally.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
boolean empty_output_buffer(j_compress_ptr cinfo)
Packit Service df60bb
{
Packit Service df60bb
	my_dest_ptr dest = (my_dest_ptr)cinfo->dest;
Packit Service df60bb
Packit Service df60bb
	if(gdPutBuf(dest->buffer, OUTPUT_BUF_SIZE, dest->outfile) != (size_t)OUTPUT_BUF_SIZE) {
Packit Service df60bb
		ERREXIT(cinfo, JERR_FILE_WRITE);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	dest->pub.next_output_byte = dest->buffer;
Packit Service df60bb
	dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
Packit Service df60bb
Packit Service df60bb
	return TRUE;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * Terminate destination --- called by jpeg_finish_compress
Packit Service df60bb
 * after all data has been written.  Usually needs to flush buffer.
Packit Service df60bb
 *
Packit Service df60bb
 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
Packit Service df60bb
 * application must deal with any cleanup that should happen even
Packit Service df60bb
 * for error exit.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
void term_destination(j_compress_ptr cinfo)
Packit Service df60bb
{
Packit Service df60bb
	my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
Packit Service df60bb
	int datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
Packit Service df60bb
Packit Service df60bb
	/* Write any data remaining in the buffer */
Packit Service df60bb
	if(datacount > 0) {
Packit Service df60bb
		if(gdPutBuf(dest->buffer, datacount, dest->outfile) != datacount) {
Packit Service df60bb
			ERREXIT(cinfo, JERR_FILE_WRITE);
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
 * Prepare for output to a stdio stream.
Packit Service df60bb
 * The caller must have already opened the stream, and is responsible
Packit Service df60bb
 * for closing it after finishing compression.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
void jpeg_gdIOCtx_dest(j_compress_ptr cinfo, gdIOCtx *outfile)
Packit Service df60bb
{
Packit Service df60bb
	my_dest_ptr dest;
Packit Service df60bb
Packit Service df60bb
	/* The destination object is made permanent so that multiple JPEG images
Packit Service df60bb
	 * can be written to the same file without re-executing jpeg_stdio_dest.
Packit Service df60bb
	 * This makes it dangerous to use this manager and a different destination
Packit Service df60bb
	 * manager serially with the same JPEG object, because their private object
Packit Service df60bb
	 * sizes may be different.  Caveat programmer.
Packit Service df60bb
	 */
Packit Service df60bb
	if(cinfo->dest == NULL) {
Packit Service df60bb
		/* first time for this JPEG object? */
Packit Service df60bb
		cinfo->dest = (struct jpeg_destination_mgr *)
Packit Service df60bb
		              (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT,
Packit Service df60bb
		                      sizeof(my_destination_mgr));
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	dest = (my_dest_ptr)cinfo->dest;
Packit Service df60bb
	dest->pub.init_destination = init_destination;
Packit Service df60bb
	dest->pub.empty_output_buffer = empty_output_buffer;
Packit Service df60bb
	dest->pub.term_destination = term_destination;
Packit Service df60bb
	dest->outfile = outfile;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
#endif /* HAVE_LIBJPEG */