2010-07-31 06:52:47 +04:00
|
|
|
/*
|
|
|
|
* 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
|
2013-01-11 00:36:21 +04:00
|
|
|
* Copyright (c) 1996-1997 by Fredrik Lundh
|
2010-07-31 06:52:47 +04:00
|
|
|
*
|
|
|
|
* See the README file for information on usage and redistribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* FIXME: make these pluggable! */
|
|
|
|
|
2019-03-26 05:50:57 +03:00
|
|
|
#define PY_SSIZE_T_CLEAN
|
2010-07-31 06:52:47 +04:00
|
|
|
#include "Python.h"
|
|
|
|
|
2020-09-16 08:10:28 +03:00
|
|
|
#include "libImaging/Imaging.h"
|
2020-09-22 06:33:05 +03:00
|
|
|
#include "libImaging/Gif.h"
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h> /* write */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2014-03-04 08:43:47 +04:00
|
|
|
/* Common */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD
|
|
|
|
int (*encode)(Imaging im, ImagingCodecState state,
|
2014-03-04 08:43:47 +04:00
|
|
|
UINT8* buffer, int bytes);
|
2014-03-13 22:27:16 +04:00
|
|
|
int (*cleanup)(ImagingCodecState state);
|
2010-07-31 06:52:47 +04:00
|
|
|
struct ImagingCodecStateInstance state;
|
|
|
|
Imaging im;
|
|
|
|
PyObject* lock;
|
2016-05-29 01:07:36 +03:00
|
|
|
int pushes_fd;
|
2010-07-31 06:52:47 +04:00
|
|
|
} ImagingEncoderObject;
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyTypeObject ImagingEncoderType;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
static ImagingEncoderObject*
|
|
|
|
PyImaging_EncoderNew(int contextsize)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject *encoder;
|
|
|
|
void *context;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if(PyType_Ready(&ImagingEncoderType) < 0) {
|
2012-10-13 20:53:07 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder = PyObject_New(ImagingEncoderObject, &ImagingEncoderType);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (encoder == NULL) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Clear the encoder state */
|
|
|
|
memset(&encoder->state, 0, sizeof(encoder->state));
|
|
|
|
|
|
|
|
/* Allocate encoder context */
|
|
|
|
if (contextsize > 0) {
|
2014-03-04 08:43:47 +04:00
|
|
|
context = (void*) calloc(1, contextsize);
|
|
|
|
if (!context) {
|
|
|
|
Py_DECREF(encoder);
|
|
|
|
(void) PyErr_NoMemory();
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2014-03-04 08:43:47 +04:00
|
|
|
context = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Initialize encoder context */
|
|
|
|
encoder->state.context = context;
|
|
|
|
|
2014-03-13 22:27:16 +04:00
|
|
|
/* Most encoders don't need this */
|
|
|
|
encoder->cleanup = NULL;
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
/* Target image */
|
|
|
|
encoder->lock = NULL;
|
|
|
|
encoder->im = NULL;
|
2016-05-29 01:07:36 +03:00
|
|
|
encoder->pushes_fd = 0;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return encoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_dealloc(ImagingEncoderObject* encoder)
|
|
|
|
{
|
2020-05-10 12:56:36 +03:00
|
|
|
if (encoder->cleanup) {
|
2014-03-13 22:27:16 +04:00
|
|
|
encoder->cleanup(&encoder->state);
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
free(encoder->state.buffer);
|
|
|
|
free(encoder->state.context);
|
|
|
|
Py_XDECREF(encoder->lock);
|
2016-05-29 01:07:36 +03:00
|
|
|
Py_XDECREF(encoder->state.fd);
|
2010-07-31 06:52:47 +04:00
|
|
|
PyObject_Del(encoder);
|
|
|
|
}
|
|
|
|
|
2014-08-27 09:30:31 +04:00
|
|
|
static PyObject*
|
|
|
|
_encode_cleanup(ImagingEncoderObject* encoder, PyObject* args)
|
|
|
|
{
|
|
|
|
int status = 0;
|
|
|
|
|
|
|
|
if (encoder->cleanup){
|
|
|
|
status = encoder->cleanup(&encoder->state);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Py_BuildValue("i", status);
|
|
|
|
}
|
|
|
|
|
2013-01-11 00:36:21 +04:00
|
|
|
static PyObject*
|
2010-07-31 06:52:47 +04:00
|
|
|
_encode(ImagingEncoderObject* encoder, PyObject* args)
|
|
|
|
{
|
|
|
|
PyObject* buf;
|
|
|
|
PyObject* result;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
/* Encode to a Python string (allocated by this method) */
|
|
|
|
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t bufsize = 16384;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "|n", &bufsize)) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2012-10-14 08:47:30 +04:00
|
|
|
buf = PyBytes_FromStringAndSize(NULL, bufsize);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!buf) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
status = encoder->encode(encoder->im, &encoder->state,
|
2014-03-04 08:43:47 +04:00
|
|
|
(UINT8*) PyBytes_AsString(buf), bufsize);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* adjust string length to avoid slicing in encoder */
|
2020-05-10 12:56:36 +03:00
|
|
|
if (_PyBytes_Resize(&buf, (status > 0) ? status : 0) < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
result = Py_BuildValue("iiO", status, encoder->state.errcode, buf);
|
|
|
|
|
|
|
|
Py_DECREF(buf); /* must release buffer!!! */
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-05-29 01:07:36 +03:00
|
|
|
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);
|
2016-09-03 05:23:42 +03:00
|
|
|
|
2016-05-29 01:07:36 +03:00
|
|
|
result = Py_BuildValue("ii", status, encoder->state.errcode);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-01-11 00:36:21 +04:00
|
|
|
static PyObject*
|
2010-07-31 06:52:47 +04:00
|
|
|
_encode_to_file(ImagingEncoderObject* encoder, PyObject* args)
|
|
|
|
{
|
|
|
|
UINT8* buf;
|
|
|
|
int status;
|
|
|
|
ImagingSectionCookie cookie;
|
|
|
|
|
|
|
|
/* Encode to a file handle */
|
|
|
|
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t fh;
|
|
|
|
Py_ssize_t bufsize = 16384;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "n|n", &fh, &bufsize)) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Allocate an encoder buffer */
|
2016-03-16 14:47:18 +03:00
|
|
|
/* malloc check ok, either constant int, or checked by PyArg_ParseTuple */
|
2010-07-31 06:52:47 +04:00
|
|
|
buf = (UINT8*) malloc(bufsize);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!buf) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return PyErr_NoMemory();
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
ImagingSectionEnter(&cookie);
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
2014-03-04 08:43:47 +04:00
|
|
|
/* This replaces the inner loop in the ImageFile _save
|
|
|
|
function. */
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2014-03-04 08:43:47 +04:00
|
|
|
status = encoder->encode(encoder->im, &encoder->state, buf, bufsize);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (status > 0) {
|
2014-03-04 08:43:47 +04:00
|
|
|
if (write(fh, buf, status) < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
ImagingSectionLeave(&cookie);
|
2014-03-04 08:43:47 +04:00
|
|
|
free(buf);
|
2020-04-07 09:58:21 +03:00
|
|
|
return PyErr_SetFromErrno(PyExc_OSError);
|
2014-03-04 08:43:47 +04:00
|
|
|
}
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
} 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;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t x0, y0, x1, y1;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Define where image data should be stored */
|
|
|
|
|
|
|
|
x0 = y0 = x1 = y1 = 0;
|
|
|
|
|
|
|
|
/* FIXME: should publish the ImagingType descriptor */
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O|(nnnn)", &op, &x0, &y0, &x1, &y1)) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
im = PyImaging_AsImaging(op);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!im) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder->im = im;
|
|
|
|
|
|
|
|
state = &encoder->state;
|
|
|
|
|
|
|
|
if (x0 == 0 && x1 == 0) {
|
2014-03-04 08:43:47 +04:00
|
|
|
state->xsize = im->xsize;
|
|
|
|
state->ysize = im->ysize;
|
2010-07-31 06:52:47 +04:00
|
|
|
} else {
|
2014-03-04 08:43:47 +04:00
|
|
|
state->xoff = x0;
|
|
|
|
state->yoff = y0;
|
|
|
|
state->xsize = x1 - x0;
|
|
|
|
state->ysize = y1 - y0;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (state->xsize <= 0 ||
|
2014-03-04 08:43:47 +04:00
|
|
|
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;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate memory buffer (if bits field is set) */
|
|
|
|
if (state->bits > 0) {
|
2016-05-21 17:31:19 +03:00
|
|
|
if (state->xsize > ((INT_MAX / state->bits)-7)) {
|
2016-03-16 14:47:18 +03:00
|
|
|
return PyErr_NoMemory();
|
|
|
|
}
|
2014-03-04 08:43:47 +04:00
|
|
|
state->bytes = (state->bits * state->xsize+7)/8;
|
2016-03-16 14:47:18 +03:00
|
|
|
/* malloc check ok, overflow checked above */
|
2014-03-04 08:43:47 +04:00
|
|
|
state->buffer = (UINT8*) malloc(state->bytes);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!state->buffer) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return PyErr_NoMemory();
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2016-05-29 01:07:36 +03:00
|
|
|
static PyObject*
|
|
|
|
_setfd(ImagingEncoderObject* encoder, PyObject* args)
|
|
|
|
{
|
|
|
|
PyObject* fd;
|
|
|
|
ImagingCodecState state;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O", &fd)) {
|
2016-05-29 01:07:36 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2016-05-29 01:07:36 +03:00
|
|
|
|
|
|
|
state = &encoder->state;
|
|
|
|
|
|
|
|
Py_XINCREF(fd);
|
|
|
|
state->fd = fd;
|
2016-09-03 05:23:42 +03:00
|
|
|
|
2016-05-29 01:07:36 +03:00
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_get_pushes_fd(ImagingEncoderObject *encoder)
|
|
|
|
{
|
|
|
|
return PyBool_FromLong(encoder->pushes_fd);
|
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
static struct PyMethodDef methods[] = {
|
|
|
|
{"encode", (PyCFunction)_encode, 1},
|
2014-08-27 09:30:31 +04:00
|
|
|
{"cleanup", (PyCFunction)_encode_cleanup, 1},
|
2010-07-31 06:52:47 +04:00
|
|
|
{"encode_to_file", (PyCFunction)_encode_to_file, 1},
|
2016-05-29 01:07:36 +03:00
|
|
|
{"encode_to_pyfd", (PyCFunction)_encode_to_pyfd, 1},
|
2010-07-31 06:52:47 +04:00
|
|
|
{"setimage", (PyCFunction)_setimage, 1},
|
2016-05-29 01:07:36 +03:00
|
|
|
{"setfd", (PyCFunction)_setfd, 1},
|
2010-07-31 06:52:47 +04:00
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
|
};
|
|
|
|
|
2016-05-29 01:07:36 +03:00
|
|
|
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 */
|
|
|
|
};
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyTypeObject ImagingEncoderType = {
|
2014-03-04 08:43:47 +04:00
|
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
|
|
"ImagingEncoder", /*tp_name*/
|
|
|
|
sizeof(ImagingEncoderObject), /*tp_size*/
|
|
|
|
0, /*tp_itemsize*/
|
|
|
|
/* methods */
|
|
|
|
(destructor)_dealloc, /*tp_dealloc*/
|
|
|
|
0, /*tp_print*/
|
2012-10-13 20:53:07 +04:00
|
|
|
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*/
|
2016-05-29 01:07:36 +03:00
|
|
|
getseters, /*tp_getset*/
|
2010-07-31 06:52:47 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
int
|
|
|
|
get_packer(ImagingEncoderObject* encoder, const char* mode,
|
|
|
|
const char* rawmode)
|
|
|
|
{
|
|
|
|
int bits;
|
|
|
|
ImagingShuffler pack;
|
|
|
|
|
|
|
|
pack = ImagingFindPacker(mode, rawmode, &bits);
|
|
|
|
if (!pack) {
|
2014-03-04 08:43:47 +04:00
|
|
|
Py_DECREF(encoder);
|
2016-08-07 03:17:16 +03:00
|
|
|
PyErr_Format(PyExc_ValueError, "No packer found from %s to %s", mode, rawmode);
|
2014-03-04 08:43:47 +04:00
|
|
|
return -1;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
encoder->state.shuffle = pack;
|
|
|
|
encoder->state.bits = bits;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2014-03-04 08:43:47 +04:00
|
|
|
/* EPS */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
PyObject*
|
|
|
|
PyImaging_EpsEncoderNew(PyObject* self, PyObject* args)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject* encoder;
|
|
|
|
|
|
|
|
encoder = PyImaging_EncoderNew(0);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (encoder == NULL) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder->encode = ImagingEpsEncode;
|
|
|
|
|
|
|
|
return (PyObject*) encoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2014-03-04 08:43:47 +04:00
|
|
|
/* GIF */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
PyObject*
|
|
|
|
PyImaging_GifEncoderNew(PyObject* self, PyObject* args)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject* encoder;
|
|
|
|
|
|
|
|
char *mode;
|
|
|
|
char *rawmode;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t bits = 8;
|
|
|
|
Py_ssize_t interlace = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ss|nn", &mode, &rawmode, &bits, &interlace)) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder = PyImaging_EncoderNew(sizeof(GIFENCODERSTATE));
|
2020-05-10 12:56:36 +03:00
|
|
|
if (encoder == NULL) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (get_packer(encoder, mode, rawmode) < 0) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder->encode = ImagingGifEncode;
|
|
|
|
|
|
|
|
((GIFENCODERSTATE*)encoder->state.context)->bits = bits;
|
|
|
|
((GIFENCODERSTATE*)encoder->state.context)->interlace = interlace;
|
|
|
|
|
|
|
|
return (PyObject*) encoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2014-03-04 08:43:47 +04:00
|
|
|
/* PCX */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
PyObject*
|
|
|
|
PyImaging_PcxEncoderNew(PyObject* self, PyObject* args)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject* encoder;
|
|
|
|
|
|
|
|
char *mode;
|
|
|
|
char *rawmode;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t bits = 8;
|
2014-03-04 08:43:47 +04:00
|
|
|
|
2019-05-31 12:55:13 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ss|n", &mode, &rawmode, &bits)) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder = PyImaging_EncoderNew(0);
|
2014-03-04 08:43:47 +04:00
|
|
|
if (encoder == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2014-03-04 08:43:47 +04:00
|
|
|
if (get_packer(encoder, mode, rawmode) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder->encode = ImagingPcxEncode;
|
|
|
|
|
|
|
|
return (PyObject*) encoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2014-03-04 08:43:47 +04:00
|
|
|
/* RAW */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
PyObject*
|
|
|
|
PyImaging_RawEncoderNew(PyObject* self, PyObject* args)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject* encoder;
|
|
|
|
|
|
|
|
char *mode;
|
|
|
|
char *rawmode;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t stride = 0;
|
|
|
|
Py_ssize_t ystep = 1;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ss|nn", &mode, &rawmode, &stride, &ystep)) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder = PyImaging_EncoderNew(0);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (encoder == NULL) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (get_packer(encoder, mode, rawmode) < 0) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder->encode = ImagingRawEncode;
|
|
|
|
|
|
|
|
encoder->state.ystep = ystep;
|
|
|
|
encoder->state.count = stride;
|
|
|
|
|
|
|
|
return (PyObject*) encoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-15 23:01:06 +03:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* TGA */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
PyObject*
|
|
|
|
PyImaging_TgaRleEncoderNew(PyObject* self, PyObject* args)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject* encoder;
|
|
|
|
|
|
|
|
char *mode;
|
|
|
|
char *rawmode;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t ystep = 1;
|
2018-06-15 23:01:06 +03:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ss|n", &mode, &rawmode, &ystep)) {
|
2018-06-15 23:01:06 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-06-15 23:01:06 +03:00
|
|
|
|
|
|
|
encoder = PyImaging_EncoderNew(0);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (encoder == NULL) {
|
2018-06-15 23:01:06 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-06-15 23:01:06 +03:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (get_packer(encoder, mode, rawmode) < 0) {
|
2018-06-15 23:01:06 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-06-15 23:01:06 +03:00
|
|
|
|
|
|
|
encoder->encode = ImagingTgaRleEncode;
|
|
|
|
|
|
|
|
encoder->state.ystep = ystep;
|
|
|
|
|
|
|
|
return (PyObject*) encoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
2014-03-04 08:43:47 +04:00
|
|
|
/* XBM */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
PyObject*
|
|
|
|
PyImaging_XbmEncoderNew(PyObject* self, PyObject* args)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject* encoder;
|
|
|
|
|
|
|
|
encoder = PyImaging_EncoderNew(0);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (encoder == NULL) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (get_packer(encoder, "1", "1;R") < 0) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder->encode = ImagingXbmEncode;
|
|
|
|
|
|
|
|
return (PyObject*) encoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2014-03-04 08:43:47 +04:00
|
|
|
/* ZIP */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBZ
|
|
|
|
|
2020-09-22 06:33:05 +03:00
|
|
|
#include "libImaging/ZipCodecs.h"
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
PyObject*
|
|
|
|
PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject* encoder;
|
|
|
|
|
|
|
|
char* mode;
|
|
|
|
char* rawmode;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t optimize = 0;
|
|
|
|
Py_ssize_t compress_level = -1;
|
|
|
|
Py_ssize_t compress_type = -1;
|
2010-07-31 06:52:47 +04:00
|
|
|
char* dictionary = NULL;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t dictionary_size = 0;
|
2019-09-26 15:12:28 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ss|nnny#", &mode, &rawmode,
|
2013-03-11 23:33:04 +04:00
|
|
|
&optimize,
|
|
|
|
&compress_level, &compress_type,
|
2020-05-10 12:56:36 +03:00
|
|
|
&dictionary, &dictionary_size)) {
|
2012-10-14 20:38:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2012-10-14 20:38:06 +04:00
|
|
|
|
2016-04-15 18:48:57 +03:00
|
|
|
/* Copy to avoid referencing Python's memory */
|
2012-10-14 20:38:06 +04:00
|
|
|
if (dictionary && dictionary_size > 0) {
|
2016-03-16 14:47:18 +03:00
|
|
|
/* malloc check ok, size comes from PyArg_ParseTuple */
|
2012-10-14 20:38:06 +04:00
|
|
|
char* p = malloc(dictionary_size);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!p) {
|
2012-10-14 20:38:06 +04:00
|
|
|
return PyErr_NoMemory();
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2012-10-14 20:38:06 +04:00
|
|
|
memcpy(p, dictionary, dictionary_size);
|
|
|
|
dictionary = p;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2012-10-14 20:38:06 +04:00
|
|
|
dictionary = NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder = PyImaging_EncoderNew(sizeof(ZIPSTATE));
|
2018-09-13 13:22:11 +03:00
|
|
|
if (encoder == NULL) {
|
|
|
|
free(dictionary);
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2018-09-13 13:22:11 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2018-09-13 13:22:11 +03:00
|
|
|
if (get_packer(encoder, mode, rawmode) < 0) {
|
|
|
|
free(dictionary);
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2018-09-13 13:22:11 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder->encode = ImagingZipEncode;
|
2016-04-15 18:48:57 +03:00
|
|
|
encoder->cleanup = ImagingZipEncodeCleanup;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (rawmode[0] == 'P') {
|
2014-03-04 08:43:47 +04:00
|
|
|
/* disable filtering */
|
|
|
|
((ZIPSTATE*)encoder->state.context)->mode = ZIP_PNG_PALETTE;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
((ZIPSTATE*)encoder->state.context)->optimize = optimize;
|
2013-03-11 23:33:04 +04:00
|
|
|
((ZIPSTATE*)encoder->state.context)->compress_level = compress_level;
|
|
|
|
((ZIPSTATE*)encoder->state.context)->compress_type = compress_type;
|
2010-07-31 06:52:47 +04:00
|
|
|
((ZIPSTATE*)encoder->state.context)->dictionary = dictionary;
|
|
|
|
((ZIPSTATE*)encoder->state.context)->dictionary_size = dictionary_size;
|
|
|
|
|
|
|
|
return (PyObject*) encoder;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2019-05-21 14:18:09 +03:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* LibTiff */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBTIFF
|
|
|
|
|
2020-09-22 06:33:05 +03:00
|
|
|
#include "libImaging/TiffDecode.h"
|
2019-05-21 14:18:09 +03:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
PyObject*
|
|
|
|
PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject* encoder;
|
|
|
|
|
|
|
|
char* mode;
|
|
|
|
char* rawmode;
|
|
|
|
char* compname;
|
|
|
|
char* filename;
|
|
|
|
Py_ssize_t fp;
|
|
|
|
|
|
|
|
PyObject *tags, *types;
|
|
|
|
PyObject *key, *value;
|
|
|
|
Py_ssize_t pos = 0;
|
|
|
|
int key_int, status, is_core_tag, is_var_length, num_core_tags, i;
|
|
|
|
TIFFDataType type = TIFF_NOTYPE;
|
|
|
|
// This list also exists in TiffTags.py
|
|
|
|
const int core_tags[] = {
|
|
|
|
256, 257, 258, 259, 262, 263, 266, 269, 274, 277, 278, 280, 281, 340,
|
2020-05-26 09:38:38 +03:00
|
|
|
341, 282, 283, 284, 286, 287, 296, 297, 320, 321, 338, 32995, 32998, 32996,
|
2019-06-04 14:30:13 +03:00
|
|
|
339, 32997, 330, 531, 530, 65537
|
2019-05-21 14:18:09 +03:00
|
|
|
};
|
|
|
|
|
2019-06-04 14:30:13 +03:00
|
|
|
Py_ssize_t tags_size;
|
|
|
|
PyObject *item;
|
2019-05-21 14:18:09 +03:00
|
|
|
|
2019-06-30 07:03:09 +03:00
|
|
|
if (! PyArg_ParseTuple(args, "sssnsOO", &mode, &rawmode, &compname, &fp, &filename, &tags, &types)) {
|
2019-05-21 14:18:09 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-06-04 14:30:13 +03:00
|
|
|
if (!PyList_Check(tags)) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "Invalid tags list");
|
2019-05-21 14:18:09 +03:00
|
|
|
return NULL;
|
|
|
|
} else {
|
2019-06-04 14:30:13 +03:00
|
|
|
tags_size = PyList_Size(tags);
|
|
|
|
TRACE(("tags size: %d\n", (int)tags_size));
|
|
|
|
for (pos=0;pos<tags_size;pos++){
|
|
|
|
item = PyList_GetItem(tags, pos);
|
|
|
|
if (!PyTuple_Check(item) || PyTuple_Size(item) != 2) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "Invalid tags list");
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-05-21 14:18:09 +03:00
|
|
|
}
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
if (!PyDict_Check(types)) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "Invalid types dictionary");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE(("new tiff encoder %s fp: %d, filename: %s \n", compname, fp, filename));
|
|
|
|
|
|
|
|
encoder = PyImaging_EncoderNew(sizeof(TIFFSTATE));
|
2020-05-10 12:56:36 +03:00
|
|
|
if (encoder == NULL) {
|
2019-05-21 14:18:09 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2019-05-21 14:18:09 +03:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (get_packer(encoder, mode, rawmode) < 0) {
|
2019-05-21 14:18:09 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2019-05-21 14:18:09 +03:00
|
|
|
|
|
|
|
if (! ImagingLibTiffEncodeInit(&encoder->state, filename, fp)) {
|
|
|
|
Py_DECREF(encoder);
|
|
|
|
PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_core_tags = sizeof(core_tags) / sizeof(int);
|
2019-06-04 14:30:13 +03:00
|
|
|
for (pos = 0; pos < tags_size; pos++) {
|
|
|
|
item = PyList_GetItem(tags, pos);
|
|
|
|
// We already checked that tags is a 2-tuple list.
|
|
|
|
key = PyTuple_GetItem(item, 0);
|
2019-09-26 15:12:28 +03:00
|
|
|
key_int = (int)PyLong_AsLong(key);
|
2019-06-04 14:30:13 +03:00
|
|
|
value = PyTuple_GetItem(item, 1);
|
2019-05-21 14:18:09 +03:00
|
|
|
status = 0;
|
|
|
|
is_core_tag = 0;
|
|
|
|
is_var_length = 0;
|
|
|
|
type = TIFF_NOTYPE;
|
|
|
|
|
|
|
|
for (i=0; i<num_core_tags; i++) {
|
|
|
|
if (core_tags[i] == key_int) {
|
|
|
|
is_core_tag = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_core_tag) {
|
|
|
|
PyObject *tag_type = PyDict_GetItem(types, key);
|
|
|
|
if (tag_type) {
|
2019-09-26 15:12:28 +03:00
|
|
|
int type_int = PyLong_AsLong(tag_type);
|
2019-05-21 14:18:09 +03:00
|
|
|
if (type_int >= TIFF_BYTE && type_int <= TIFF_DOUBLE) {
|
|
|
|
type = (TIFFDataType)type_int;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (type == TIFF_NOTYPE) {
|
|
|
|
// Autodetect type. Types should not be changed for backwards
|
|
|
|
// compatibility.
|
2019-09-26 15:12:28 +03:00
|
|
|
if (PyLong_Check(value)) {
|
2019-05-21 14:18:09 +03:00
|
|
|
type = TIFF_LONG;
|
|
|
|
} else if (PyFloat_Check(value)) {
|
|
|
|
type = TIFF_DOUBLE;
|
|
|
|
} else if (PyBytes_Check(value)) {
|
|
|
|
type = TIFF_ASCII;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PyTuple_Check(value)) {
|
|
|
|
Py_ssize_t len;
|
|
|
|
len = PyTuple_Size(value);
|
|
|
|
|
|
|
|
is_var_length = 1;
|
|
|
|
|
|
|
|
if (!len) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == TIFF_NOTYPE) {
|
|
|
|
// Autodetect type based on first item. Types should not be
|
|
|
|
// changed for backwards compatibility.
|
2019-09-26 15:12:28 +03:00
|
|
|
if (PyLong_Check(PyTuple_GetItem(value,0))) {
|
2019-05-21 14:18:09 +03:00
|
|
|
type = TIFF_LONG;
|
|
|
|
} else if (PyFloat_Check(PyTuple_GetItem(value,0))) {
|
|
|
|
type = TIFF_FLOAT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_core_tag) {
|
|
|
|
// Register field for non core tags.
|
2020-05-05 14:20:59 +03:00
|
|
|
if (type == TIFF_BYTE) {
|
|
|
|
is_var_length = 1;
|
|
|
|
}
|
2019-05-21 14:18:09 +03:00
|
|
|
if (ImagingLibTiffMergeFieldInfo(&encoder->state, type, key_int, is_var_length)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-06 13:12:59 +03:00
|
|
|
if (type == TIFF_BYTE || type == TIFF_UNDEFINED) {
|
2020-05-05 14:20:59 +03:00
|
|
|
status = ImagingLibTiffSetField(&encoder->state,
|
|
|
|
(ttag_t) key_int,
|
|
|
|
PyBytes_Size(value), PyBytes_AsString(value));
|
|
|
|
} else if (is_var_length) {
|
2019-05-21 14:18:09 +03:00
|
|
|
Py_ssize_t len,i;
|
|
|
|
TRACE(("Setting from Tuple: %d \n", key_int));
|
|
|
|
len = PyTuple_Size(value);
|
|
|
|
|
2020-05-26 09:38:38 +03:00
|
|
|
if (key_int == TIFFTAG_COLORMAP) {
|
|
|
|
int stride = 256;
|
|
|
|
if (len != 768) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "Requiring 768 items for for Colormap");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
UINT16 *av;
|
|
|
|
/* malloc check ok, calloc checks for overflow */
|
|
|
|
av = calloc(len, sizeof(UINT16));
|
|
|
|
if (av) {
|
|
|
|
for (i=0;i<len;i++) {
|
|
|
|
av[i] = (UINT16)PyLong_AsLong(PyTuple_GetItem(value,i));
|
|
|
|
}
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int,
|
|
|
|
av,
|
|
|
|
av + stride,
|
|
|
|
av + stride * 2);
|
|
|
|
free(av);
|
|
|
|
}
|
|
|
|
} else if (type == TIFF_SHORT) {
|
2019-05-21 14:18:09 +03:00
|
|
|
UINT16 *av;
|
|
|
|
/* malloc check ok, calloc checks for overflow */
|
|
|
|
av = calloc(len, sizeof(UINT16));
|
|
|
|
if (av) {
|
|
|
|
for (i=0;i<len;i++) {
|
2019-09-26 15:12:28 +03:00
|
|
|
av[i] = (UINT16)PyLong_AsLong(PyTuple_GetItem(value,i));
|
2019-05-21 14:18:09 +03:00
|
|
|
}
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
|
|
|
|
free(av);
|
|
|
|
}
|
|
|
|
} else if (type == TIFF_LONG) {
|
|
|
|
UINT32 *av;
|
|
|
|
/* malloc check ok, calloc checks for overflow */
|
|
|
|
av = calloc(len, sizeof(UINT32));
|
|
|
|
if (av) {
|
|
|
|
for (i=0;i<len;i++) {
|
2019-09-26 15:12:28 +03:00
|
|
|
av[i] = (UINT32)PyLong_AsLong(PyTuple_GetItem(value,i));
|
2019-05-21 14:18:09 +03:00
|
|
|
}
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
|
|
|
|
free(av);
|
|
|
|
}
|
|
|
|
} else if (type == TIFF_SBYTE) {
|
|
|
|
INT8 *av;
|
|
|
|
/* malloc check ok, calloc checks for overflow */
|
|
|
|
av = calloc(len, sizeof(INT8));
|
|
|
|
if (av) {
|
|
|
|
for (i=0;i<len;i++) {
|
2019-09-26 15:12:28 +03:00
|
|
|
av[i] = (INT8)PyLong_AsLong(PyTuple_GetItem(value,i));
|
2019-05-21 14:18:09 +03:00
|
|
|
}
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
|
|
|
|
free(av);
|
|
|
|
}
|
|
|
|
} else if (type == TIFF_SSHORT) {
|
|
|
|
INT16 *av;
|
|
|
|
/* malloc check ok, calloc checks for overflow */
|
|
|
|
av = calloc(len, sizeof(INT16));
|
|
|
|
if (av) {
|
|
|
|
for (i=0;i<len;i++) {
|
2019-09-26 15:12:28 +03:00
|
|
|
av[i] = (INT16)PyLong_AsLong(PyTuple_GetItem(value,i));
|
2019-05-21 14:18:09 +03:00
|
|
|
}
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
|
|
|
|
free(av);
|
|
|
|
}
|
|
|
|
} else if (type == TIFF_SLONG) {
|
|
|
|
INT32 *av;
|
|
|
|
/* malloc check ok, calloc checks for overflow */
|
|
|
|
av = calloc(len, sizeof(INT32));
|
|
|
|
if (av) {
|
|
|
|
for (i=0;i<len;i++) {
|
2019-09-26 15:12:28 +03:00
|
|
|
av[i] = (INT32)PyLong_AsLong(PyTuple_GetItem(value,i));
|
2019-05-21 14:18:09 +03:00
|
|
|
}
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
|
|
|
|
free(av);
|
|
|
|
}
|
|
|
|
} else if (type == TIFF_FLOAT) {
|
|
|
|
FLOAT32 *av;
|
|
|
|
/* malloc check ok, calloc checks for overflow */
|
|
|
|
av = calloc(len, sizeof(FLOAT32));
|
|
|
|
if (av) {
|
|
|
|
for (i=0;i<len;i++) {
|
|
|
|
av[i] = (FLOAT32)PyFloat_AsDouble(PyTuple_GetItem(value,i));
|
|
|
|
}
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
|
|
|
|
free(av);
|
|
|
|
}
|
|
|
|
} else if (type == TIFF_DOUBLE) {
|
|
|
|
FLOAT64 *av;
|
|
|
|
/* malloc check ok, calloc checks for overflow */
|
|
|
|
av = calloc(len, sizeof(FLOAT64));
|
|
|
|
if (av) {
|
|
|
|
for (i=0;i<len;i++) {
|
|
|
|
av[i] = PyFloat_AsDouble(PyTuple_GetItem(value,i));
|
|
|
|
}
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
|
|
|
|
free(av);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (type == TIFF_SHORT) {
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state,
|
|
|
|
(ttag_t) key_int,
|
2019-09-26 15:12:28 +03:00
|
|
|
(UINT16)PyLong_AsLong(value));
|
2019-05-21 14:18:09 +03:00
|
|
|
} else if (type == TIFF_LONG) {
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state,
|
|
|
|
(ttag_t) key_int,
|
2019-09-26 15:12:28 +03:00
|
|
|
(UINT32)PyLong_AsLong(value));
|
2019-05-21 14:18:09 +03:00
|
|
|
} else if (type == TIFF_SSHORT) {
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state,
|
|
|
|
(ttag_t) key_int,
|
2019-09-26 15:12:28 +03:00
|
|
|
(INT16)PyLong_AsLong(value));
|
2019-05-21 14:18:09 +03:00
|
|
|
} else if (type == TIFF_SLONG) {
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state,
|
|
|
|
(ttag_t) key_int,
|
2019-09-26 15:12:28 +03:00
|
|
|
(INT32)PyLong_AsLong(value));
|
2019-05-21 14:18:09 +03:00
|
|
|
} else if (type == TIFF_FLOAT) {
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state,
|
|
|
|
(ttag_t) key_int,
|
|
|
|
(FLOAT32)PyFloat_AsDouble(value));
|
|
|
|
} else if (type == TIFF_DOUBLE) {
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state,
|
|
|
|
(ttag_t) key_int,
|
|
|
|
(FLOAT64)PyFloat_AsDouble(value));
|
|
|
|
} else if (type == TIFF_SBYTE) {
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state,
|
|
|
|
(ttag_t) key_int,
|
2019-09-26 15:12:28 +03:00
|
|
|
(INT8)PyLong_AsLong(value));
|
2019-05-21 14:18:09 +03:00
|
|
|
} else if (type == TIFF_ASCII) {
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state,
|
|
|
|
(ttag_t) key_int,
|
|
|
|
PyBytes_AsString(value));
|
|
|
|
} else if (type == TIFF_RATIONAL) {
|
|
|
|
status = ImagingLibTiffSetField(&encoder->state,
|
|
|
|
(ttag_t) key_int,
|
|
|
|
(FLOAT64)PyFloat_AsDouble(value));
|
|
|
|
} else {
|
|
|
|
TRACE(("Unhandled type for key %d : %s \n",
|
|
|
|
key_int,
|
|
|
|
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
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
2014-03-04 08:43:47 +04:00
|
|
|
/* JPEG */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
#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. */
|
|
|
|
|
2014-03-04 08:43:47 +04:00
|
|
|
#undef HAVE_PROTOTYPES
|
|
|
|
#undef HAVE_STDDEF_H
|
|
|
|
#undef HAVE_STDLIB_H
|
|
|
|
#undef UINT8
|
|
|
|
#undef UINT16
|
|
|
|
#undef UINT32
|
|
|
|
#undef INT8
|
|
|
|
#undef INT16
|
|
|
|
#undef INT32
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-09-22 06:33:05 +03:00
|
|
|
#include "libImaging/Jpeg.h"
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2014-09-23 09:30:00 +04:00
|
|
|
static unsigned int* get_qtables_arrays(PyObject* qtables, int* qtablesLen) {
|
2013-03-07 05:23:02 +04:00
|
|
|
PyObject* tables;
|
|
|
|
PyObject* table;
|
|
|
|
PyObject* table_data;
|
|
|
|
int i, j, num_tables;
|
2014-09-23 09:30:00 +04:00
|
|
|
unsigned int *qarrays;
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2013-05-12 03:56:15 +04:00
|
|
|
if ((qtables == NULL) || (qtables == Py_None)) {
|
2013-03-07 05:23:02 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2013-03-07 05:23:02 +04:00
|
|
|
if (!PySequence_Check(qtables)) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "Invalid quantization tables");
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2013-03-07 05:23:02 +04:00
|
|
|
tables = PySequence_Fast(qtables, "expected a sequence");
|
|
|
|
num_tables = PySequence_Size(qtables);
|
2014-09-02 22:49:24 +04:00
|
|
|
if (num_tables < 1 || num_tables > NUM_QUANT_TBLS) {
|
2015-10-11 13:24:35 +03:00
|
|
|
PyErr_SetString(PyExc_ValueError,
|
2014-09-23 09:30:00 +04:00
|
|
|
"Not a valid number of quantization tables. Should be between 1 and 4.");
|
|
|
|
Py_DECREF(tables);
|
2013-03-07 05:23:02 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2016-03-16 14:47:18 +03:00
|
|
|
/* malloc check ok, num_tables <4, DCTSIZE2 == 64 from jpeglib.h */
|
2014-09-23 09:30:00 +04:00
|
|
|
qarrays = (unsigned int*) malloc(num_tables * DCTSIZE2 * sizeof(unsigned int));
|
2013-03-07 05:23:02 +04:00
|
|
|
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)) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "Invalid quantization tables");
|
2014-09-23 09:30:00 +04:00
|
|
|
goto JPEG_QTABLES_ERR;
|
2013-03-07 05:23:02 +04:00
|
|
|
}
|
|
|
|
if (PySequence_Size(table) != DCTSIZE2) {
|
2014-09-23 09:30:00 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, "Invalid quantization table size");
|
|
|
|
goto JPEG_QTABLES_ERR;
|
2013-03-07 05:23:02 +04:00
|
|
|
}
|
|
|
|
table_data = PySequence_Fast(table, "expected a sequence");
|
|
|
|
for (j = 0; j < DCTSIZE2; j++) {
|
2019-09-26 15:12:28 +03:00
|
|
|
qarrays[i * DCTSIZE2 + j] = PyLong_AS_LONG(PySequence_Fast_GET_ITEM(table_data, j));
|
2013-03-07 05:23:02 +04:00
|
|
|
}
|
2014-09-25 02:27:43 +04:00
|
|
|
Py_DECREF(table_data);
|
2013-03-07 05:23:02 +04:00
|
|
|
}
|
|
|
|
|
2015-10-11 13:24:35 +03:00
|
|
|
*qtablesLen = num_tables;
|
2013-03-07 05:23:02 +04:00
|
|
|
|
2014-09-23 09:30:00 +04:00
|
|
|
JPEG_QTABLES_ERR:
|
|
|
|
Py_DECREF(tables); // Run on both error and not error
|
2013-03-07 05:23:02 +04:00
|
|
|
if (PyErr_Occurred()) {
|
2014-09-23 09:30:00 +04:00
|
|
|
free(qarrays);
|
2013-03-07 05:23:02 +04:00
|
|
|
qarrays = NULL;
|
2014-09-23 09:30:00 +04:00
|
|
|
return NULL;
|
2013-03-07 05:23:02 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return qarrays;
|
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
PyObject*
|
|
|
|
PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject* encoder;
|
|
|
|
|
|
|
|
char *mode;
|
|
|
|
char *rawmode;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t quality = 0;
|
|
|
|
Py_ssize_t progressive = 0;
|
|
|
|
Py_ssize_t smooth = 0;
|
|
|
|
Py_ssize_t optimize = 0;
|
|
|
|
Py_ssize_t streamtype = 0; /* 0=interchange, 1=tables only, 2=image only */
|
|
|
|
Py_ssize_t xdpi = 0, ydpi = 0;
|
|
|
|
Py_ssize_t subsampling = -1; /* -1=default, 0=none, 1=medium, 2=high */
|
2013-05-12 03:56:15 +04:00
|
|
|
PyObject* qtables=NULL;
|
2014-09-23 09:30:00 +04:00
|
|
|
unsigned int *qarrays = NULL;
|
2014-09-23 09:22:30 +04:00
|
|
|
int qtablesLen = 0;
|
2013-01-11 00:36:21 +04:00
|
|
|
char* extra = NULL;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t extra_size;
|
2013-01-11 00:36:21 +04:00
|
|
|
char* rawExif = NULL;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t rawExifLen = 0;
|
2013-01-11 00:36:21 +04:00
|
|
|
|
2019-09-26 15:12:28 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ss|nnnnnnnnOy#y#",
|
2012-10-14 20:38:06 +04:00
|
|
|
&mode, &rawmode, &quality,
|
|
|
|
&progressive, &smooth, &optimize, &streamtype,
|
2013-03-07 05:23:02 +04:00
|
|
|
&xdpi, &ydpi, &subsampling, &qtables, &extra, &extra_size,
|
2020-05-10 12:56:36 +03:00
|
|
|
&rawExif, &rawExifLen)) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
encoder = PyImaging_EncoderNew(sizeof(JPEGENCODERSTATE));
|
2020-05-10 12:56:36 +03:00
|
|
|
if (encoder == NULL) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2017-08-11 04:10:55 +03:00
|
|
|
// libjpeg-turbo supports different output formats.
|
|
|
|
// We are choosing Pillow's native format (3 color bytes + 1 padding)
|
|
|
|
// to avoid extra conversion in Pack.c.
|
|
|
|
if (ImagingJpegUseJCSExtensions() && strcmp(rawmode, "RGB") == 0) {
|
|
|
|
rawmode = "RGBX";
|
|
|
|
}
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (get_packer(encoder, mode, rawmode) < 0) {
|
2014-03-04 08:43:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-04-15 18:48:57 +03:00
|
|
|
// Freed in JpegEncode, Case 5
|
2014-09-23 09:22:30 +04:00
|
|
|
qarrays = get_qtables_arrays(qtables, &qtablesLen);
|
2013-03-07 05:23:02 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
if (extra && extra_size > 0) {
|
2016-03-16 14:47:18 +03:00
|
|
|
/* malloc check ok, length is from python parsearg */
|
2014-09-23 09:30:00 +04:00
|
|
|
char* p = malloc(extra_size); // Freed in JpegEncode, Case 5
|
2020-05-11 00:46:12 +03:00
|
|
|
if (!p) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return PyErr_NoMemory();
|
2020-05-11 00:46:12 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
memcpy(p, extra, extra_size);
|
|
|
|
extra = p;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2010-07-31 06:52:47 +04:00
|
|
|
extra = NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2013-01-11 00:36:21 +04:00
|
|
|
if (rawExif && rawExifLen > 0) {
|
2016-03-16 14:47:18 +03:00
|
|
|
/* malloc check ok, length is from python parsearg */
|
2014-09-23 09:30:00 +04:00
|
|
|
char* pp = malloc(rawExifLen); // Freed in JpegEncode, Case 5
|
2018-09-13 13:22:11 +03:00
|
|
|
if (!pp) {
|
2020-05-11 00:46:12 +03:00
|
|
|
if (extra) {
|
|
|
|
free(extra);
|
|
|
|
}
|
2013-01-11 00:36:21 +04:00
|
|
|
return PyErr_NoMemory();
|
2018-09-13 13:22:11 +03:00
|
|
|
}
|
2013-01-11 00:36:21 +04:00
|
|
|
memcpy(pp, rawExif, rawExifLen);
|
|
|
|
rawExif = pp;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2013-01-11 00:36:21 +04:00
|
|
|
rawExif = NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2013-01-11 00:36:21 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
encoder->encode = ImagingJpegEncode;
|
|
|
|
|
2017-08-11 04:10:55 +03:00
|
|
|
strncpy(((JPEGENCODERSTATE*)encoder->state.context)->rawmode, rawmode, 8);
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
((JPEGENCODERSTATE*)encoder->state.context)->quality = quality;
|
2013-03-07 05:23:02 +04:00
|
|
|
((JPEGENCODERSTATE*)encoder->state.context)->qtables = qarrays;
|
2014-09-23 09:22:30 +04:00
|
|
|
((JPEGENCODERSTATE*)encoder->state.context)->qtablesLen = qtablesLen;
|
2010-07-31 06:52:47 +04:00
|
|
|
((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;
|
2013-01-11 00:36:21 +04:00
|
|
|
((JPEGENCODERSTATE*)encoder->state.context)->rawExif = rawExif;
|
|
|
|
((JPEGENCODERSTATE*)encoder->state.context)->rawExifLen = rawExifLen;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return (PyObject*) encoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2013-03-09 07:51:59 +04:00
|
|
|
|
|
|
|
|
2014-03-13 22:27:16 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
2020-05-01 15:08:57 +03:00
|
|
|
/* JPEG 2000 */
|
2014-03-13 22:27:16 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
#ifdef HAVE_OPENJPEG
|
|
|
|
|
2020-09-22 06:33:05 +03:00
|
|
|
#include "libImaging/Jpeg2K.h"
|
2014-03-13 22:27:16 +04:00
|
|
|
|
|
|
|
static void
|
|
|
|
j2k_decode_coord_tuple(PyObject *tuple, int *x, int *y)
|
|
|
|
{
|
|
|
|
*x = *y = 0;
|
|
|
|
|
|
|
|
if (tuple && PyTuple_Check(tuple) && PyTuple_GET_SIZE(tuple) == 2) {
|
2019-09-26 15:12:28 +03:00
|
|
|
*x = (int)PyLong_AsLong(PyTuple_GET_ITEM(tuple, 0));
|
|
|
|
*y = (int)PyLong_AsLong(PyTuple_GET_ITEM(tuple, 1));
|
2014-03-13 22:27:16 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (*x < 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
*x = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
|
|
|
if (*y < 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
*y = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-03-13 22:27:16 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PyObject*
|
|
|
|
PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
ImagingEncoderObject *encoder;
|
|
|
|
JPEG2KENCODESTATE *context;
|
|
|
|
|
|
|
|
char *mode;
|
|
|
|
char *format;
|
|
|
|
OPJ_CODEC_FORMAT codec_format;
|
|
|
|
PyObject *offset = NULL, *tile_offset = NULL, *tile_size = NULL;
|
|
|
|
char *quality_mode = "rates";
|
|
|
|
PyObject *quality_layers = NULL;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t num_resolutions = 0;
|
2014-03-14 19:40:30 +04:00
|
|
|
PyObject *cblk_size = NULL, *precinct_size = NULL;
|
2014-03-14 15:21:08 +04:00
|
|
|
PyObject *irreversible = NULL;
|
2014-03-13 22:27:16 +04:00
|
|
|
char *progression = "LRCP";
|
|
|
|
OPJ_PROG_ORDER prog_order;
|
|
|
|
char *cinema_mode = "no";
|
|
|
|
OPJ_CINEMA_MODE cine_mode;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t fd = -1;
|
2014-03-13 22:27:16 +04:00
|
|
|
|
2019-05-31 12:55:13 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ss|OOOsOnOOOssn", &mode, &format,
|
2014-03-13 22:27:16 +04:00
|
|
|
&offset, &tile_offset, &tile_size,
|
|
|
|
&quality_mode, &quality_layers, &num_resolutions,
|
2014-03-14 19:40:30 +04:00
|
|
|
&cblk_size, &precinct_size,
|
|
|
|
&irreversible, &progression, &cinema_mode,
|
2020-05-10 12:56:36 +03:00
|
|
|
&fd)) {
|
2014-03-13 22:27:16 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-03-13 22:27:16 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (strcmp (format, "j2k") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
codec_format = OPJ_CODEC_J2K;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (strcmp (format, "jpt") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
codec_format = OPJ_CODEC_JPT;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (strcmp (format, "jp2") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
codec_format = OPJ_CODEC_JP2;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2014-03-13 22:27:16 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-03-13 22:27:16 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (strcmp(progression, "LRCP") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
prog_order = OPJ_LRCP;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (strcmp(progression, "RLCP") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
prog_order = OPJ_RLCP;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (strcmp(progression, "RPCL") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
prog_order = OPJ_RPCL;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (strcmp(progression, "PCRL") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
prog_order = OPJ_PCRL;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (strcmp(progression, "CPRL") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
prog_order = OPJ_CPRL;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2014-03-13 22:27:16 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-03-13 22:27:16 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (strcmp(cinema_mode, "no") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
cine_mode = OPJ_OFF;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (strcmp(cinema_mode, "cinema2k-24") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
cine_mode = OPJ_CINEMA2K_24;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (strcmp(cinema_mode, "cinema2k-48") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
cine_mode = OPJ_CINEMA2K_48;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (strcmp(cinema_mode, "cinema4k-24") == 0) {
|
2014-03-13 22:27:16 +04:00
|
|
|
cine_mode = OPJ_CINEMA4K_24;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2014-03-13 22:27:16 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-03-13 22:27:16 +04:00
|
|
|
|
2014-03-19 16:16:14 +04:00
|
|
|
encoder = PyImaging_EncoderNew(sizeof(JPEG2KENCODESTATE));
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!encoder) {
|
2014-03-13 22:27:16 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-03-13 22:27:16 +04:00
|
|
|
|
|
|
|
encoder->encode = ImagingJpeg2KEncode;
|
|
|
|
encoder->cleanup = ImagingJpeg2KEncodeCleanup;
|
2016-05-29 01:07:36 +03:00
|
|
|
encoder->pushes_fd = 1;
|
2014-03-13 22:27:16 +04:00
|
|
|
|
|
|
|
context = (JPEG2KENCODESTATE *)encoder->state.context;
|
|
|
|
|
2014-03-14 15:21:08 +04:00
|
|
|
context->fd = fd;
|
2014-03-13 22:27:16 +04:00
|
|
|
context->format = codec_format;
|
|
|
|
context->offset_x = context->offset_y = 0;
|
|
|
|
|
2016-05-29 01:07:36 +03:00
|
|
|
|
2014-03-13 22:27:16 +04:00
|
|
|
j2k_decode_coord_tuple(offset, &context->offset_x, &context->offset_y);
|
|
|
|
j2k_decode_coord_tuple(tile_offset,
|
|
|
|
&context->tile_offset_x,
|
|
|
|
&context->tile_offset_y);
|
2014-09-02 22:49:24 +04:00
|
|
|
j2k_decode_coord_tuple(tile_size,
|
2014-03-13 22:27:16 +04:00
|
|
|
&context->tile_size_x,
|
|
|
|
&context->tile_size_y);
|
|
|
|
|
2014-03-19 16:16:14 +04:00
|
|
|
/* Error on illegal tile offsets */
|
|
|
|
if (context->tile_size_x && context->tile_size_y) {
|
|
|
|
if (context->tile_offset_x <= context->offset_x - context->tile_size_x
|
|
|
|
|| context->tile_offset_y <= context->offset_y - context->tile_size_y) {
|
|
|
|
PyErr_SetString(PyExc_ValueError,
|
|
|
|
"JPEG 2000 tile offset too small; top left tile must "
|
|
|
|
"intersect image area");
|
2019-07-13 06:50:13 +03:00
|
|
|
Py_DECREF(encoder);
|
|
|
|
return NULL;
|
2014-03-19 16:16:14 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (context->tile_offset_x > context->offset_x
|
|
|
|
|| context->tile_offset_y > context->offset_y) {
|
2014-09-02 22:49:24 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError,
|
2014-03-19 16:16:14 +04:00
|
|
|
"JPEG 2000 tile offset too large to cover image area");
|
|
|
|
Py_DECREF(encoder);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-13 22:27:16 +04:00
|
|
|
if (quality_layers && PySequence_Check(quality_layers)) {
|
|
|
|
context->quality_is_in_db = strcmp (quality_mode, "dB") == 0;
|
|
|
|
context->quality_layers = quality_layers;
|
2014-03-14 15:21:08 +04:00
|
|
|
Py_INCREF(quality_layers);
|
2014-03-13 22:27:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
context->num_resolutions = num_resolutions;
|
2014-03-04 08:43:47 +04:00
|
|
|
|
2014-03-13 22:27:16 +04:00
|
|
|
j2k_decode_coord_tuple(cblk_size,
|
|
|
|
&context->cblk_width,
|
|
|
|
&context->cblk_height);
|
2014-03-14 19:40:30 +04:00
|
|
|
j2k_decode_coord_tuple(precinct_size,
|
|
|
|
&context->precinct_width,
|
|
|
|
&context->precinct_height);
|
2014-03-13 22:27:16 +04:00
|
|
|
|
2014-03-14 15:21:08 +04:00
|
|
|
context->irreversible = PyObject_IsTrue(irreversible);
|
2014-03-13 22:27:16 +04:00
|
|
|
context->progression = prog_order;
|
|
|
|
context->cinema_mode = cine_mode;
|
|
|
|
|
|
|
|
return (PyObject *)encoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local Variables:
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* End:
|
|
|
|
*
|
|
|
|
*/
|