mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-06-11 00:23:21 +03:00
Merge pull request #219 from wiredfool/maxblock
Fixing buffer size for JPEGs with large exif
This commit is contained in:
commit
5c51ae02f3
|
@ -554,6 +554,7 @@ def _save(im, fp, filename):
|
||||||
info.get("exif", b"")
|
info.get("exif", b"")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# if we optimize, libjpeg needs a buffer big enough to hold the whole image in a shot.
|
# if we optimize, libjpeg needs a buffer big enough to hold the whole image in a shot.
|
||||||
# Guessing on the size, at im.size bytes. (raw pizel size is channels*size, this
|
# Guessing on the size, at im.size bytes. (raw pizel size is channels*size, this
|
||||||
# is a value that's been used in a django patch.
|
# is a value that's been used in a django patch.
|
||||||
|
@ -562,6 +563,10 @@ def _save(im, fp, filename):
|
||||||
if "optimize" in info:
|
if "optimize" in info:
|
||||||
bufsize = im.size[0]*im.size[1]
|
bufsize = im.size[0]*im.size[1]
|
||||||
|
|
||||||
|
# The exif info needs to be written as one block, + APP1, + one spare byte.
|
||||||
|
# Ensure that our buffer is big enough
|
||||||
|
bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif",b"")) + 5 )
|
||||||
|
|
||||||
ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)], bufsize)
|
ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)], bufsize)
|
||||||
|
|
||||||
def _save_cjpeg(im, fp, filename):
|
def _save_cjpeg(im, fp, filename):
|
||||||
|
|
|
@ -120,6 +120,12 @@ def test_optimize_large_buffer():
|
||||||
im = Image.new("RGB", (4096,4096), 0xff3333)
|
im = Image.new("RGB", (4096,4096), 0xff3333)
|
||||||
im.save(f, format="JPEG", optimize=True)
|
im.save(f, format="JPEG", optimize=True)
|
||||||
|
|
||||||
|
def test_large_exif():
|
||||||
|
#https://github.com/python-imaging/Pillow/issues/148
|
||||||
|
f = tempfile('temp.jpg')
|
||||||
|
im = lena()
|
||||||
|
im.save(f,'JPEG', quality=90, exif=b"1"*65532)
|
||||||
|
|
||||||
def test_progressive():
|
def test_progressive():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
im2 = roundtrip(lena(), progressive=1)
|
im2 = roundtrip(lena(), progressive=1)
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include "Imaging.h"
|
#include "Imaging.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBJPEG
|
#ifdef HAVE_LIBJPEG
|
||||||
|
|
||||||
#undef HAVE_PROTOTYPES
|
#undef HAVE_PROTOTYPES
|
||||||
#undef HAVE_STDLIB_H
|
#undef HAVE_STDLIB_H
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
#include "Jpeg.h"
|
#include "Jpeg.h"
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* Suspending output handler */
|
/* Suspending output handler */
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
|
@ -64,16 +64,16 @@ jpeg_buffer_dest(j_compress_ptr cinfo, JPEGDESTINATION* destination)
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* Error handler */
|
/* Error handler */
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
error(j_common_ptr cinfo)
|
error(j_common_ptr cinfo)
|
||||||
{
|
{
|
||||||
JPEGERROR* error;
|
JPEGERROR* error;
|
||||||
error = (JPEGERROR*) cinfo->err;
|
error = (JPEGERROR*) cinfo->err;
|
||||||
(*cinfo->err->output_message) (cinfo);
|
(*cinfo->err->output_message) (cinfo);
|
||||||
longjmp(error->setjmp_buffer, 1);
|
longjmp(error->setjmp_buffer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -146,59 +146,59 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
|
|
||||||
/* Use custom quantization tables */
|
/* Use custom quantization tables */
|
||||||
if (context->qtables) {
|
if (context->qtables) {
|
||||||
int i;
|
int i;
|
||||||
int quality = 100;
|
int quality = 100;
|
||||||
if (context->quality > 0) {
|
if (context->quality > 0) {
|
||||||
quality = context->quality;
|
quality = context->quality;
|
||||||
}
|
}
|
||||||
for (i = 0; i < sizeof(context->qtables)/sizeof(unsigned int); i++) {
|
for (i = 0; i < sizeof(context->qtables)/sizeof(unsigned int); i++) {
|
||||||
// TODO: Should add support for none baseline
|
// TODO: Should add support for none baseline
|
||||||
jpeg_add_quant_table(&context->cinfo, i, context->qtables[i],
|
jpeg_add_quant_table(&context->cinfo, i, context->qtables[i],
|
||||||
quality, TRUE);
|
quality, TRUE);
|
||||||
}
|
}
|
||||||
} else if (context->quality > 0) {
|
} else if (context->quality > 0) {
|
||||||
jpeg_set_quality(&context->cinfo, context->quality, 1);
|
jpeg_set_quality(&context->cinfo, context->quality, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set subsampling options */
|
/* Set subsampling options */
|
||||||
switch (context->subsampling)
|
switch (context->subsampling)
|
||||||
{
|
{
|
||||||
case 0: /* 1x1 1x1 1x1 (4:4:4) : None */
|
case 0: /* 1x1 1x1 1x1 (4:4:4) : None */
|
||||||
{
|
{
|
||||||
context->cinfo.comp_info[0].h_samp_factor = 1;
|
context->cinfo.comp_info[0].h_samp_factor = 1;
|
||||||
context->cinfo.comp_info[0].v_samp_factor = 1;
|
context->cinfo.comp_info[0].v_samp_factor = 1;
|
||||||
context->cinfo.comp_info[1].h_samp_factor = 1;
|
context->cinfo.comp_info[1].h_samp_factor = 1;
|
||||||
context->cinfo.comp_info[1].v_samp_factor = 1;
|
context->cinfo.comp_info[1].v_samp_factor = 1;
|
||||||
context->cinfo.comp_info[2].h_samp_factor = 1;
|
context->cinfo.comp_info[2].h_samp_factor = 1;
|
||||||
context->cinfo.comp_info[2].v_samp_factor = 1;
|
context->cinfo.comp_info[2].v_samp_factor = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: /* 2x1, 1x1, 1x1 (4:2:2) : Medium */
|
case 1: /* 2x1, 1x1, 1x1 (4:2:2) : Medium */
|
||||||
{
|
{
|
||||||
context->cinfo.comp_info[0].h_samp_factor = 2;
|
context->cinfo.comp_info[0].h_samp_factor = 2;
|
||||||
context->cinfo.comp_info[0].v_samp_factor = 1;
|
context->cinfo.comp_info[0].v_samp_factor = 1;
|
||||||
context->cinfo.comp_info[1].h_samp_factor = 1;
|
context->cinfo.comp_info[1].h_samp_factor = 1;
|
||||||
context->cinfo.comp_info[1].v_samp_factor = 1;
|
context->cinfo.comp_info[1].v_samp_factor = 1;
|
||||||
context->cinfo.comp_info[2].h_samp_factor = 1;
|
context->cinfo.comp_info[2].h_samp_factor = 1;
|
||||||
context->cinfo.comp_info[2].v_samp_factor = 1;
|
context->cinfo.comp_info[2].v_samp_factor = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: /* 2x2, 1x1, 1x1 (4:1:1) : High */
|
case 2: /* 2x2, 1x1, 1x1 (4:1:1) : High */
|
||||||
{
|
{
|
||||||
context->cinfo.comp_info[0].h_samp_factor = 2;
|
context->cinfo.comp_info[0].h_samp_factor = 2;
|
||||||
context->cinfo.comp_info[0].v_samp_factor = 2;
|
context->cinfo.comp_info[0].v_samp_factor = 2;
|
||||||
context->cinfo.comp_info[1].h_samp_factor = 1;
|
context->cinfo.comp_info[1].h_samp_factor = 1;
|
||||||
context->cinfo.comp_info[1].v_samp_factor = 1;
|
context->cinfo.comp_info[1].v_samp_factor = 1;
|
||||||
context->cinfo.comp_info[2].h_samp_factor = 1;
|
context->cinfo.comp_info[2].h_samp_factor = 1;
|
||||||
context->cinfo.comp_info[2].v_samp_factor = 1;
|
context->cinfo.comp_info[2].v_samp_factor = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
/* Use the lib's default */
|
/* Use the lib's default */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (context->progressive)
|
if (context->progressive)
|
||||||
jpeg_simple_progression(&context->cinfo);
|
jpeg_simple_progression(&context->cinfo);
|
||||||
context->cinfo.smoothing_factor = context->smooth;
|
context->cinfo.smoothing_factor = context->smooth;
|
||||||
|
@ -219,24 +219,29 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
jpeg_start_compress(&context->cinfo, FALSE);
|
jpeg_start_compress(&context->cinfo, FALSE);
|
||||||
/* suppress extra section */
|
/* suppress extra section */
|
||||||
context->extra_offset = context->extra_size;
|
context->extra_offset = context->extra_size;
|
||||||
//add exif header
|
|
||||||
if (context->rawExifLen > 0)
|
|
||||||
jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* interchange stream */
|
/* interchange stream */
|
||||||
jpeg_start_compress(&context->cinfo, TRUE);
|
jpeg_start_compress(&context->cinfo, TRUE);
|
||||||
//add exif header
|
break;
|
||||||
if (context->rawExifLen > 0)
|
|
||||||
jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
state->state++;
|
state->state++;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
// check for exif len + 'APP1' header bytes
|
||||||
|
if (context->rawExifLen + 5 > context->destination.pub.free_in_buffer){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//add exif header
|
||||||
|
if (context->rawExifLen > 0){
|
||||||
|
jpeg_write_marker(&context->cinfo, JPEG_APP0+1,
|
||||||
|
(unsigned char*)context->rawExif, context->rawExifLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->state++;
|
||||||
|
/* fall through */
|
||||||
|
case 3:
|
||||||
|
|
||||||
if (context->extra) {
|
if (context->extra) {
|
||||||
/* copy extra buffer to output buffer */
|
/* copy extra buffer to output buffer */
|
||||||
|
@ -253,9 +258,12 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
} else
|
} else
|
||||||
state->state++;
|
state->state++;
|
||||||
|
|
||||||
case 3:
|
case 4:
|
||||||
|
if (1024 > context->destination.pub.free_in_buffer){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ok = 1;
|
ok = 1;
|
||||||
while (state->y < state->ysize) {
|
while (state->y < state->ysize) {
|
||||||
|
@ -273,7 +281,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
state->state++;
|
state->state++;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
case 4:
|
case 5:
|
||||||
|
|
||||||
/* Finish compression */
|
/* Finish compression */
|
||||||
if (context->destination.pub.free_in_buffer < 100)
|
if (context->destination.pub.free_in_buffer < 100)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user