From addf0f4d95c2b35af12bade794b5d3e43c18b637 Mon Sep 17 00:00:00 2001 From: d-schmidt Date: Thu, 10 Jan 2013 21:36:21 +0100 Subject: [PATCH] Added possibility to save exif information in jpeg-files --- PIL/JpegImagePlugin.py | 1 + encode.c | 26 +++++++++++++++++++++----- libImaging/Jpeg.h | 3 +++ libImaging/JpegEncode.c | 18 +++++++++++++----- py3.h | 4 ++-- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/PIL/JpegImagePlugin.py b/PIL/JpegImagePlugin.py index aa6745ee8..3416711a4 100644 --- a/PIL/JpegImagePlugin.py +++ b/PIL/JpegImagePlugin.py @@ -465,6 +465,7 @@ def _save(im, fp, filename): dpi[0], dpi[1], subsampling, extra, + info.get("exif", "") ) ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)]) diff --git a/encode.c b/encode.c index 479da7d51..4f5902e5b 100644 --- a/encode.c +++ b/encode.c @@ -15,7 +15,7 @@ * 1999-02-07 fl Added PCX encoder * * Copyright (c) 1997-2001 by Secret Labs AB - * Copyright (c) 1996-1997 by Fredrik Lundh + * Copyright (c) 1996-1997 by Fredrik Lundh * * See the README file for information on usage and redistribution. */ @@ -93,7 +93,7 @@ _dealloc(ImagingEncoderObject* encoder) PyObject_Del(encoder); } -static PyObject* +static PyObject* _encode(ImagingEncoderObject* encoder, PyObject* args) { PyObject* buf; @@ -125,7 +125,7 @@ _encode(ImagingEncoderObject* encoder, PyObject* args) return result; } -static PyObject* +static PyObject* _encode_to_file(ImagingEncoderObject* encoder, PyObject* args) { UINT8* buf; @@ -520,11 +520,16 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) int streamtype = 0; /* 0=interchange, 1=tables only, 2=image only */ int xdpi = 0, ydpi = 0; 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, &mode, &rawmode, &quality, &progressive, &smooth, &optimize, &streamtype, - &xdpi, &ydpi, &subsampling, &extra, &extra_size)) + &xdpi, &ydpi, &subsampling, &extra, &extra_size, + &rawExif, &rawExifLen)) return NULL; encoder = PyImaging_EncoderNew(sizeof(JPEGENCODERSTATE)); @@ -543,6 +548,15 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) } else 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; ((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)->extra = extra; ((JPEGENCODERSTATE*)encoder->state.context)->extra_size = extra_size; + ((JPEGENCODERSTATE*)encoder->state.context)->rawExif = rawExif; + ((JPEGENCODERSTATE*)encoder->state.context)->rawExifLen = rawExifLen; return (PyObject*) encoder; } diff --git a/libImaging/Jpeg.h b/libImaging/Jpeg.h index d39165f3c..749d42a22 100644 --- a/libImaging/Jpeg.h +++ b/libImaging/Jpeg.h @@ -100,5 +100,8 @@ typedef struct { JPEGDESTINATION destination; int extra_offset; + + int rawExifLen; /* EXIF data length */ + char* rawExif; /* EXIF buffer pointer */ } JPEGENCODERSTATE; diff --git a/libImaging/JpegEncode.c b/libImaging/JpegEncode.c index 1e2191a69..50ddf61da 100644 --- a/libImaging/JpegEncode.c +++ b/libImaging/JpegEncode.c @@ -24,9 +24,9 @@ #ifdef HAVE_LIBJPEG -#undef HAVE_PROTOTYPES -#undef HAVE_STDLIB_H -#undef HAVE_STDDEF_H +#undef HAVE_PROTOTYPES +#undef HAVE_STDLIB_H +#undef HAVE_STDDEF_H #undef UINT8 #undef UINT16 #undef UINT32 @@ -145,7 +145,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) jpeg_set_defaults(&context->cinfo); if (context->quality > 0) jpeg_set_quality(&context->cinfo, context->quality, 1); - + /* Set subsampling options */ switch (context->subsampling) { @@ -205,11 +205,19 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) jpeg_start_compress(&context->cinfo, FALSE); /* suppress extra section */ 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; default: /* interchange stream */ 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++; /* fall through */ diff --git a/py3.h b/py3.h index 85979c81c..bee457e06 100644 --- a/py3.h +++ b/py3.h @@ -11,7 +11,7 @@ */ #if PY_VERSION_HEX >= 0x03000000 -#define PY_ARG_BYTES_LENGTH "y#" +#define PY_ARG_BYTES_LENGTH "y#y#" /* Map PyInt -> PyLong */ #define PyInt_AsLong PyLong_AsLong @@ -20,7 +20,7 @@ #define PyInt_AS_LONG PyLong_AS_LONG #else /* PY_VERSION_HEX < 0x03000000 */ -#define PY_ARG_BYTES_LENGTH "s#" +#define PY_ARG_BYTES_LENGTH "s#s#" #if !defined(KEEP_PY_UNICODE) /* Map PyUnicode -> PyString */