Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

squarecapadmin / Pillow   python

Repository URL to install this package:

/ src / encode.c

/*
 * The Python Imaging Library.
 *
 * 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"

#include "Imaging.h"
#include "py3.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);
    int (*cleanup)(ImagingCodecState state);
    struct ImagingCodecStateInstance state;
    Imaging im;
    PyObject* lock;
    int pushes_fd;
} ImagingEncoderObject;

static PyTypeObject ImagingEncoderType;

static ImagingEncoderObject*
PyImaging_EncoderNew(int contextsize)
{
    ImagingEncoderObject *encoder;
    void *context;

    if(PyType_Ready(&ImagingEncoderType) < 0)
        return NULL;

    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);
            (void) PyErr_NoMemory();
            return NULL;
        }
    } else
        context = 0;

    /* Initialize encoder context */
    encoder->state.context = context;

    /* Most encoders don't need this */
    encoder->cleanup = NULL;

    /* Target image */
    encoder->lock = NULL;
    encoder->im = NULL;
    encoder->pushes_fd = 0;

    return encoder;
}

static void
_dealloc(ImagingEncoderObject* encoder)
{
    if (encoder->cleanup)
        encoder->cleanup(&encoder->state);
    free(encoder->state.buffer);
    free(encoder->state.context);
    Py_XDECREF(encoder->lock);
    Py_XDECREF(encoder->state.fd);
    PyObject_Del(encoder);
}

static PyObject*
_encode_cleanup(ImagingEncoderObject* encoder, PyObject* args)
{
    int status = 0;

    if (encoder->cleanup){
        status = encoder->cleanup(&encoder->state);
    }

    return Py_BuildValue("i", status);
}

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 = PyBytes_FromStringAndSize(NULL, bufsize);
    if (!buf)
        return NULL;

    status = encoder->encode(encoder->im, &encoder->state,
                             (UINT8*) PyBytes_AsString(buf), bufsize);

    /* adjust string length to avoid slicing in encoder */
    if (_PyBytes_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_pyfd(ImagingEncoderObject* encoder, PyObject* args)
{

    PyObject *result;
    int status;

    if (!encoder->pushes_fd) {
        // UNDONE, appropriate errcode???
        result = Py_BuildValue("ii", 0, IMAGING_CODEC_CONFIG);;
        return result;
    }

    status = encoder->encode(encoder->im, &encoder->state,
                             (UINT8*) NULL, 0);

    result = Py_BuildValue("ii", status, encoder->state.errcode);

    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 */
    /* malloc check ok, either constant int, or checked by PyArg_ParseTuple */
    buf = (UINT8*) malloc(bufsize);
    if (!buf)
        return PyErr_NoMemory();

    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) {
        if (state->xsize > ((INT_MAX / state->bits)-7)) {
            return PyErr_NoMemory();
        }
        state->bytes = (state->bits * state->xsize+7)/8;
        /* malloc check ok, overflow checked above */
        state->buffer = (UINT8*) malloc(state->bytes);
        if (!state->buffer)
            return PyErr_NoMemory();
    }

    /* 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 PyObject*
_setfd(ImagingEncoderObject* encoder, PyObject* args)
{
    PyObject* fd;
    ImagingCodecState state;

    if (!PyArg_ParseTuple(args, "O", &fd))
        return NULL;

    state = &encoder->state;

    Py_XINCREF(fd);
    state->fd = fd;

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
_get_pushes_fd(ImagingEncoderObject *encoder)
{
    return PyBool_FromLong(encoder->pushes_fd);
}

static struct PyMethodDef methods[] = {
    {"encode", (PyCFunction)_encode, 1},
    {"cleanup", (PyCFunction)_encode_cleanup, 1},
    {"encode_to_file", (PyCFunction)_encode_to_file, 1},
    {"encode_to_pyfd", (PyCFunction)_encode_to_pyfd, 1},
    {"setimage", (PyCFunction)_setimage, 1},
    {"setfd", (PyCFunction)_setfd, 1},
    {NULL, NULL} /* sentinel */
};

static struct PyGetSetDef getseters[] = {
   {"pushes_fd", (getter)_get_pushes_fd, NULL,
     "True if this decoder expects to push directly to self.fd",
     NULL},
    {NULL, NULL, NULL, NULL, NULL} /* sentinel */
};

static PyTypeObject ImagingEncoderType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "ImagingEncoder",               /*tp_name*/
    sizeof(ImagingEncoderObject),   /*tp_size*/
    0,                              /*tp_itemsize*/
    /* methods */
    (destructor)_dealloc,           /*tp_dealloc*/
    0,                              /*tp_print*/
    0,                          /*tp_getattr*/
    0,                          /*tp_setattr*/
    0,                          /*tp_compare*/
    0,                          /*tp_repr*/
    0,                          /*tp_as_number */
    0,                          /*tp_as_sequence */
    0,                          /*tp_as_mapping */
    0,                          /*tp_hash*/
    0,                          /*tp_call*/
    0,                          /*tp_str*/
    0,                          /*tp_getattro*/
    0,                          /*tp_setattro*/
    0,                          /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT,         /*tp_flags*/
    0,                          /*tp_doc*/
    0,                          /*tp_traverse*/
Loading ...