mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-31 07:57:27 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			822 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			822 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			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);
 | |
|     struct ImagingCodecStateInstance state;
 | |
|     Imaging im;
 | |
|     PyObject* lock;
 | |
| } 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;
 | |
| 
 | |
|     /* 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 = 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_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)
 | |
| 	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) {
 | |
| 	state->bytes = (state->bits * state->xsize+7)/8;
 | |
| 	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 struct PyMethodDef methods[] = {
 | |
|     {"encode", (PyCFunction)_encode, 1},
 | |
|     {"encode_to_file", (PyCFunction)_encode_to_file, 1},
 | |
|     {"setimage", (PyCFunction)_setimage, 1},
 | |
|     {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*/
 | |
|     0,                          /*tp_clear*/
 | |
|     0,                          /*tp_richcompare*/
 | |
|     0,                          /*tp_weaklistoffset*/
 | |
|     0,                          /*tp_iter*/
 | |
|     0,                          /*tp_iternext*/
 | |
|     methods,                    /*tp_methods*/
 | |
|     0,                          /*tp_members*/
 | |
|     0,                          /*tp_getset*/
 | |
| };
 | |
| 
 | |
| /* -------------------------------------------------------------------- */
 | |
| 
 | |
| 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;
 | |
|     int compress_level = -1;
 | |
|     int compress_type = -1;
 | |
|     char* dictionary = NULL;
 | |
|     int dictionary_size = 0;
 | |
|     if (!PyArg_ParseTuple(args, "ss|iii"PY_ARG_BYTES_LENGTH, &mode, &rawmode,
 | |
|                           &optimize,
 | |
|                           &compress_level, &compress_type,
 | |
|                           &dictionary, &dictionary_size))
 | |
|         return NULL;
 | |
| 
 | |
|     /* Copy to avoid referencing Python's memory, but there's no mechanism to
 | |
|        free this memory later, so this function (and several others here)
 | |
|        leaks. */
 | |
|     if (dictionary && dictionary_size > 0) {
 | |
|         char* p = malloc(dictionary_size);
 | |
|         if (!p)
 | |
|             return PyErr_NoMemory();
 | |
|         memcpy(p, dictionary, dictionary_size);
 | |
|         dictionary = p;
 | |
|     } else
 | |
|         dictionary = 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)->compress_level = compress_level;
 | |
|     ((ZIPSTATE*)encoder->state.context)->compress_type = compress_type;
 | |
