mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 17:24:31 +03:00
Merge branch 'pcx' of https://github.com/wiredfool/Pillow into wiredfool-pcx
This commit is contained in:
commit
c1d44980b8
|
@ -8,6 +8,8 @@ Changelog (Pillow)
|
|||
[wiredfool]
|
||||
|
||||
- Skip CFFI test earlier if it's not installed
|
||||
|
||||
- Fixed opening and saving odd sized .pcx files, fixes #523
|
||||
[wiredfool]
|
||||
|
||||
- Fixed saving mode P image as a PNG with transparency = palette color 0
|
||||
|
|
|
@ -55,12 +55,18 @@ class PcxImageFile(ImageFile.ImageFile):
|
|||
bbox = i16(s,4), i16(s,6), i16(s,8)+1, i16(s,10)+1
|
||||
if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]:
|
||||
raise SyntaxError("bad PCX image size")
|
||||
if Image.DEBUG:
|
||||
print ("BBox: %s %s %s %s" % bbox)
|
||||
|
||||
|
||||
# format
|
||||
version = i8(s[1])
|
||||
bits = i8(s[3])
|
||||
planes = i8(s[65])
|
||||
stride = i16(s,66)
|
||||
if Image.DEBUG:
|
||||
print ("PCX version %s, bits %s, planes %s, stride %s" %
|
||||
(version, bits, planes, stride))
|
||||
|
||||
self.info["dpi"] = i16(s,12), i16(s,14)
|
||||
|
||||
|
@ -98,7 +104,9 @@ class PcxImageFile(ImageFile.ImageFile):
|
|||
self.size = bbox[2]-bbox[0], bbox[3]-bbox[1]
|
||||
|
||||
bbox = (0, 0) + self.size
|
||||
|
||||
if Image.DEBUG:
|
||||
print ("size: %sx%s" % self.size)
|
||||
|
||||
self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))]
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
@ -126,6 +134,16 @@ def _save(im, fp, filename, check=0):
|
|||
|
||||
# bytes per plane
|
||||
stride = (im.size[0] * bits + 7) // 8
|
||||
# stride should be even
|
||||
stride = stride + (stride % 2)
|
||||
# Stride needs to be kept in sync with the PcxEncode.c version.
|
||||
# Ideally it should be passed in in the state, but the bytes value
|
||||
# gets overwritten.
|
||||
|
||||
|
||||
if Image.DEBUG:
|
||||
print ("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" % (
|
||||
im.size[0], bits, stride))
|
||||
|
||||
# under windows, we could determine the current screen size with
|
||||
# "Image.core.display_mode()[1]", but I think that's overkill...
|
||||
|
|
|
@ -2,29 +2,30 @@ from tester import *
|
|||
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def _roundtrip(im):
|
||||
f = tempfile("temp.pcx")
|
||||
im.save(f)
|
||||
im2 = Image.open(f)
|
||||
|
||||
assert_equal(im2.mode, im.mode)
|
||||
assert_equal(im2.size, im.size)
|
||||
assert_equal(im2.format, "PCX")
|
||||
assert_image_equal(im2, im)
|
||||
|
||||
def test_sanity():
|
||||
for mode in ('1', 'L', 'P', 'RGB'):
|
||||
_roundtrip(lena(mode))
|
||||
|
||||
file = tempfile("temp.pcx")
|
||||
|
||||
lena("1").save(file)
|
||||
|
||||
im = Image.open(file)
|
||||
im.load()
|
||||
assert_equal(im.mode, "1")
|
||||
assert_equal(im.size, (128, 128))
|
||||
assert_equal(im.format, "PCX")
|
||||
|
||||
lena("1").save(file)
|
||||
im = Image.open(file)
|
||||
|
||||
lena("L").save(file)
|
||||
im = Image.open(file)
|
||||
|
||||
lena("P").save(file)
|
||||
im = Image.open(file)
|
||||
|
||||
lena("RGB").save(file)
|
||||
im = Image.open(file)
|
||||
def test_odd():
|
||||
# see issue #523, odd sized images should have a stride that's even.
|
||||
# not that imagemagick or gimp write pcx that way.
|
||||
# we were not handling properly.
|
||||
for mode in ('1', 'L', 'P', 'RGB'):
|
||||
# larger, odd sized images are better here to ensure that
|
||||
# we handle interrupted scan lines properly.
|
||||
_roundtrip(lena(mode).resize((511,511)))
|
||||
|
||||
|
||||
def test_pil184():
|
||||
# Check reading of files where xmin/xmax is not zero.
|
||||
|
|
191
encode.c
191
encode.c
|
@ -33,13 +33,13 @@
|
|||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Common */
|
||||
/* Common */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
int (*encode)(Imaging im, ImagingCodecState state,
|
||||
UINT8* buffer, int bytes);
|
||||
UINT8* buffer, int bytes);
|
||||
struct ImagingCodecStateInstance state;
|
||||
Imaging im;
|
||||
PyObject* lock;
|
||||
|
@ -58,21 +58,21 @@ PyImaging_EncoderNew(int contextsize)
|
|||
|
||||
encoder = PyObject_New(ImagingEncoderObject, &ImagingEncoderType);
|
||||
if (encoder == NULL)
|
||||
return 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;
|
||||
}
|
||||
context = (void*) calloc(1, contextsize);
|
||||
if (!context) {
|
||||
Py_DECREF(encoder);
|
||||
(void) PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
} else
|
||||
context = 0;
|
||||
context = 0;
|
||||
|
||||
/* Initialize encoder context */
|
||||
encoder->state.context = context;
|
||||
|
@ -105,14 +105,14 @@ _encode(ImagingEncoderObject* encoder, PyObject* args)
|
|||
int bufsize = 16384;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|i", &bufsize))
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
buf = PyBytes_FromStringAndSize(NULL, bufsize);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
status = encoder->encode(encoder->im, &encoder->state,
|
||||
(UINT8*) PyBytes_AsString(buf), bufsize);
|
||||
(UINT8*) PyBytes_AsString(buf), bufsize);
|
||||
|
||||
/* adjust string length to avoid slicing in encoder */
|
||||
if (_PyBytes_Resize(&buf, (status > 0) ? status : 0) < 0)
|
||||
|
@ -138,28 +138,28 @@ _encode_to_file(ImagingEncoderObject* encoder, PyObject* args)
|
|||
int bufsize = 16384;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|i", &fh, &bufsize))
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
/* Allocate an encoder buffer */
|
||||
buf = (UINT8*) malloc(bufsize);
|
||||
if (!buf)
|
||||
return PyErr_NoMemory();
|
||||
return PyErr_NoMemory();
|
||||
|
||||
ImagingSectionEnter(&cookie);
|
||||
|
||||
do {
|
||||
|
||||
/* This replaces the inner loop in the ImageFile _save
|
||||
function. */
|
||||
/* This replaces the inner loop in the ImageFile _save
|
||||
function. */
|
||||
|
||||
status = encoder->encode(encoder->im, &encoder->state, buf, bufsize);
|
||||
status = encoder->encode(encoder->im, &encoder->state, buf, bufsize);
|
||||
|
||||
if (status > 0)
|
||||
if (write(fh, buf, status) < 0) {
|
||||
if (status > 0)
|
||||
if (write(fh, buf, status) < 0) {
|
||||
ImagingSectionLeave(&cookie);
|
||||
free(buf);
|
||||
return PyErr_SetFromErrno(PyExc_IOError);
|
||||
}
|
||||
free(buf);
|
||||
return PyErr_SetFromErrno(PyExc_IOError);
|
||||
}
|
||||
|
||||
} while (encoder->state.errcode == 0);
|
||||
|
||||
|
@ -186,39 +186,39 @@ _setimage(ImagingEncoderObject* encoder, PyObject* args)
|
|||
|
||||
/* FIXME: should publish the ImagingType descriptor */
|
||||
if (!PyArg_ParseTuple(args, "O|(iiii)", &op, &x0, &y0, &x1, &y1))
|
||||
return NULL;
|
||||
return NULL;
|
||||
im = PyImaging_AsImaging(op);
|
||||
if (!im)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
encoder->im = im;
|
||||
|
||||
state = &encoder->state;
|
||||
|
||||
if (x0 == 0 && x1 == 0) {
|
||||
state->xsize = im->xsize;
|
||||
state->ysize = im->ysize;
|
||||
state->xsize = im->xsize;
|
||||
state->ysize = im->ysize;
|
||||
} else {
|
||||
state->xoff = x0;
|
||||
state->yoff = y0;
|
||||
state->xsize = x1 - x0;
|
||||
state->ysize = y1 - y0;
|
||||
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;
|
||||
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();
|
||||
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
|
||||
|
@ -239,13 +239,13 @@ static struct PyMethodDef methods[] = {
|
|||
};
|
||||
|
||||
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*/
|
||||
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*/
|
||||
|
@ -283,9 +283,9 @@ get_packer(ImagingEncoderObject* encoder, const char* mode,
|
|||
|
||||
pack = ImagingFindPacker(mode, rawmode, &bits);
|
||||
if (!pack) {
|
||||
Py_DECREF(encoder);
|
||||
PyErr_SetString(PyExc_SystemError, "unknown raw mode");
|
||||
return -1;
|
||||
Py_DECREF(encoder);
|
||||
PyErr_SetString(PyExc_SystemError, "unknown raw mode");
|
||||
return -1;
|
||||
}
|
||||
|
||||
encoder->state.shuffle = pack;
|
||||
|
@ -296,7 +296,7 @@ get_packer(ImagingEncoderObject* encoder, const char* mode,
|
|||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* EPS */
|
||||
/* EPS */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
PyObject*
|
||||
|
@ -306,7 +306,7 @@ PyImaging_EpsEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
encoder = PyImaging_EncoderNew(0);
|
||||
if (encoder == NULL)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
encoder->encode = ImagingEpsEncode;
|
||||
|
||||
|
@ -315,7 +315,7 @@ PyImaging_EpsEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* GIF */
|
||||
/* GIF */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
PyObject*
|
||||
|
@ -328,14 +328,14 @@ PyImaging_GifEncoderNew(PyObject* self, PyObject* args)
|
|||
int bits = 8;
|
||||
int interlace = 0;
|
||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits, &interlace))
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
encoder = PyImaging_EncoderNew(sizeof(GIFENCODERSTATE));
|
||||
if (encoder == NULL)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
if (get_packer(encoder, mode, rawmode) < 0)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
encoder->encode = ImagingGifEncode;
|
||||
|
||||
|
@ -347,7 +347,7 @@ PyImaging_GifEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* PCX */
|
||||
/* PCX */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
PyObject*
|
||||
|
@ -358,15 +358,19 @@ PyImaging_PcxEncoderNew(PyObject* self, PyObject* args)
|
|||
char *mode;
|
||||
char *rawmode;
|
||||
int bits = 8;
|
||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits))
|
||||
return NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
encoder = PyImaging_EncoderNew(0);
|
||||
if (encoder == NULL)
|
||||
return NULL;
|
||||
if (encoder == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (get_packer(encoder, mode, rawmode) < 0)
|
||||
return NULL;
|
||||
if (get_packer(encoder, mode, rawmode) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
encoder->encode = ImagingPcxEncode;
|
||||
|
||||
|
@ -375,7 +379,7 @@ PyImaging_PcxEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* RAW */
|
||||
/* RAW */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
PyObject*
|
||||
|
@ -389,14 +393,14 @@ PyImaging_RawEncoderNew(PyObject* self, PyObject* args)
|
|||
int ystep = 1;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &stride, &ystep))
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
encoder = PyImaging_EncoderNew(0);
|
||||
if (encoder == NULL)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
if (get_packer(encoder, mode, rawmode) < 0)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
encoder->encode = ImagingRawEncode;
|
||||
|
||||
|
@ -408,7 +412,7 @@ PyImaging_RawEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* XBM */
|
||||
/* XBM */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
PyObject*
|
||||
|
@ -418,10 +422,10 @@ PyImaging_XbmEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
encoder = PyImaging_EncoderNew(0);
|
||||
if (encoder == NULL)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
if (get_packer(encoder, "1", "1;R") < 0)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
encoder->encode = ImagingXbmEncode;
|
||||
|
||||
|
@ -430,7 +434,7 @@ PyImaging_XbmEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* ZIP */
|
||||
/* ZIP */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
|
@ -469,16 +473,16 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
encoder = PyImaging_EncoderNew(sizeof(ZIPSTATE));
|
||||
if (encoder == NULL)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
if (get_packer(encoder, mode, rawmode) < 0)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
encoder->encode = ImagingZipEncode;
|
||||
|
||||
if (rawmode[0] == 'P')
|
||||
/* disable filtering */
|
||||
((ZIPSTATE*)encoder->state.context)->mode = ZIP_PNG_PALETTE;
|
||||
/* disable filtering */
|
||||
((ZIPSTATE*)encoder->state.context)->mode = ZIP_PNG_PALETTE;
|
||||
|
||||
((ZIPSTATE*)encoder->state.context)->optimize = optimize;
|
||||
((ZIPSTATE*)encoder->state.context)->compress_level = compress_level;
|
||||
|
@ -492,7 +496,7 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* JPEG */
|
||||
/* JPEG */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
#ifdef HAVE_LIBJPEG
|
||||
|
@ -500,15 +504,15 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
|
|||
/* 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
|
||||
#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"
|
||||
|
||||
|
@ -601,14 +605,14 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
|
|||
&progressive, &smooth, &optimize, &streamtype,
|
||||
&xdpi, &ydpi, &subsampling, &qtables, &extra, &extra_size,
|
||||
&rawExif, &rawExifLen))
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
encoder = PyImaging_EncoderNew(sizeof(JPEGENCODERSTATE));
|
||||
if (encoder == NULL)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
if (get_packer(encoder, mode, rawmode) < 0)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
qarrays = get_qtables_arrays(qtables);
|
||||
|
||||
|
@ -718,11 +722,11 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|||
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);
|
||||
// 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)) {
|
||||
|
@ -793,3 +797,4 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -57,7 +57,16 @@ ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
|||
}
|
||||
|
||||
if (state->x >= state->bytes) {
|
||||
|
||||
if (state->bytes % state->xsize && state->bytes > state->xsize) {
|
||||
int bands = state->bytes / state->xsize;
|
||||
int stride = state->bytes / bands;
|
||||
int i;
|
||||
for (i=1; i< bands; i++) { // note -- skipping first band
|
||||
memmove(&state->buffer[i*state->xsize],
|
||||
&state->buffer[i*stride],
|
||||
state->xsize);
|
||||
}
|
||||
}
|
||||
/* Got a full line, unpack it */
|
||||
state->shuffle((UINT8*) im->image[state->y + state->yoff] +
|
||||
state->xoff * im->pixelsize, state->buffer,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* encoder for PCX data
|
||||
*
|
||||
* history:
|
||||
* 99-02-07 fl created
|
||||
* 99-02-07 fl created
|
||||
*
|
||||
* Copyright (c) Fredrik Lundh 1999.
|
||||
* Copyright (c) Secret Labs AB 1999.
|
||||
|
@ -26,23 +26,41 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
|||
{
|
||||
UINT8* ptr;
|
||||
int this;
|
||||
int bytes_per_line = 0;
|
||||
int padding = 0;
|
||||
int stride = 0;
|
||||
int bpp = 0;
|
||||
int planes = 1;
|
||||
int i;
|
||||
|
||||
ptr = buf;
|
||||
|
||||
if (!state->state) {
|
||||
|
||||
/* sanity check */
|
||||
if (state->xsize <= 0 || state->ysize <= 0) {
|
||||
state->errcode = IMAGING_CODEC_END;
|
||||
return 0;
|
||||
}
|
||||
|
||||
state->bytes = (state->xsize*state->bits + 7) / 8;
|
||||
state->state = FETCH;
|
||||
|
||||
}
|
||||
|
||||
for (;;)
|
||||
bpp = state->bits;
|
||||
if (state->bits == 24){
|
||||
planes = 3;
|
||||
bpp = 8;
|
||||
}
|
||||
|
||||
bytes_per_line = (state->xsize*bpp + 7) / 8;
|
||||
/* The stride here needs to be kept in sync with the version in
|
||||
PcxImagePlugin.py. If it's not, the header and the body of the
|
||||
image will be out of sync and bad things will happen on decode.
|
||||
*/
|
||||
stride = bytes_per_line + (bytes_per_line % 2);
|
||||
|
||||
padding = stride - bytes_per_line;
|
||||
|
||||
|
||||
for (;;) {
|
||||
|
||||
switch (state->state) {
|
||||
case FETCH:
|
||||
|
@ -68,81 +86,103 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
|||
/* fall through */
|
||||
|
||||
case ENCODE:
|
||||
|
||||
/* compress this line */
|
||||
|
||||
/* when we arrive here, "count" contains the number of
|
||||
bytes having the value of "LAST" that we've already
|
||||
seen */
|
||||
while (state->x < planes * bytes_per_line) {
|
||||
/* If we're encoding an odd width file, and we've
|
||||
got more than one plane, we need to pad each
|
||||
color row with padding bytes at the end. Since
|
||||
The pixels are stored RRRRRGGGGGBBBBB, so we need
|
||||
to have the padding be RRRRRPGGGGGPBBBBBP. Hence
|
||||
the double loop
|
||||
*/
|
||||
while (state->x % bytes_per_line) {
|
||||
|
||||
while (state->x < state->bytes) {
|
||||
|
||||
if (state->count == 63) {
|
||||
|
||||
/* this run is full; flush it */
|
||||
if (bytes < 2)
|
||||
return ptr - buf;
|
||||
*ptr++ = 0xff;
|
||||
*ptr++ = state->LAST;
|
||||
bytes -= 2;
|
||||
|
||||
state->count = 0;
|
||||
|
||||
}
|
||||
|
||||
this = state->buffer[state->x];
|
||||
|
||||
if (this == state->LAST) {
|
||||
|
||||
/* extend the current run */
|
||||
state->x++;
|
||||
state->count++;
|
||||
|
||||
} else {
|
||||
|
||||
/* start a new run */
|
||||
if (state->count == 1 && (state->LAST < 0xc0)) {
|
||||
if (bytes < 1)
|
||||
if (state->count == 63) {
|
||||
/* this run is full; flush it */
|
||||
if (bytes < 2)
|
||||
return ptr - buf;
|
||||
*ptr++ = 0xff;
|
||||
*ptr++ = state->LAST;
|
||||
bytes--;
|
||||
} else {
|
||||
if (state->count > 0) {
|
||||
if (bytes < 2)
|
||||
return ptr - buf;
|
||||
*ptr++ = 0xc0 | state->count;
|
||||
*ptr++ = state->LAST;
|
||||
bytes -= 2;
|
||||
}
|
||||
bytes -= 2;
|
||||
|
||||
state->count = 0;
|
||||
|
||||
}
|
||||
|
||||
state->LAST = this;
|
||||
state->count = 1;
|
||||
this = state->buffer[state->x];
|
||||
|
||||
state->x++;
|
||||
if (this == state->LAST) {
|
||||
/* extend the current run */
|
||||
state->x++;
|
||||
state->count++;
|
||||
|
||||
} else {
|
||||
/* start a new run */
|
||||
if (state->count == 1 && (state->LAST < 0xc0)) {
|
||||
if (bytes < 1) {
|
||||
return ptr - buf;
|
||||
}
|
||||
*ptr++ = state->LAST;
|
||||
bytes--;
|
||||
} else {
|
||||
if (state->count > 0) {
|
||||
if (bytes < 2) {
|
||||
return ptr - buf;
|
||||
}
|
||||
*ptr++ = 0xc0 | state->count;
|
||||
*ptr++ = state->LAST;
|
||||
bytes -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
state->LAST = this;
|
||||
state->count = 1;
|
||||
|
||||
state->x++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* end of line; flush the current run */
|
||||
if (state->count == 1 && (state->LAST < 0xc0)) {
|
||||
if (bytes < 1)
|
||||
return ptr - buf;
|
||||
*ptr++ = state->LAST;
|
||||
bytes--;
|
||||
} else {
|
||||
if (state->count > 0) {
|
||||
if (bytes < 2)
|
||||
/* end of line; flush the current run */
|
||||
if (state->count == 1 && (state->LAST < 0xc0)) {
|
||||
if (bytes < 1 + padding) {
|
||||
return ptr - buf;
|
||||
*ptr++ = 0xc0 | state->count;
|
||||
}
|
||||
*ptr++ = state->LAST;
|
||||
bytes -= 2;
|
||||
bytes--;
|
||||
} else {
|
||||
if (state->count > 0) {
|
||||
if (bytes < 2 + padding) {
|
||||
return ptr - buf;
|
||||
}
|
||||
*ptr++ = 0xc0 | state->count;
|
||||
*ptr++ = state->LAST;
|
||||
bytes -= 2;
|
||||
}
|
||||
}
|
||||
if (bytes < padding) {
|
||||
return ptr - buf;
|
||||
}
|
||||
/* add the padding */
|
||||
for (i=0;i<padding;i++){
|
||||
*ptr++=0;
|
||||
bytes--;
|
||||
}
|
||||
/* reset for the next color plane. */
|
||||
if (state->x < planes * bytes_per_line) {
|
||||
state->count = 1;
|
||||
state->LAST = state->buffer[state->x];
|
||||
state->x++;
|
||||
}
|
||||
}
|
||||
|
||||
/* read next line */
|
||||
state->state = FETCH;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user