Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Imaging/encode.c
diff options
context:
space:
mode:
Diffstat (limited to 'Imaging/encode.c')
-rw-r--r--Imaging/encode.c531
1 files changed, 531 insertions, 0 deletions
diff --git a/Imaging/encode.c b/Imaging/encode.c
new file mode 100644
index 0000000..0a57e74
--- /dev/null
+++ b/Imaging/encode.c
@@ -0,0 +1,531 @@
+/*
+ * The Python Imaging Library.
+ * $Id: encode.c 2751 2006-06-18 19:50:45Z fredrik $
+ *
+ * standard encoder interfaces for the Imaging library
+ *
+ * History:
+ * 1996-04-19 fl Based on decoders.c
+ * 1996-05-12 fl Compile cleanly as C++
+ * 1996-12-30 fl Plugged potential memory leak for tiled images
+ * 1997-01-03 fl Added GIF encoder
+ * 1997-01-05 fl Plugged encoder buffer leaks
+ * 1997-01-11 fl Added encode_to_file method
+ * 1998-03-09 fl Added mode/rawmode argument to encoders
+ * 1998-07-09 fl Added interlace argument to GIF encoder
+ * 1999-02-07 fl Added PCX encoder
+ *
+ * Copyright (c) 1997-2001 by Secret Labs AB
+ * Copyright (c) 1996-1997 by Fredrik Lundh
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+/* FIXME: make these pluggable! */
+
+#include "Python.h"
+
+#if PY_VERSION_HEX < 0x01060000
+#define PyObject_New PyObject_NEW
+#define PyObject_Del PyMem_DEL
+#endif
+
+#include "Imaging.h"
+#include "Gif.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* write */
+#endif
+
+/* -------------------------------------------------------------------- */
+/* Common */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ PyObject_HEAD
+ int (*encode)(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+ struct ImagingCodecStateInstance state;
+ Imaging im;
+ PyObject* lock;
+} ImagingEncoderObject;
+
+staticforward PyTypeObject ImagingEncoderType;
+
+static ImagingEncoderObject*
+PyImaging_EncoderNew(int contextsize)
+{
+ ImagingEncoderObject *encoder;
+ void *context;
+
+ ImagingEncoderType.ob_type = &PyType_Type;
+
+ encoder = PyObject_New(ImagingEncoderObject, &ImagingEncoderType);
+ if (encoder == NULL)
+ return NULL;
+
+ /* Clear the encoder state */
+ memset(&encoder->state, 0, sizeof(encoder->state));
+
+ /* Allocate encoder context */
+ if (contextsize > 0) {
+ context = (void*) calloc(1, contextsize);
+ if (!context) {
+ Py_DECREF(encoder);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ } else
+ context = 0;
+
+ /* Initialize encoder context */
+ encoder->state.context = context;
+
+ /* Target image */
+ encoder->lock = NULL;
+ encoder->im = NULL;
+
+ return encoder;
+}
+
+static void
+_dealloc(ImagingEncoderObject* encoder)
+{
+ free(encoder->state.buffer);
+ free(encoder->state.context);
+ Py_XDECREF(encoder->lock);
+ PyObject_Del(encoder);
+}
+
+static PyObject*
+_encode(ImagingEncoderObject* encoder, PyObject* args)
+{
+ PyObject* buf;
+ PyObject* result;
+ int status;
+
+ /* Encode to a Python string (allocated by this method) */
+
+ int bufsize = 16384;
+
+ if (!PyArg_ParseTuple(args, "|i", &bufsize))
+ return NULL;
+
+ buf = PyString_FromStringAndSize(NULL, bufsize);
+ if (!buf)
+ return NULL;
+
+ status = encoder->encode(encoder->im, &encoder->state,
+ (UINT8*) PyString_AsString(buf), bufsize);
+
+ /* adjust string length to avoid slicing in encoder */
+ if (_PyString_Resize(&buf, (status > 0) ? status : 0) < 0)
+ return NULL;
+
+ result = Py_BuildValue("iiO", status, encoder->state.errcode, buf);
+
+ Py_DECREF(buf); /* must release buffer!!! */
+
+ return result;
+}
+
+static PyObject*
+_encode_to_file(ImagingEncoderObject* encoder, PyObject* args)
+{
+ UINT8* buf;
+ int status;
+ ImagingSectionCookie cookie;
+
+ /* Encode to a file handle */
+
+ int fh;
+ int bufsize = 16384;
+
+ if (!PyArg_ParseTuple(args, "i|i", &fh, &bufsize))
+ return NULL;
+
+ /* Allocate an encoder buffer */
+ buf = (UINT8*) malloc(bufsize);
+ if (!buf) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ do {
+
+ /* This replaces the inner loop in the ImageFile _save
+ function. */
+
+ status = encoder->encode(encoder->im, &encoder->state, buf, bufsize);
+
+ if (status > 0)
+ if (write(fh, buf, status) < 0) {
+ ImagingSectionLeave(&cookie);
+ free(buf);
+ return PyErr_SetFromErrno(PyExc_IOError);
+ }
+
+ } while (encoder->state.errcode == 0);
+
+ ImagingSectionLeave(&cookie);
+
+ free(buf);
+
+ return Py_BuildValue("i", encoder->state.errcode);
+}
+
+extern Imaging PyImaging_AsImaging(PyObject *op);
+
+static PyObject*
+_setimage(ImagingEncoderObject* encoder, PyObject* args)
+{
+ PyObject* op;
+ Imaging im;
+ ImagingCodecState state;
+ int x0, y0, x1, y1;
+
+ /* Define where image data should be stored */
+
+ x0 = y0 = x1 = y1 = 0;
+
+ /* FIXME: should publish the ImagingType descriptor */
+ if (!PyArg_ParseTuple(args, "O|(iiii)", &op, &x0, &y0, &x1, &y1))
+ return NULL;
+ im = PyImaging_AsImaging(op);
+ if (!im)
+ return NULL;
+
+ encoder->im = im;
+
+ state = &encoder->state;
+
+ if (x0 == 0 && x1 == 0) {
+ state->xsize = im->xsize;
+ state->ysize = im->ysize;
+ } else {
+ state->xoff = x0;
+ state->yoff = y0;
+ state->xsize = x1 - x0;
+ state->ysize = y1 - y0;
+ }
+
+ if (state->xsize <= 0 ||
+ state->xsize + state->xoff > im->xsize ||
+ state->ysize <= 0 ||
+ state->ysize + state->yoff > im->ysize) {
+ PyErr_SetString(PyExc_SystemError, "tile cannot extend outside image");
+ return NULL;
+ }
+
+ /* Allocate memory buffer (if bits field is set) */
+ if (state->bits > 0) {
+ state->bytes = (state->bits * state->xsize+7)/8;
+ state->buffer = (UINT8*) malloc(state->bytes);
+ if (!state->buffer) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ }
+
+ /* Keep a reference to the image object, to make sure it doesn't
+ go away before we do */
+ Py_INCREF(op);
+ Py_XDECREF(encoder->lock);
+ encoder->lock = op;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct PyMethodDef methods[] = {
+ {"encode", (PyCFunction)_encode, 1},
+ {"encode_to_file", (PyCFunction)_encode_to_file, 1},
+ {"setimage", (PyCFunction)_setimage, 1},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject*
+_getattr(ImagingEncoderObject* self, char* name)
+{
+ return Py_FindMethod(methods, (PyObject*) self, name);
+}
+
+statichere PyTypeObject ImagingEncoderType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "ImagingEncoder", /*tp_name*/
+ sizeof(ImagingEncoderObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ (getattrfunc)_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_hash*/
+};
+
+/* -------------------------------------------------------------------- */
+
+int
+get_packer(ImagingEncoderObject* encoder, const char* mode,
+ const char* rawmode)
+{
+ int bits;
+ ImagingShuffler pack;
+
+ pack = ImagingFindPacker(mode, rawmode, &bits);
+ if (!pack) {
+ Py_DECREF(encoder);
+ PyErr_SetString(PyExc_SystemError, "unknown raw mode");
+ return -1;
+ }
+
+ encoder->state.shuffle = pack;
+ encoder->state.bits = bits;
+
+ return 0;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* EPS */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_EpsEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ encoder = PyImaging_EncoderNew(0);
+ if (encoder == NULL)
+ return NULL;
+
+ encoder->encode = ImagingEpsEncode;
+
+ return (PyObject*) encoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* GIF */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_GifEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char *mode;
+ char *rawmode;
+ int bits = 8;
+ int interlace = 0;
+ if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits, &interlace))
+ return NULL;
+
+ encoder = PyImaging_EncoderNew(sizeof(GIFENCODERSTATE));
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, mode, rawmode) < 0)
+ return NULL;
+
+ encoder->encode = ImagingGifEncode;
+
+ ((GIFENCODERSTATE*)encoder->state.context)->bits = bits;
+ ((GIFENCODERSTATE*)encoder->state.context)->interlace = interlace;
+
+ return (PyObject*) encoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* PCX */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_PcxEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char *mode;
+ char *rawmode;
+ int bits = 8;
+ if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits))
+ return NULL;
+
+ encoder = PyImaging_EncoderNew(0);
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, mode, rawmode) < 0)
+ return NULL;
+
+ encoder->encode = ImagingPcxEncode;
+
+ return (PyObject*) encoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* RAW */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_RawEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char *mode;
+ char *rawmode;
+ int stride = 0;
+ int ystep = 1;
+
+ if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &stride, &ystep))
+ return NULL;
+
+ encoder = PyImaging_EncoderNew(0);
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, mode, rawmode) < 0)
+ return NULL;
+
+ encoder->encode = ImagingRawEncode;
+
+ encoder->state.ystep = ystep;
+ encoder->state.count = stride;
+
+ return (PyObject*) encoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* XBM */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_XbmEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ encoder = PyImaging_EncoderNew(0);
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, "1", "1;R") < 0)
+ return NULL;
+
+ encoder->encode = ImagingXbmEncode;
+
+ return (PyObject*) encoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* ZIP */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_LIBZ
+
+#include "Zip.h"
+
+PyObject*
+PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char* mode;
+ char* rawmode;
+ int optimize = 0;
+ char* dictionary = NULL;
+ int dictionary_size = 0;
+ if (!PyArg_ParseTuple(args, "ss|is#", &mode, &rawmode, &optimize,
+ &dictionary, &dictionary_size))
+ return NULL;
+
+ encoder = PyImaging_EncoderNew(sizeof(ZIPSTATE));
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, mode, rawmode) < 0)
+ return NULL;
+
+ encoder->encode = ImagingZipEncode;
+
+ if (rawmode[0] == 'P')
+ /* disable filtering */
+ ((ZIPSTATE*)encoder->state.context)->mode = ZIP_PNG_PALETTE;
+
+ ((ZIPSTATE*)encoder->state.context)->optimize = optimize;
+ ((ZIPSTATE*)encoder->state.context)->dictionary = dictionary;
+ ((ZIPSTATE*)encoder->state.context)->dictionary_size = dictionary_size;
+
+ return (PyObject*) encoder;
+}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/* JPEG */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_LIBJPEG
+
+/* We better define this encoder last in this file, so the following
+ undef's won't mess things up for the Imaging library proper. */
+
+#undef HAVE_PROTOTYPES
+#undef HAVE_STDDEF_H
+#undef HAVE_STDLIB_H
+#undef UINT8
+#undef UINT16
+#undef UINT32
+#undef INT8
+#undef INT16
+#undef INT32
+
+#include "Jpeg.h"
+
+PyObject*
+PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char *mode;
+ char *rawmode;
+ int quality = 0;
+ int progressive = 0;
+ int smooth = 0;
+ int optimize = 0;
+ int streamtype = 0; /* 0=interchange, 1=tables only, 2=image only */
+ int xdpi = 0, ydpi = 0;
+ if (!PyArg_ParseTuple(args, "ss|iiiiiii", &mode, &rawmode, &quality,
+ &progressive, &smooth, &optimize, &streamtype,
+ &xdpi, &ydpi))
+ return NULL;
+
+ encoder = PyImaging_EncoderNew(sizeof(JPEGENCODERSTATE));
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, mode, rawmode) < 0)
+ return NULL;
+
+ encoder->encode = ImagingJpegEncode;
+
+ ((JPEGENCODERSTATE*)encoder->state.context)->quality = quality;
+ ((JPEGENCODERSTATE*)encoder->state.context)->progressive = progressive;
+ ((JPEGENCODERSTATE*)encoder->state.context)->smooth = smooth;
+ ((JPEGENCODERSTATE*)encoder->state.context)->optimize = optimize;
+ ((JPEGENCODERSTATE*)encoder->state.context)->streamtype = streamtype;
+ ((JPEGENCODERSTATE*)encoder->state.context)->xdpi = xdpi;
+ ((JPEGENCODERSTATE*)encoder->state.context)->ydpi = ydpi;
+
+ return (PyObject*) encoder;
+}
+
+#endif