Merge pull request #36 from d-schmidt/feature

Bugfix + 3 features
This commit is contained in:
Alex Clark ☺ 2013-01-10 14:26:31 -08:00
commit a635a1dcb1
8 changed files with 81 additions and 24 deletions

View File

@ -248,7 +248,12 @@ def _save(im, fp, filename):
rawmode = "L" rawmode = "L"
# header # header
for s in getheader(imOut, im.encoderinfo): try:
palette = im.encoderinfo["palette"]
except KeyError:
palette = None
for s in getheader(imOut, palette, im.encoderinfo):
fp.write(s) fp.write(s)
flags = 0 flags = 0
@ -319,7 +324,7 @@ def _save_netpbm(im, fp, filename):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# GIF utilities # GIF utilities
def getheader(im, info=None): def getheader(im, palette, info=None):
"""Return a list of strings representing a GIF header""" """Return a list of strings representing a GIF header"""
optimize = info and info.get("optimize", 0) optimize = info and info.get("optimize", 0)
@ -347,7 +352,13 @@ def getheader(im, info=None):
# global palette # global palette
if im.mode == "P": if im.mode == "P":
# colour palette # colour palette
s.append(im.im.getpalette("RGB")[:maxcolor*3]) if palette is not None and Image.isBytesType(palette):
paletteBytes = palette
else:
paletteBytes =im.im.getpalette("RGB")[:maxcolor*3]
s.append(paletteBytes)
else: else:
# greyscale # greyscale
for i in range(maxcolor): for i in range(maxcolor):

View File

@ -35,6 +35,8 @@ MAXBLOCK = 65536
SAFEBLOCK = 1024*1024 SAFEBLOCK = 1024*1024
LOAD_TRUNCATED_IMAGES = False
ERRORS = { ERRORS = {
-1: "image buffer overrun error", -1: "image buffer overrun error",
-2: "decoding error", -2: "decoding error",
@ -196,10 +198,22 @@ class ImageFile(Image.Image):
b = prefix b = prefix
t = len(b) t = len(b)
while True: while True:
s = read(self.decodermaxblock) try:
if not s: s = read(self.decodermaxblock)
except IndexError as ie: # truncated png/gif
if LOAD_TRUNCATED_IMAGES:
break
else:
raise IndexError(ie)
if not s: # truncated jpeg
self.tile = [] self.tile = []
raise IOError("image file is truncated (%d bytes not processed)" % len(b))
if LOAD_TRUNCATED_IMAGES:
break
else:
raise IOError("image file is truncated (%d bytes not processed)" % len(b))
b = b + s b = b + s
n, e = d.decode(b) n, e = d.decode(b)
if n < 0: if n < 0:
@ -212,7 +226,9 @@ class ImageFile(Image.Image):
self.fp = None # might be shared self.fp = None # might be shared
if not self.map and e < 0: if not LOAD_TRUNCATED_IMAGES and not self.map and e < 0:
# Note: If loading a truncated image results in an all black Image,
# the decoder wasn't able to decode anything.
raise_ioerror(e) raise_ioerror(e)
# post processing # post processing

View File

@ -465,6 +465,7 @@ def _save(im, fp, filename):
dpi[0], dpi[1], dpi[0], dpi[1],
subsampling, subsampling,
extra, extra,
info.get("exif", "")
) )
ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)]) ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)])

View File

