42static const char *
const GD_JPEG_VERSION =
"1.0";
44typedef struct _jmpbuf_wrapper
50static void php_jpeg_emit_message(j_common_ptr jpeg_info,
int level)
52 char message[JMSG_LENGTH_MAX];
53 jmpbuf_wrapper *jmpbufw;
54 int ignore_warning = 0;
56 jmpbufw = (jmpbuf_wrapper *) jpeg_info->client_data;
59 ignore_warning = jmpbufw->ignore_warning;
62 (jpeg_info->err->format_message)(jpeg_info,message);
69 if ((jpeg_info->err->num_warnings == 0) || (jpeg_info->err->trace_level >= 3)) {
70 if (!ignore_warning) {
71 gd_error(
"gd-jpeg, libjpeg: recoverable error: %s\n", message);
75 jpeg_info->err->num_warnings++;
78 if (jpeg_info->err->trace_level >= level) {
79 if (!ignore_warning) {
80 gd_error(
"gd-jpeg, libjpeg: strace message: %s\n", message);
88static void fatal_jpeg_error (j_common_ptr cinfo)
90 jmpbuf_wrapper *jmpbufw;
91 char buffer[JMSG_LENGTH_MAX];
93 (*cinfo->err->format_message)(cinfo,
buffer);
96 jmpbufw = (jmpbuf_wrapper *) cinfo->client_data;
100 longjmp (jmpbufw->jmpbuf, 1);
101 gd_error_ex(
GD_ERROR,
"gd-jpeg: EXTREMELY fatal error: longjmp returned control; terminating");
103 gd_error_ex(
GD_ERROR,
"gd-jpeg: EXTREMELY fatal error: jmpbuf unrecoverable; terminating");
111 switch(JPEG_LIB_VERSION) {
125 return "9 compatible";
155 if (!_gdImageJpegCtx(im,
out, quality)) {
165void jpeg_gdIOCtx_dest (j_compress_ptr cinfo,
gdIOCtx * outfile);
169 _gdImageJpegCtx(im, outfile, quality);
175 struct jpeg_compress_struct cinfo;
176 struct jpeg_error_mgr jerr;
181 jmpbuf_wrapper jmpbufw;
185 memset (&cinfo, 0,
sizeof (cinfo));
186 memset (&jerr, 0,
sizeof (jerr));
188 cinfo.err = jpeg_std_error (&jerr);
189 cinfo.client_data = &jmpbufw;
190 if (setjmp (jmpbufw.jmpbuf) != 0) {
198 cinfo.err->error_exit = fatal_jpeg_error;
200 jpeg_create_compress (&cinfo);
202 cinfo.image_width = im->
sx;
203 cinfo.image_height = im->
sy;
204 cinfo.input_components = 3;
205 cinfo.in_color_space = JCS_RGB;
206 jpeg_set_defaults (&cinfo);
208 cinfo.density_unit = 1;
209 cinfo.X_density = im->
res_x;
210 cinfo.Y_density = im->
res_y;
213 jpeg_set_quality (&cinfo, quality,
TRUE);
218 jpeg_simple_progression (&cinfo);
221 jpeg_gdIOCtx_dest (&cinfo, outfile);
224 memset(row, 0, cinfo.image_width * cinfo.input_components *
sizeof(
JSAMPLE));
227 jpeg_start_compress (&cinfo,
TRUE);
230 snprintf(comment,
sizeof(comment)-1,
"CREATOR: gd-jpeg v%s (using IJG JPEG v%d), quality = %d\n", GD_JPEG_VERSION, JPEG_LIB_VERSION, quality);
232 snprintf(comment,
sizeof(comment)-1,
"CREATOR: gd-jpeg v%s (using IJG JPEG v%d), default quality\n", GD_JPEG_VERSION, JPEG_LIB_VERSION);
234 jpeg_write_marker (&cinfo, JPEG_COM, (
unsigned char *) comment, (
unsigned int)
strlen (comment));
237#if BITS_IN_JSAMPLE == 12
238 gd_error(
"gd-jpeg: error: jpeg library was compiled for 12-bit precision. This is mostly useless, because JPEGs on the web are 8-bit and such versions of the jpeg library won't read or write them. GD doesn't support these unusual images. Edit your jmorecfg.h file to specify the correct precision and completely 'make clean' and 'make install' libjpeg again. Sorry");
242 for (i = 0; i < im->
sy; i++) {
243 for (jidx = 0,
j = 0;
j < im->
sx;
j++) {
251 nlines = jpeg_write_scanlines (&cinfo, rowptr, 1);
257 for (i = 0; i < im->
sy; i++) {
258 for (jidx = 0,
j = 0;
j < im->
sx;
j++) {
265#if BITS_IN_JSAMPLE == 8
266 row[jidx++] = im->
red[idx];
267 row[jidx++] = im->
green[idx];
268 row[jidx++] = im->
blue[idx];
269#elif BITS_IN_JSAMPLE == 12
270 row[jidx++] = im->
red[idx] << 4;
271 row[jidx++] = im->
green[idx] << 4;
272 row[jidx++] = im->
blue[idx] << 4;
274#error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12
278 nlines = jpeg_write_scanlines (&cinfo, rowptr, 1);
285 jpeg_finish_compress (&cinfo);
286 jpeg_destroy_compress (&cinfo);
321void jpeg_gdIOCtx_src (j_decompress_ptr cinfo,
gdIOCtx * infile);
323static int CMYKToRGB(
int c,
int m,
int y,
int k,
int inverted);
337 struct jpeg_decompress_struct cinfo;
338 struct jpeg_error_mgr jerr;
339 jmpbuf_wrapper jmpbufw;
350 memset (&cinfo, 0,
sizeof (cinfo));
351 memset (&jerr, 0,
sizeof (jerr));
353 jmpbufw.ignore_warning = ignore_warning;
355 cinfo.err = jpeg_std_error (&jerr);
356 cinfo.client_data = &jmpbufw;
357 cinfo.err->emit_message = php_jpeg_emit_message;
359 if (setjmp (jmpbufw.jmpbuf) != 0) {
370 cinfo.err->error_exit = fatal_jpeg_error;
372 jpeg_create_decompress (&cinfo);
374 jpeg_gdIOCtx_src (&cinfo, infile);
377 jpeg_save_markers(&cinfo, JPEG_APP0 + 14, 256);
380 if (
retval != JPEG_HEADER_OK) {
384 if (cinfo.image_height >
INT_MAX) {
385 gd_error_ex(
GD_WARNING,
"gd-jpeg: warning: JPEG image height (%u) is greater than INT_MAX (%d) (and thus greater than gd can handle)", cinfo.image_height,
INT_MAX);
388 if (cinfo.image_width >
INT_MAX) {
389 gd_error_ex(
GD_WARNING,
"gd-jpeg: warning: JPEG image width (%u) is greater than INT_MAX (%d) (and thus greater than gd can handle)", cinfo.image_width,
INT_MAX);
394 gd_error(
"gd-jpeg error: cannot allocate gdImage struct");
399 switch (cinfo.density_unit) {
401 im->
res_x = cinfo.X_density;
402 im->
res_y = cinfo.Y_density;
413 if ((cinfo.jpeg_color_space == JCS_CMYK) || (cinfo.jpeg_color_space == JCS_YCCK)) {
414 cinfo.out_color_space = JCS_CMYK;
416 cinfo.out_color_space = JCS_RGB;
419 if (jpeg_start_decompress (&cinfo) !=
TRUE) {
420 gd_error(
"gd-jpeg: warning: jpeg_start_decompress reports suspended data source");
436 if (cinfo.out_color_space == JCS_RGB) {
437 if (cinfo.output_components != 3) {
438 gd_error_ex(
GD_WARNING,
"gd-jpeg: error: JPEG color quantization request resulted in output_components == %d (expected 3 for RGB)", cinfo.output_components);
442 }
else if (cinfo.out_color_space == JCS_CMYK) {
443 jpeg_saved_marker_ptr marker;
444 if (cinfo.output_components != 4) {
445 gd_error_ex(
GD_WARNING,
"gd-jpeg: error: JPEG color quantization request resulted in output_components == %d (expected 4 for CMYK)", cinfo.output_components);
449 marker = cinfo.marker_list;
451 if ((marker->marker == (JPEG_APP0 + 14)) && (marker->data_length >= 12) && (!
strncmp((
const char *) marker->data,
"Adobe", 5))) {
455 marker = marker->next;
462#if BITS_IN_JSAMPLE == 12
463 gd_error(
"gd-jpeg: error: jpeg library was compiled for 12-bit precision. This is mostly useless, because JPEGs on the web are 8-bit and such versions of the jpeg library won't read or write them. GD doesn't support these unusual images. Edit your jmorecfg.h file to specify the correct precision and completely 'make clean' and 'make install' libjpeg again. Sorry.");
468 memset(row, 0, cinfo.output_width * channels *
sizeof(
JSAMPLE));
471 if (cinfo.out_color_space == JCS_CMYK) {
472 for (i = 0; i < cinfo.output_height; i++) {
474 register int *tpix = im->
tpixels[i];
475 nrows = jpeg_read_scanlines (&cinfo, rowptr, 1);
480 for (
j = 0;
j < cinfo.output_width;
j++, currow += 4, tpix++) {
481 *tpix = CMYKToRGB (currow[0], currow[1], currow[2], currow[3], inverted);
485 for (i = 0; i < cinfo.output_height; i++) {
487 register int *tpix = im->
tpixels[i];
488 nrows = jpeg_read_scanlines (&cinfo, rowptr, 1);
493 for (
j = 0;
j < cinfo.output_width;
j++, currow += 3, tpix++) {
494 *tpix =
gdTrueColor (currow[0], currow[1], currow[2]);
499 if (jpeg_finish_decompress (&cinfo) !=
TRUE) {
500 gd_error(
"gd-jpeg: warning: jpeg_finish_decompress reports suspended data source");
502 if (!ignore_warning) {
503 if (cinfo.err->num_warnings > 0) {
508 jpeg_destroy_decompress (&cinfo);
514 jpeg_destroy_decompress (&cinfo);
525static int CMYKToRGB(
int c,
int m,
int y,
int k,
int inverted)
533 return gdTrueColor((255 - c) * (255 - k) / 255, (255 - m) * (255 - k) / 255, (255 - y) * (255 - k) / 255);
546 struct jpeg_source_mgr pub;
550 boolean start_of_file;
553typedef my_source_mgr *my_src_ptr;
555#define INPUT_BUF_SIZE 4096
562void init_source (j_decompress_ptr cinfo)
564 my_src_ptr src = (my_src_ptr) cinfo->src;
570 src->start_of_file =
TRUE;
607#define END_JPEG_SEQUENCE "\r\n[*]--:END JPEG:--[*]\r\n"
609boolean fill_input_buffer (j_decompress_ptr cinfo)
611 my_src_ptr src = (my_src_ptr) cinfo->src;
617 memset(src->buffer, 0, INPUT_BUF_SIZE);
619 while (nbytes < INPUT_BUF_SIZE) {
620 int got =
gdGetBuf(src->buffer + nbytes, INPUT_BUF_SIZE - nbytes, src->infile);
622 if (got == EOF || got == 0) {
633 if (src->start_of_file) {
634 ERREXIT (cinfo, JERR_INPUT_EMPTY);
636 WARNMS (cinfo, JWRN_JPEG_EOF);
638 src->buffer[0] = (
unsigned char) 0xFF;
639 src->buffer[1] = (
unsigned char) JPEG_EOI;
643 src->pub.next_input_byte = src->buffer;
644 src->pub.bytes_in_buffer = nbytes;
645 src->start_of_file =
FALSE;
663void skip_input_data (j_decompress_ptr cinfo,
long num_bytes)
665 my_src_ptr src = (my_src_ptr) cinfo->src;
671 while (num_bytes > (
long) src->pub.bytes_in_buffer) {
672 num_bytes -= (long) src->pub.bytes_in_buffer;
673 (
void) fill_input_buffer (cinfo);
678 src->pub.next_input_byte += (size_t) num_bytes;
679 src->pub.bytes_in_buffer -= (size_t) num_bytes;
702void term_source (j_decompress_ptr cinfo)
706 my_src_ptr src = (my_src_ptr) cinfo->src;
717void jpeg_gdIOCtx_src (j_decompress_ptr cinfo,
gdIOCtx * infile)
728 if (cinfo->src ==
NULL) {
729 cinfo->src = (
struct jpeg_source_mgr *)
730 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof (my_source_mgr));
731 src = (my_src_ptr) cinfo->src;
732 src->buffer = (
unsigned char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE *
sizeof (
unsigned char));
736 src = (my_src_ptr) cinfo->src;
737 src->pub.init_source = init_source;
738 src->pub.fill_input_buffer = fill_input_buffer;
739 src->pub.skip_input_data = skip_input_data;
740 src->pub.resync_to_restart = jpeg_resync_to_restart;
741 src->pub.term_source = term_source;
742 src->infile = infile;
743 src->pub.bytes_in_buffer = 0;
744 src->pub.next_input_byte =
NULL;
751 struct jpeg_destination_mgr pub;
756typedef my_destination_mgr *my_dest_ptr;
758#define OUTPUT_BUF_SIZE 4096
765void init_destination (j_compress_ptr cinfo)
767 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
770 dest->buffer = (
unsigned char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE *
sizeof (
unsigned char));
772 dest->pub.next_output_byte = dest->buffer;
773 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
800boolean empty_output_buffer (j_compress_ptr cinfo)
802 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
804 if (
gdPutBuf (dest->buffer, OUTPUT_BUF_SIZE, dest->outfile) != (
size_t) OUTPUT_BUF_SIZE) {
805 ERREXIT (cinfo, JERR_FILE_WRITE);
808 dest->pub.next_output_byte = dest->buffer;
809 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
824void term_destination (j_compress_ptr cinfo)
826 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
827 size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
830 if (datacount > 0 && ((
size_t)
gdPutBuf (dest->buffer, datacount, dest->outfile) != datacount)) {
831 ERREXIT (cinfo, JERR_FILE_WRITE);
842void jpeg_gdIOCtx_dest (j_compress_ptr cinfo,
gdIOCtx * outfile)
852 if (cinfo->dest ==
NULL) {
853 cinfo->dest = (
struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof (my_destination_mgr));
856 dest = (my_dest_ptr) cinfo->dest;
857 dest->pub.init_destination = init_destination;
858 dest->pub.empty_output_buffer = empty_output_buffer;
859 dest->pub.term_destination = term_destination;
860 dest->outfile = outfile;
memset(ptr, 0, type->size)
#define gdTrueColorGetBlue(c)
void * gdDPExtractData(struct gdIOCtx *ctx, int *size)
void gdImageJpegCtx(gdImagePtr im, gdIOCtx *out, int quality)
void * gdImageJpegPtr(gdImagePtr im, int *size, int quality)
#define gdTrueColorGetGreen(c)
gdImagePtr gdImageCreateFromJpegCtx(gdIOCtx *infile)
const char * gdJpegGetVersionString(void)
gdImagePtr gdImageCreateFromJpeg(FILE *infile)
gdImagePtr gdImageCreateFromJpegPtr(int size, void *data)
gdImagePtr gdImageCreateFromJpegCtxEx(gdIOCtx *infile, int ignore_warning)
#define gdTrueColorGetRed(c)
gdIOCtx * gdNewFileCtx(FILE *)
gdImagePtr gdImageCreateFromJpegEx(FILE *infile, int ignore_warning)
void gdImageJpeg(gdImagePtr im, FILE *out, int quality)
gdIOCtx * gdNewDynamicCtx(int, void *)
#define gdTrueColor(r, g, b)
gdImagePtr gdImageCreateFromJpegPtrEx(int size, void *data, int ignore_warning)
gdIOCtx * gdNewDynamicCtxEx(int size, void *data, int freeFlag)
#define gdImageGetInterlaced(im)
int gdGetBuf(void *buf, int size, gdIOCtx *ctx)
int gdPutBuf(const void *buf, int size, gdIOCtx *ctx)
void gdImageDestroy(gdImagePtr im)
void gd_error(const char *format,...)
void gd_error_ex(int priority, const char *format,...)
void gdImageInterlace(gdImagePtr im, int interlaceArg)
gdImagePtr gdImageCreateTrueColor(int sx, int sy)
void(* gd_free)(struct gdIOCtx *)
#define safe_emalloc(nmemb, size, offset)
strncmp(string $string1, string $string2, int $length)
exit(string|int $status=0)
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)