|     ((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"
 | |
| 
 | |
| static unsigned int** get_qtables_arrays(PyObject* qtables) {
 | |
|     PyObject* tables;
 | |
|     PyObject* table;
 | |
|     PyObject* table_data;
 | |
|     int i, j, num_tables;
 | |
|     unsigned int **qarrays;
 | |
| 
 | |
|     if ((qtables ==  NULL) || (qtables == Py_None)) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PySequence_Check(qtables)) {
 | |
|         PyErr_SetString(PyExc_ValueError, "Invalid quantization tables");
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     tables = PySequence_Fast(qtables, "expected a sequence");
 | |
|     num_tables = PySequence_Size(qtables);
 | |
|     if (num_tables < 2 || num_tables > NUM_QUANT_TBLS) {
 | |
|         PyErr_SetString(PyExc_ValueError, "Not a valid numbers of quantization tables. Should be between 2 and 4.");
 | |
|         return NULL;
 | |
|     }
 | |
|     qarrays = (unsigned int**) PyMem_Malloc(num_tables * sizeof(unsigned int*));
 | |
|     if (!qarrays) {
 | |
|         Py_DECREF(tables);
 | |
|         PyErr_NoMemory();
 | |
|         return NULL;
 | |
|     }
 | |
|     for (i = 0; i < num_tables; i++) {
 | |
|         table = PySequence_Fast_GET_ITEM(tables, i);
 | |
|         if (!PySequence_Check(table)) {
 | |
|             Py_DECREF(tables);
 | |
|             PyErr_SetString(PyExc_ValueError, "Invalid quantization tables");
 | |
|             return NULL;
 | |
|         }
 | |
|         if (PySequence_Size(table) != DCTSIZE2) {
 | |
|             Py_DECREF(tables);
 | |
|             PyErr_SetString(PyExc_ValueError, "Invalid quantization tables");
 | |
|             return NULL;
 | |
|         }
 | |
|         table_data = PySequence_Fast(table, "expected a sequence");
 | |
|         qarrays[i] = (unsigned int*) PyMem_Malloc(DCTSIZE2 * sizeof(unsigned int));
 | |
|         if (!qarrays[i]) {
 | |
|             Py_DECREF(tables);
 | |
|             PyErr_NoMemory();
 | |
|             return NULL;
 | |
|         }
 | |
|         for (j = 0; j < DCTSIZE2; j++) {
 | |
|             qarrays[i][j] = PyInt_AS_LONG(PySequence_Fast_GET_ITEM(table_data, j));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     Py_DECREF(tables);
 | |
| 
 | |
|     if (PyErr_Occurred()) {
 | |
|         PyMem_Free(qarrays);
 | |
|         qarrays = NULL;
 | |
|     }
 | |
| 
 | |
|     return qarrays;
 | |
| }
 | |
| 
 | |
| 
 | |
| 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;
 | |
|     int subsampling = -1; /* -1=default, 0=none, 1=medium, 2=high */
 | |
|     PyObject* qtables=NULL;
 | |
|     unsigned int **qarrays = NULL;
 | |
|     char* extra = NULL;
 | |
|     int extra_size;
 | |
|     char* rawExif = NULL;
 | |
|     int rawExifLen = 0;
 | |
| 
 | |
|     if (!PyArg_ParseTuple(args, "ss|iiiiiiiiO"PY_ARG_BYTES_LENGTH""PY_ARG_BYTES_LENGTH,
 | |
|                           &mode, &rawmode, &quality,
 | |
|                           &progressive, &smooth, &optimize, &streamtype,
 | |
|                           &xdpi, &ydpi, &subsampling, &qtables, &extra, &extra_size,
 | |
|                           &rawExif, &rawExifLen))
 | |
| 	return NULL;
 | |
| 
 | |
|     encoder = PyImaging_EncoderNew(sizeof(JPEGENCODERSTATE));
 | |
|     if (encoder == NULL)
 | |
| 	return NULL;
 | |
| 
 | |
|     if (get_packer(encoder, mode, rawmode) < 0)
 | |
| 	return NULL;
 | |
| 
 | |
|     qarrays = get_qtables_arrays(qtables);
 | |
| 
 | |
|     if (extra && extra_size > 0) {
 | |
|         char* p = malloc(extra_size);
 | |
|         if (!p)
 | |
|             return PyErr_NoMemory();
 | |
|         memcpy(p, extra, extra_size);
 | |
|         extra = p;
 | |
|     } 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;
 | |
|     ((JPEGENCODERSTATE*)encoder->state.context)->qtables = qarrays;
 | |
|     ((JPEGENCODERSTATE*)encoder->state.context)->subsampling = subsampling;
 | |
|     ((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;
 | |
|     ((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;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| /* -------------------------------------------------------------------- */
 | |
| /* LibTiff                                                              */
 | |
| /* -------------------------------------------------------------------- */
 | |
| 
 | |
| #ifdef HAVE_LIBTIFF
 | |
| 
 | |
| #include "TiffDecode.h"
 | |
| 
 | |
| #include <string.h>
 | |
| #ifdef __WIN32__
 | |
| #define strcasecmp(s1, s2) stricmp(s1, s2)
 | |
| #endif
 | |
| 
 | |
| PyObject*
 | |
| PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
 | |
| {
 | |
|     ImagingEncoderObject* encoder;
 | |
| 
 | |
|     char* mode;
 | |
|     char* rawmode;
 | |
|     char* compname;
 | |
|     char* filename;
 | |
|     int compression;
 | |
|     int fp;
 | |
| 
 | |
|     PyObject *dir;
 | |
|     PyObject *key, *value;
 | |
|     Py_ssize_t pos = 0;
 | |
|     int status;
 | |
| 
 | |
|     Py_ssize_t d_size;
 | |
|     PyObject *keys, *values;
 | |
| 
 | |
| 
 | |
|     if (! PyArg_ParseTuple(args, "sssisO", &mode, &rawmode, &compname, &fp, &filename, &dir)) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyDict_Check(dir)) {
 | |
|         PyErr_SetString(PyExc_ValueError, "Invalid Dictionary");
 | |
|         return NULL;
 | |
|     } else {
 | |
|         d_size = PyDict_Size(dir);
 | |
|         TRACE(("dict size: %d\n", (int)d_size));
 | |
|         keys = PyDict_Keys(dir);
 | |
|         values = PyDict_Values(dir);
 | |
|         for (pos=0;pos<d_size;pos++){
 | |
|             TRACE(("  key: %d\n", (int)PyInt_AsLong(PyList_GetItem(keys,pos))));
 | |
|         }
 | |
|         pos = 0;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     TRACE(("new tiff encoder %s fp: %d, filename: %s \n", compname, fp, filename));
 | |
| 
 | |
|     /* UNDONE -- we can probably do almost any arbitrary compression here,
 | |
|      *  so long as we're doing row/stripe based actions and not tiles.
 | |
|      */
 | |
| 
 | |
|     if (strcasecmp(compname, "tiff_ccitt") == 0) {
 | |
|         compression = COMPRESSION_CCITTRLE;
 | |
| 
 | |
|     } else if (strcasecmp(compname, "group3") == 0) {
 | |
|         compression = COMPRESSION_CCITTFAX3;
 | |
| 
 | |
|     } else if (strcasecmp(compname, "group4") == 0) {
 | |
|         compression = COMPRESSION_CCITTFAX4;
 | |
| 
 | |
|     } else if (strcasecmp(compname, "tiff_jpeg") == 0) {
 | |
|         compression = COMPRESSION_OJPEG;
 | |
| 
 | |
|     } else if (strcasecmp(compname, "tiff_adobe_deflate") == 0) {
 | |
|         compression = COMPRESSION_ADOBE_DEFLATE;
 | |
| 
 | |
|     } else if (strcasecmp(compname, "tiff_thunderscan") == 0) {
 | |
|         compression = COMPRESSION_THUNDERSCAN;
 | |
| 
 | |
|     } else if (strcasecmp(compname, "tiff_deflate") == 0) {
 | |
|         compression = COMPRESSION_DEFLATE;
 | |
| 
 | |
|     } else if (strcasecmp(compname, "tiff_sgilog") == 0) {
 | |
|         compression = COMPRESSION_SGILOG;
 | |
| 
 | |
|     } else if (strcasecmp(compname, "tiff_sgilog24") == 0) {
 | |
|         compression = COMPRESSION_SGILOG24;
 | |
| 
 | |
|     } else if (strcasecmp(compname, "tiff_raw_16") == 0) {
 | |
|         compression = COMPRESSION_CCITTRLEW;
 | |
| 
 | |
|     } else {
 | |
|         PyErr_SetString(PyExc_ValueError, "unknown compession");
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     TRACE(("Found compression: %d\n", compression));
 | |
| 
 | |
|     encoder = PyImaging_EncoderNew(sizeof(TIFFSTATE));
 | |
|     if (encoder == NULL)
 | |
|         return NULL;
 | |
| 
 | |
|     if (get_packer(encoder, mode, rawmode) < 0)
 | |
|         return NULL;
 | |
| 
 | |
|     if (! ImagingLibTiffEncodeInit(&encoder->state, filename, fp)) {
 | |
|         Py_DECREF(encoder);
 | |
|         PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed");
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
| 	// While failes on 64 bit machines, complains that pos is an int instead of a Py_ssize_t
 | |
| 	//    while (PyDict_Next(dir, &pos, &key, &value)) {
 | |
| 	for (pos=0;pos<d_size;pos++){
 | |
| 		key = PyList_GetItem(keys,pos);
 | |
| 		value = PyList_GetItem(values,pos);
 | |
|         status = 0;
 | |
|         TRACE(("Attempting to set key: %d\n", (int)PyInt_AsLong(key)));
 | |
|         if (PyInt_Check(value)) {
 | |
|             TRACE(("Setting from Int: %d %ld \n", (int)PyInt_AsLong(key),PyInt_AsLong(value)));
 | |
|             status = ImagingLibTiffSetField(&encoder->state,
 | |
|                                             (ttag_t) PyInt_AsLong(key),
 | |
|                                             PyInt_AsLong(value));
 | |
|         } else if(PyBytes_Check(value)) {
 | |
|             TRACE(("Setting from String: %d, %s \n", (int)PyInt_AsLong(key),PyBytes_AsString(value)));
 | |
|             status = ImagingLibTiffSetField(&encoder->state,
 | |
|                                             (ttag_t) PyInt_AsLong(key),
 | |
|                                             PyBytes_AsString(value));
 | |
| 
 | |
|         } else if(PyList_Check(value)) {
 | |
|             int len,i;
 | |
|             float *floatav;
 | |
|             TRACE(("Setting from List: %d \n", (int)PyInt_AsLong(key)));
 | |
|             len = (int)PyList_Size(value);
 | |
|             TRACE((" %d elements, setting as floats \n", len));
 | |
|             floatav = malloc(sizeof(float)*len);
 | |
|             if (floatav) {
 | |
|                 for (i=0;i<len;i++) {
 | |
|                     floatav[i] = (float)PyFloat_AsDouble(PyList_GetItem(value,i));
 | |
|                 }
 | |
|                 status = ImagingLibTiffSetField(&encoder->state,
 | |
|                                                 (ttag_t) PyInt_AsLong(key),
 | |
|                                                 floatav);
 | |
|                 free(floatav);
 | |
|             }
 | |
|         } else if (PyFloat_Check(value)) {
 | |
|             TRACE(("Setting from String: %d, %f \n", (int)PyInt_AsLong(key),PyFloat_AsDouble(value)));
 | |
|             status = ImagingLibTiffSetField(&encoder->state,
 | |
|                                             (ttag_t) PyInt_AsLong(key),
 | |
|                                             (float)PyFloat_AsDouble(value));
 | |
|         } else {
 | |
|             TRACE(("Unhandled type for key %d : %s ",
 | |
|                    (int)PyInt_AsLong(key),
 | |
|                    PyBytes_AsString(PyObject_Str(value))));
 | |
|         }
 | |
|         if (!status) {
 | |
|             TRACE(("Error setting Field\n"));
 | |
|             Py_DECREF(encoder);
 | |
|             PyErr_SetString(PyExc_RuntimeError, "Error setting from dictionary");
 | |
|             return NULL;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     encoder->encode  = ImagingLibTiffEncode;
 | |
| 
 | |
|     return (PyObject*) encoder;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 |