@ -522,19 +522,19 @@ static struct PyMethodDef cms_profile_methods[] = {
static PyObject* static PyObject*
cms_profile_getattr_product_name(CmsProfileObject* self, void* closure) cms_profile_getattr_product_name(CmsProfileObject* self, void* closure)
{ {
return PyUnicode_FromString(cmsTakeProductName(self->profile)); return PyUnicode_DecodeFSDefault(cmsTakeProductName(self->profile));
} }
static PyObject* static PyObject*
cms_profile_getattr_product_desc(CmsProfileObject* self, void* closure) cms_profile_getattr_product_desc(CmsProfileObject* self, void* closure)
{ {
return PyUnicode_FromString(cmsTakeProductDesc(self->profile)); return PyUnicode_DecodeFSDefault(cmsTakeProductDesc(self->profile));
} }
static PyObject* static PyObject*
cms_profile_getattr_product_info(CmsProfileObject* self, void* closure) cms_profile_getattr_product_info(CmsProfileObject* self, void* closure)
{ {
return PyUnicode_FromString(cmsTakeProductInfo(self->profile)); return PyUnicode_DecodeFSDefault(cmsTakeProductInfo(self->profile));
} }
static PyObject* static PyObject*
@ -546,13 +546,13 @@ cms_profile_getattr_rendering_intent(CmsProfileObject* self, void* closure)
static PyObject* static PyObject*
cms_profile_getattr_pcs(CmsProfileObject* self, void* closure) cms_profile_getattr_pcs(CmsProfileObject* self, void* closure)
{ {
return PyUnicode_FromString(findICmode(cmsGetPCS(self->profile))); return PyUnicode_DecodeFSDefault(findICmode(cmsGetPCS(self->profile)));
} }
static PyObject* static PyObject*
cms_profile_getattr_color_space(CmsProfileObject* self, void* closure) cms_profile_getattr_color_space(CmsProfileObject* self, void* closure)
{ {
return PyUnicode_FromString(findICmode(cmsGetColorSpace(self->profile))); return PyUnicode_DecodeFSDefault(findICmode(cmsGetColorSpace(self->profile)));
} }
/* FIXME: add more properties (creation_datetime etc) */ /* FIXME: add more properties (creation_datetime etc) */

View File

@ -520,11 +520,16 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
int streamtype = 0; /* 0=interchange, 1=tables only, 2=image only */ int streamtype = 0; /* 0=interchange, 1=tables only, 2=image only */
int xdpi = 0, ydpi = 0; int xdpi = 0, ydpi = 0;
int subsampling = -1; /* -1=default, 0=none, 1=medium, 2=high */ int subsampling = -1; /* -1=default, 0=none, 1=medium, 2=high */
char* extra = NULL; int extra_size; char* extra = NULL;
int extra_size;
char* rawExif = NULL;
int rawExifLen = 0;
if (!PyArg_ParseTuple(args, "ss|iiiiiiii"PY_ARG_BYTES_LENGTH, if (!PyArg_ParseTuple(args, "ss|iiiiiiii"PY_ARG_BYTES_LENGTH,
&mode, &rawmode, &quality, &mode, &rawmode, &quality,
&progressive, &smooth, &optimize, &streamtype, &progressive, &smooth, &optimize, &streamtype,
&xdpi, &ydpi, &subsampling, &extra, &extra_size)) &xdpi, &ydpi, &subsampling, &extra, &extra_size,
&rawExif, &rawExifLen))
return NULL; return NULL;
encoder = PyImaging_EncoderNew(sizeof(JPEGENCODERSTATE)); encoder = PyImaging_EncoderNew(sizeof(JPEGENCODERSTATE));
@ -543,6 +548,15 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
} else } else
extra = NULL; extra = NULL;
if (rawExif && rawExifLen > 0) {
char* pp = malloc(rawExifLen);
if (!pp)
return PyErr_NoMemory();
memcpy(pp, rawExif, rawExifLen);
rawExif = pp;
} else
rawExif = NULL;
encoder->encode = ImagingJpegEncode; encoder->encode = ImagingJpegEncode;
((JPEGENCODERSTATE*)encoder->state.context)->quality = quality; ((JPEGENCODERSTATE*)encoder->state.context)->quality = quality;
@ -555,6 +569,8 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
((JPEGENCODERSTATE*)encoder->state.context)->ydpi = ydpi; ((JPEGENCODERSTATE*)encoder->state.context)->ydpi = ydpi;
((JPEGENCODERSTATE*)encoder->state.context)->extra = extra; ((JPEGENCODERSTATE*)encoder->state.context)->extra = extra;
((JPEGENCODERSTATE*)encoder->state.context)->extra_size = extra_size; ((JPEGENCODERSTATE*)encoder->state.context)->extra_size = extra_size;
((JPEGENCODERSTATE*)encoder->state.context)->rawExif = rawExif;
((JPEGENCODERSTATE*)encoder->state.context)->rawExifLen = rawExifLen;
return (PyObject*) encoder; return (PyObject*) encoder;
} }

View File

@ -101,4 +101,7 @@ typedef struct {
int extra_offset; int extra_offset;
int rawExifLen; /* EXIF data length */
char* rawExif; /* EXIF buffer pointer */
} JPEGENCODERSTATE; } JPEGENCODERSTATE;

View File

@ -205,11 +205,19 @@ 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, context->rawExif, context->rawExifLen);
break; break;
default: default:
/* interchange stream */ /* interchange stream */
jpeg_start_compress(&context->cinfo, TRUE); jpeg_start_compress(&context->cinfo, TRUE);
break; //add exif header
if (context->rawExifLen > 0)
jpeg_write_marker(&context->cinfo, JPEG_APP0+1, context->rawExif, context->rawExifLen);
break;
} }
state->state++; state->state++;
/* fall through */ /* fall through */

6
py3.h
View File

@ -11,7 +11,7 @@
*/ */
#if PY_VERSION_HEX >= 0x03000000 #if PY_VERSION_HEX >= 0x03000000
#define PY_ARG_BYTES_LENGTH "y#" #define PY_ARG_BYTES_LENGTH "y#y#"
/* Map PyInt -> PyLong */ /* Map PyInt -> PyLong */
#define PyInt_AsLong PyLong_AsLong #define PyInt_AsLong PyLong_AsLong
@ -20,7 +20,7 @@
#define PyInt_AS_LONG PyLong_AS_LONG #define PyInt_AS_LONG PyLong_AS_LONG
#else /* PY_VERSION_HEX < 0x03000000 */ #else /* PY_VERSION_HEX < 0x03000000 */
#define PY_ARG_BYTES_LENGTH "s#" #define PY_ARG_BYTES_LENGTH "s#s#"
#if !defined(KEEP_PY_UNICODE) #if !defined(KEEP_PY_UNICODE)
/* Map PyUnicode -> PyString */ /* Map PyUnicode -> PyString */
@ -30,6 +30,7 @@
#undef PyUnicode_FromStringAndSize #undef PyUnicode_FromStringAndSize
#undef PyUnicode_FromString #undef PyUnicode_FromString
#undef PyUnicode_FromFormat #undef PyUnicode_FromFormat
#undef PyUnicode_DecodeFSDefault
#define PyUnicode_AsString PyString_AsString #define PyUnicode_AsString PyString_AsString
#define PyUnicode_AS_STRING PyString_AS_STRING #define PyUnicode_AS_STRING PyString_AS_STRING
@ -37,6 +38,7 @@
#define PyUnicode_FromStringAndSize PyString_FromStringAndSize #define PyUnicode_FromStringAndSize PyString_FromStringAndSize
#define PyUnicode_FromString PyString_FromString #define PyUnicode_FromString PyString_FromString
#define PyUnicode_FromFormat PyString_FromFormat #define PyUnicode_FromFormat PyString_FromFormat
#define PyUnicode_DecodeFSDefault PyString_FromString
#endif #endif
/* Map PyBytes -> PyString */ /* Map PyBytes -> PyString */