mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 18:26:17 +03:00
backport PIL's PNG/Zip improvements
- add new FASTOCTREE quantizer with alpha support
- make ZIP compress level and type configurable
- support reading/writing PNGs with paletted alpha
source 3637439d51
This commit is contained in:
parent
c60bb09fcd
commit
6537ba19c3
19
PIL/Image.py
19
PIL/Image.py
|
@ -143,11 +143,23 @@ FLOYDSTEINBERG = 3 # default
|
||||||
WEB = 0
|
WEB = 0
|
||||||
ADAPTIVE = 1
|
ADAPTIVE = 1
|
||||||
|
|
||||||
|
MEDIANCUT = 0
|
||||||
|
MAXCOVERAGE = 1
|
||||||
|
FASTOCTREE = 2
|
||||||
|
|
||||||
# categories
|
# categories
|
||||||
NORMAL = 0
|
NORMAL = 0
|
||||||
SEQUENCE = 1
|
SEQUENCE = 1
|
||||||
CONTAINER = 2
|
CONTAINER = 2
|
||||||
|
|
||||||
|
if hasattr(core, 'DEFAULT_STRATEGY'):
|
||||||
|
DEFAULT_STRATEGY = core.DEFAULT_STRATEGY
|
||||||
|
FILTERED = core.FILTERED
|
||||||
|
HUFFMAN_ONLY = core.HUFFMAN_ONLY
|
||||||
|
RLE = core.RLE
|
||||||
|
FIXED = core.FIXED
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# Registries
|
# Registries
|
||||||
|
|
||||||
|
@ -616,8 +628,12 @@ class Image:
|
||||||
self.palette.mode = "RGB"
|
self.palette.mode = "RGB"
|
||||||
self.palette.rawmode = None
|
self.palette.rawmode = None
|
||||||
if "transparency" in self.info:
|
if "transparency" in self.info:
|
||||||
self.im.putpalettealpha(self.info["transparency"], 0)
|
if isinstance(self.info["transparency"], str):
|
||||||
|
self.im.putpalettealphas(self.info["transparency"])
|
||||||
|
else:
|
||||||
|
self.im.putpalettealpha(self.info["transparency"], 0)
|
||||||
self.palette.mode = "RGBA"
|
self.palette.mode = "RGBA"
|
||||||
|
|
||||||
if self.im:
|
if self.im:
|
||||||
return self.im.pixel_access(self.readonly)
|
return self.im.pixel_access(self.readonly)
|
||||||
|
|
||||||
|
@ -714,6 +730,7 @@ class Image:
|
||||||
# methods:
|
# methods:
|
||||||
# 0 = median cut
|
# 0 = median cut
|
||||||
# 1 = maximum coverage
|
# 1 = maximum coverage
|
||||||
|
# 2 = fast octree
|
||||||
|
|
||||||
# NOTE: this functionality will be moved to the extended
|
# NOTE: this functionality will be moved to the extended
|
||||||
# quantizer interface in a later version of PIL.
|
# quantizer interface in a later version of PIL.
|
||||||
|
|
|
@ -70,6 +70,8 @@ _MODES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_simple_palette = re.compile(b'^\xff+\x00+$')
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# Support classes. Suitable for PNG and related formats like MNG etc.
|
# Support classes. Suitable for PNG and related formats like MNG etc.
|
||||||
|
|
||||||
|
@ -251,9 +253,12 @@ class PngStream(ChunkStream):
|
||||||
# transparency
|
# transparency
|
||||||
s = ImageFile._safe_read(self.fp, len)
|
s = ImageFile._safe_read(self.fp, len)
|
||||||
if self.im_mode == "P":
|
if self.im_mode == "P":
|
||||||
i = s.find(b"\0")
|
if _simple_palette.match(s):
|
||||||
if i >= 0:
|
i = s.find(b"\0")
|
||||||
self.im_info["transparency"] = i
|
if i >= 0:
|
||||||
|
self.im_info["transparency"] = i
|
||||||
|
else:
|
||||||
|
self.im_info["transparency"] = s
|
||||||
elif self.im_mode == "L":
|
elif self.im_mode == "L":
|
||||||
self.im_info["transparency"] = i16(s)
|
self.im_info["transparency"] = i16(s)
|
||||||
elif self.im_mode == "RGB":
|
elif self.im_mode == "RGB":
|
||||||
|
@ -513,7 +518,10 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
|
||||||
else:
|
else:
|
||||||
dictionary = b""
|
dictionary = b""
|
||||||
|
|
||||||
im.encoderconfig = ("optimize" in im.encoderinfo, dictionary)
|
im.encoderconfig = ("optimize" in im.encoderinfo,
|
||||||
|
im.encoderinfo.get("compress_level", -1),
|
||||||
|
im.encoderinfo.get("compress_type", -1),
|
||||||
|
dictionary)
|
||||||
|
|
||||||
# get the corresponding PNG mode
|
# get the corresponding PNG mode
|
||||||
try:
|
try:
|
||||||
|
@ -551,6 +559,10 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
|
||||||
chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
|
chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
|
||||||
else:
|
else:
|
||||||
raise IOError("cannot use transparency for this mode")
|
raise IOError("cannot use transparency for this mode")
|
||||||
|
else:
|
||||||
|
if im.mode == "P" and im.im.getpalettemode() == "RGBA":
|
||||||
|
alpha = im.im.getpalette("RGBA", "A")
|
||||||
|
chunk(fp, "tRNS", alpha)
|
||||||
|
|
||||||
if 0:
|
if 0:
|
||||||
# FIXME: to be supported some day
|
# FIXME: to be supported some day
|
||||||
|
|
|
@ -117,6 +117,17 @@ def test_interlace():
|
||||||
|
|
||||||
assert_no_exception(lambda: im.load())
|
assert_no_exception(lambda: im.load())
|
||||||
|
|
||||||
|
def test_load_transparent_p():
|
||||||
|
file = "Tests/images/pil123p.png"
|
||||||
|
im = Image.open(file)
|
||||||
|
|
||||||
|
assert_image(im, "P", (162, 150))
|
||||||
|
im = im.convert("RGBA")
|
||||||
|
assert_image(im, "RGBA", (162, 150))
|
||||||
|
|
||||||
|
# image has 124 uniqe qlpha values
|
||||||
|
assert_equal(len(im.split()[3].getcolors()), 124)
|
||||||
|
|
||||||
def test_load_verify():
|
def test_load_verify():
|
||||||
# Check open/load/verify exception (@PIL150)
|
# Check open/load/verify exception (@PIL150)
|
||||||
|
|
||||||
|
|
|
@ -13,3 +13,10 @@ def test_sanity():
|
||||||
im = im.quantize(palette=lena("P"))
|
im = im.quantize(palette=lena("P"))
|
||||||
assert_image(im, "P", im.size)
|
assert_image(im, "P", im.size)
|
||||||
|
|
||||||
|
def test_octree_quantize():
|
||||||
|
im = lena()
|
||||||
|
|
||||||
|
im = im.quantize(100, Image.FASTOCTREE)
|
||||||
|
assert_image(im, "P", im.size)
|
||||||
|
|
||||||
|
assert len(im.getcolors()) == 100
|
236
_imaging.c
236
_imaging.c
|
@ -65,7 +65,7 @@
|
||||||
* 2005-10-02 fl Added access proxy
|
* 2005-10-02 fl Added access proxy
|
||||||
* 2006-06-18 fl Always draw last point in polyline
|
* 2006-06-18 fl Always draw last point in polyline
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2006 by Secret Labs AB
|
* Copyright (c) 1997-2006 by Secret Labs AB
|
||||||
* Copyright (c) 1995-2006 by Fredrik Lundh
|
* Copyright (c) 1995-2006 by Fredrik Lundh
|
||||||
*
|
*
|
||||||
* See the README file for information on usage and redistribution.
|
* See the README file for information on usage and redistribution.
|
||||||
|
@ -157,7 +157,7 @@ typedef struct {
|
||||||
|
|
||||||
static PyTypeObject PixelAccess_Type;
|
static PyTypeObject PixelAccess_Type;
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
PyImagingNew(Imaging imOut)
|
PyImagingNew(Imaging imOut)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -584,7 +584,7 @@ getink(PyObject* color, Imaging im, char* ink)
|
||||||
/* FACTORIES */
|
/* FACTORIES */
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_fill(PyObject* self, PyObject* args)
|
_fill(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
char* mode;
|
char* mode;
|
||||||
|
@ -592,7 +592,7 @@ _fill(PyObject* self, PyObject* args)
|
||||||
PyObject* color;
|
PyObject* color;
|
||||||
char buffer[4];
|
char buffer[4];
|
||||||
Imaging im;
|
Imaging im;
|
||||||
|
|
||||||
xsize = ysize = 256;
|
xsize = ysize = 256;
|
||||||
color = NULL;
|
color = NULL;
|
||||||
|
|
||||||
|
@ -616,7 +616,7 @@ _fill(PyObject* self, PyObject* args)
|
||||||
return PyImagingNew(im);
|
return PyImagingNew(im);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_new(PyObject* self, PyObject* args)
|
_new(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
char* mode;
|
char* mode;
|
||||||
|
@ -628,7 +628,7 @@ _new(PyObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingNew(mode, xsize, ysize));
|
return PyImagingNew(ImagingNew(mode, xsize, ysize));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_new_array(PyObject* self, PyObject* args)
|
_new_array(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
char* mode;
|
char* mode;
|
||||||
|
@ -640,7 +640,7 @@ _new_array(PyObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingNewArray(mode, xsize, ysize));
|
return PyImagingNew(ImagingNewArray(mode, xsize, ysize));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_new_block(PyObject* self, PyObject* args)
|
_new_block(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
char* mode;
|
char* mode;
|
||||||
|
@ -652,7 +652,7 @@ _new_block(PyObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingNewBlock(mode, xsize, ysize));
|
return PyImagingNew(ImagingNewBlock(mode, xsize, ysize));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_getcount(PyObject* self, PyObject* args)
|
_getcount(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
if (!PyArg_ParseTuple(args, ":getcount"))
|
if (!PyArg_ParseTuple(args, ":getcount"))
|
||||||
|
@ -661,7 +661,7 @@ _getcount(PyObject* self, PyObject* args)
|
||||||
return PyInt_FromLong(ImagingNewCount);
|
return PyInt_FromLong(ImagingNewCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_linear_gradient(PyObject* self, PyObject* args)
|
_linear_gradient(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
char* mode;
|
char* mode;
|
||||||
|
@ -672,7 +672,7 @@ _linear_gradient(PyObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingFillLinearGradient(mode));
|
return PyImagingNew(ImagingFillLinearGradient(mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_radial_gradient(PyObject* self, PyObject* args)
|
_radial_gradient(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
char* mode;
|
char* mode;
|
||||||
|
@ -683,7 +683,7 @@ _radial_gradient(PyObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingFillRadialGradient(mode));
|
return PyImagingNew(ImagingFillRadialGradient(mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_open_ppm(PyObject* self, PyObject* args)
|
_open_ppm(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
char* filename;
|
char* filename;
|
||||||
|
@ -708,13 +708,13 @@ _alpha_composite(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingAlphaComposite(imagep1->image, imagep2->image));
|
return PyImagingNew(ImagingAlphaComposite(imagep1->image, imagep2->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_blend(ImagingObject* self, PyObject* args)
|
_blend(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep1;
|
ImagingObject* imagep1;
|
||||||
ImagingObject* imagep2;
|
ImagingObject* imagep2;
|
||||||
double alpha;
|
double alpha;
|
||||||
|
|
||||||
alpha = 0.5;
|
alpha = 0.5;
|
||||||
if (!PyArg_ParseTuple(args, "O!O!|d",
|
if (!PyArg_ParseTuple(args, "O!O!|d",
|
||||||
&Imaging_Type, &imagep1,
|
&Imaging_Type, &imagep1,
|
||||||
|
@ -730,7 +730,7 @@ _blend(ImagingObject* self, PyObject* args)
|
||||||
/* METHODS */
|
/* METHODS */
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_convert(ImagingObject* self, PyObject* args)
|
_convert(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
char* mode;
|
char* mode;
|
||||||
|
@ -754,7 +754,7 @@ _convert(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingConvert(self->image, mode, paletteimage ? paletteimage->image->palette : NULL, dither));
|
return PyImagingNew(ImagingConvert(self->image, mode, paletteimage ? paletteimage->image->palette : NULL, dither));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_convert2(ImagingObject* self, PyObject* args)
|
_convert2(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep1;
|
ImagingObject* imagep1;
|
||||||
|
@ -771,7 +771,7 @@ _convert2(ImagingObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_convert_matrix(ImagingObject* self, PyObject* args)
|
_convert_matrix(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
char* mode;
|
char* mode;
|
||||||
|
@ -788,7 +788,7 @@ _convert_matrix(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingConvertMatrix(self->image, mode, m));
|
return PyImagingNew(ImagingConvertMatrix(self->image, mode, m));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_copy(ImagingObject* self, PyObject* args)
|
_copy(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
if (!PyArg_ParseTuple(args, ""))
|
if (!PyArg_ParseTuple(args, ""))
|
||||||
|
@ -797,7 +797,7 @@ _copy(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingCopy(self->image));
|
return PyImagingNew(ImagingCopy(self->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_copy2(ImagingObject* self, PyObject* args)
|
_copy2(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep1;
|
ImagingObject* imagep1;
|
||||||
|
@ -814,7 +814,7 @@ _copy2(ImagingObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_crop(ImagingObject* self, PyObject* args)
|
_crop(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int x0, y0, x1, y1;
|
int x0, y0, x1, y1;
|
||||||
|
@ -824,7 +824,7 @@ _crop(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingCrop(self->image, x0, y0, x1, y1));
|
return PyImagingNew(ImagingCrop(self->image, x0, y0, x1, y1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_expand(ImagingObject* self, PyObject* args)
|
_expand(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
|
@ -835,7 +835,7 @@ _expand(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingExpand(self->image, x, y, mode));
|
return PyImagingNew(ImagingExpand(self->image, x, y, mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_filter(ImagingObject* self, PyObject* args)
|
_filter(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
PyObject* imOut;
|
PyObject* imOut;
|
||||||
|
@ -848,7 +848,7 @@ _filter(ImagingObject* self, PyObject* args)
|
||||||
if (!PyArg_ParseTuple(args, "(ii)ffO", &xsize, &ysize,
|
if (!PyArg_ParseTuple(args, "(ii)ffO", &xsize, &ysize,
|
||||||
&divisor, &offset, &kernel))
|
&divisor, &offset, &kernel))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* get user-defined kernel */
|
/* get user-defined kernel */
|
||||||
kerneldata = getlist(kernel, &kernelsize, NULL, TYPE_FLOAT32);
|
kerneldata = getlist(kernel, &kernelsize, NULL, TYPE_FLOAT32);
|
||||||
if (!kerneldata)
|
if (!kerneldata)
|
||||||
|
@ -868,7 +868,7 @@ _filter(ImagingObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_UNSHARPMASK
|
#ifdef WITH_UNSHARPMASK
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_gaussian_blur(ImagingObject* self, PyObject* args)
|
_gaussian_blur(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
Imaging imIn;
|
Imaging imIn;
|
||||||
|
@ -890,7 +890,7 @@ _gaussian_blur(ImagingObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_getpalette(ImagingObject* self, PyObject* args)
|
_getpalette(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
PyObject* palette;
|
PyObject* palette;
|
||||||
|
@ -924,6 +924,17 @@ _getpalette(ImagingObject* self, PyObject* args)
|
||||||
return palette;
|
return palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
_getpalettemode(ImagingObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
if (!self->image->palette) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, no_palette);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyString_FromString(self->image->palette->mode);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
_getxy(PyObject* xy, int* x, int *y)
|
_getxy(PyObject* xy, int* x, int *y)
|
||||||
{
|
{
|
||||||
|
@ -931,7 +942,7 @@ _getxy(PyObject* xy, int* x, int *y)
|
||||||
|
|
||||||
if (!PyTuple_Check(xy) || PyTuple_GET_SIZE(xy) != 2)
|
if (!PyTuple_Check(xy) || PyTuple_GET_SIZE(xy) != 2)
|
||||||
goto badarg;
|
goto badarg;
|
||||||
|
|
||||||
value = PyTuple_GET_ITEM(xy, 0);
|
value = PyTuple_GET_ITEM(xy, 0);
|
||||||
if (PyInt_Check(value))
|
if (PyInt_Check(value))
|
||||||
*x = PyInt_AS_LONG(value);
|
*x = PyInt_AS_LONG(value);
|
||||||
|
@ -965,7 +976,7 @@ _getxy(PyObject* xy, int* x, int *y)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_getpixel(ImagingObject* self, PyObject* args)
|
_getpixel(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
PyObject* xy;
|
PyObject* xy;
|
||||||
|
@ -1065,7 +1076,7 @@ _histogram(ImagingObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_MODEFILTER
|
#ifdef WITH_MODEFILTER
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_modefilter(ImagingObject* self, PyObject* args)
|
_modefilter(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
|
@ -1076,7 +1087,7 @@ _modefilter(ImagingObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_offset(ImagingObject* self, PyObject* args)
|
_offset(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int xoffset, yoffset;
|
int xoffset, yoffset;
|
||||||
|
@ -1086,7 +1097,7 @@ _offset(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingOffset(self->image, xoffset, yoffset));
|
return PyImagingNew(ImagingOffset(self->image, xoffset, yoffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_paste(ImagingObject* self, PyObject* args)
|
_paste(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
@ -1251,7 +1262,7 @@ _putdata(ImagingObject* self, PyObject* args)
|
||||||
x = image->xsize;
|
x = image->xsize;
|
||||||
memcpy(image->image8[y], p+i, x);
|
memcpy(image->image8[y], p+i, x);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* Scaled and clipped string data */
|
/* Scaled and clipped string data */
|
||||||
for (i = x = y = 0; i < n; i++) {
|
for (i = x = y = 0; i < n; i++) {
|
||||||
image->image8[y][x] = CLIP((int) (p[i] * scale + offset));
|
image->image8[y][x] = CLIP((int) (p[i] * scale + offset));
|
||||||
|
@ -1355,7 +1366,7 @@ _putdata(ImagingObject* self, PyObject* args)
|
||||||
#ifdef WITH_QUANTIZE
|
#ifdef WITH_QUANTIZE
|
||||||
|
|
||||||
#include "Quant.h"
|
#include "Quant.h"
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_quantize(ImagingObject* self, PyObject* args)
|
_quantize(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int colours = 256;
|
int colours = 256;
|
||||||
|
@ -1375,7 +1386,7 @@ _quantize(ImagingObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_putpalette(ImagingObject* self, PyObject* args)
|
_putpalette(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingShuffler unpack;
|
ImagingShuffler unpack;
|
||||||
|
@ -1410,7 +1421,7 @@ _putpalette(ImagingObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_putpalettealpha(ImagingObject* self, PyObject* args)
|
_putpalettealpha(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
@ -1435,7 +1446,35 @@ _putpalettealpha(ImagingObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
|
_putpalettealphas(ImagingObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
UINT8 *values;
|
||||||
|
int length;
|
||||||
|
if (!PyArg_ParseTuple(args, "s#", &values, &length))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!self->image->palette) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, no_palette);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > 256) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, outside_palette);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(self->image->palette->mode, "RGBA");
|
||||||
|
for (i=0; i<length; i++) {
|
||||||
|
self->image->palette->palette[i*4+3] = (UINT8) values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
_putpixel(ImagingObject* self, PyObject* args)
|
_putpixel(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
Imaging im;
|
Imaging im;
|
||||||
|
@ -1447,7 +1486,7 @@ _putpixel(ImagingObject* self, PyObject* args)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
im = self->image;
|
im = self->image;
|
||||||
|
|
||||||
if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
|
if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
|
||||||
PyErr_SetString(PyExc_IndexError, outside_image);
|
PyErr_SetString(PyExc_IndexError, outside_image);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1464,7 +1503,7 @@ _putpixel(ImagingObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_RANKFILTER
|
#ifdef WITH_RANKFILTER
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_rankfilter(ImagingObject* self, PyObject* args)
|
_rankfilter(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int size, rank;
|
int size, rank;
|
||||||
|
@ -1475,7 +1514,7 @@ _rankfilter(ImagingObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_resize(ImagingObject* self, PyObject* args)
|
_resize(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
Imaging imIn;
|
Imaging imIn;
|
||||||
|
@ -1491,16 +1530,16 @@ _resize(ImagingObject* self, PyObject* args)
|
||||||
imOut = ImagingNew(imIn->mode, xsize, ysize);
|
imOut = ImagingNew(imIn->mode, xsize, ysize);
|
||||||
if (imOut)
|
if (imOut)
|
||||||
(void) ImagingResize(imOut, imIn, filter);
|
(void) ImagingResize(imOut, imIn, filter);
|
||||||
|
|
||||||
return PyImagingNew(imOut);
|
return PyImagingNew(imOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_rotate(ImagingObject* self, PyObject* args)
|
_rotate(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
Imaging imOut;
|
Imaging imOut;
|
||||||
Imaging imIn;
|
Imaging imIn;
|
||||||
|
|
||||||
double theta;
|
double theta;
|
||||||
int filter = IMAGING_TRANSFORM_NEAREST;
|
int filter = IMAGING_TRANSFORM_NEAREST;
|
||||||
if (!PyArg_ParseTuple(args, "d|i", &theta, &filter))
|
if (!PyArg_ParseTuple(args, "d|i", &theta, &filter))
|
||||||
|
@ -1546,7 +1585,7 @@ _rotate(ImagingObject* self, PyObject* args)
|
||||||
#define IS_RGB(mode)\
|
#define IS_RGB(mode)\
|
||||||
(!strcmp(mode, "RGB") || !strcmp(mode, "RGBA") || !strcmp(mode, "RGBX"))
|
(!strcmp(mode, "RGB") || !strcmp(mode, "RGBA") || !strcmp(mode, "RGBX"))
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
im_setmode(ImagingObject* self, PyObject* args)
|
im_setmode(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
/* attempt to modify the mode of an image in place */
|
/* attempt to modify the mode of an image in place */
|
||||||
|
@ -1584,7 +1623,7 @@ im_setmode(ImagingObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_stretch(ImagingObject* self, PyObject* args)
|
_stretch(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
Imaging imIn;
|
Imaging imIn;
|
||||||
|
@ -1601,7 +1640,7 @@ _stretch(ImagingObject* self, PyObject* args)
|
||||||
/* two-pass resize: minimize size of intermediate image */
|
/* two-pass resize: minimize size of intermediate image */
|
||||||
if (imIn->xsize * ysize < xsize * imIn->ysize)
|
if (imIn->xsize * ysize < xsize * imIn->ysize)
|
||||||
imTemp = ImagingNew(imIn->mode, imIn->xsize, ysize);
|
imTemp = ImagingNew(imIn->mode, imIn->xsize, ysize);
|
||||||
else
|
else
|
||||||
imTemp = ImagingNew(imIn->mode, xsize, imIn->ysize);
|
imTemp = ImagingNew(imIn->mode, xsize, imIn->ysize);
|
||||||
if (!imTemp)
|
if (!imTemp)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1626,11 +1665,11 @@ _stretch(ImagingObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagingDelete(imTemp);
|
ImagingDelete(imTemp);
|
||||||
|
|
||||||
return PyImagingNew(imOut);
|
return PyImagingNew(imOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_transform2(ImagingObject* self, PyObject* args)
|
_transform2(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
static const char* wrong_number = "wrong number of matrix entries";
|
static const char* wrong_number = "wrong number of matrix entries";
|
||||||
|
@ -1705,7 +1744,7 @@ _transform2(ImagingObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_transpose(ImagingObject* self, PyObject* args)
|
_transpose(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
Imaging imIn;
|
Imaging imIn;
|
||||||
|
@ -1716,7 +1755,7 @@ _transpose(ImagingObject* self, PyObject* args)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
imIn = self->image;
|
imIn = self->image;
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case 0: /* flip left right */
|
case 0: /* flip left right */
|
||||||
case 1: /* flip top bottom */
|
case 1: /* flip top bottom */
|
||||||
|
@ -1755,7 +1794,7 @@ _transpose(ImagingObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_UNSHARPMASK
|
#ifdef WITH_UNSHARPMASK
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_unsharp_mask(ImagingObject* self, PyObject* args)
|
_unsharp_mask(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
Imaging imIn;
|
Imaging imIn;
|
||||||
|
@ -1781,13 +1820,13 @@ _unsharp_mask(ImagingObject* self, PyObject* args)
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_isblock(ImagingObject* self, PyObject* args)
|
_isblock(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
return PyInt_FromLong((long) self->image->block);
|
return PyInt_FromLong((long) self->image->block);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_getbbox(ImagingObject* self, PyObject* args)
|
_getbbox(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int bbox[4];
|
int bbox[4];
|
||||||
|
@ -1799,7 +1838,7 @@ _getbbox(ImagingObject* self, PyObject* args)
|
||||||
return Py_BuildValue("iiii", bbox[0], bbox[1], bbox[2], bbox[3]);
|
return Py_BuildValue("iiii", bbox[0], bbox[1], bbox[2], bbox[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_getcolors(ImagingObject* self, PyObject* args)
|
_getcolors(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingColorItem* items;
|
ImagingColorItem* items;
|
||||||
|
@ -1833,7 +1872,7 @@ _getcolors(ImagingObject* self, PyObject* args)
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_getextrema(ImagingObject* self, PyObject* args)
|
_getextrema(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
|
@ -1842,7 +1881,7 @@ _getextrema(ImagingObject* self, PyObject* args)
|
||||||
FLOAT32 f[2];
|
FLOAT32 f[2];
|
||||||
} extrema;
|
} extrema;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
status = ImagingGetExtrema(self->image, &extrema);
|
status = ImagingGetExtrema(self->image, &extrema);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1861,7 +1900,7 @@ _getextrema(ImagingObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_getprojection(ImagingObject* self, PyObject* args)
|
_getprojection(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
unsigned char* xprofile;
|
unsigned char* xprofile;
|
||||||
|
@ -1891,7 +1930,7 @@ _getprojection(ImagingObject* self, PyObject* args)
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_getband(ImagingObject* self, PyObject* args)
|
_getband(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int band;
|
int band;
|
||||||
|
@ -1902,7 +1941,7 @@ _getband(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingGetBand(self->image, band));
|
return PyImagingNew(ImagingGetBand(self->image, band));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_fillband(ImagingObject* self, PyObject* args)
|
_fillband(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int band;
|
int band;
|
||||||
|
@ -1913,12 +1952,12 @@ _fillband(ImagingObject* self, PyObject* args)
|
||||||
|
|
||||||
if (!ImagingFillBand(self->image, band, color))
|
if (!ImagingFillBand(self->image, band, color))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_putband(ImagingObject* self, PyObject* args)
|
_putband(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -1939,13 +1978,13 @@ _putband(ImagingObject* self, PyObject* args)
|
||||||
|
|
||||||
#ifdef WITH_IMAGECHOPS
|
#ifdef WITH_IMAGECHOPS
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_invert(ImagingObject* self, PyObject* args)
|
_chop_invert(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
return PyImagingNew(ImagingNegative(self->image));
|
return PyImagingNew(ImagingNegative(self->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_lighter(ImagingObject* self, PyObject* args)
|
_chop_lighter(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -1956,7 +1995,7 @@ _chop_lighter(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingChopLighter(self->image, imagep->image));
|
return PyImagingNew(ImagingChopLighter(self->image, imagep->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_darker(ImagingObject* self, PyObject* args)
|
_chop_darker(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -1967,7 +2006,7 @@ _chop_darker(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingChopDarker(self->image, imagep->image));
|
return PyImagingNew(ImagingChopDarker(self->image, imagep->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_difference(ImagingObject* self, PyObject* args)
|
_chop_difference(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -1978,7 +2017,7 @@ _chop_difference(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingChopDifference(self->image, imagep->image));
|
return PyImagingNew(ImagingChopDifference(self->image, imagep->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_multiply(ImagingObject* self, PyObject* args)
|
_chop_multiply(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -1989,7 +2028,7 @@ _chop_multiply(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingChopMultiply(self->image, imagep->image));
|
return PyImagingNew(ImagingChopMultiply(self->image, imagep->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_screen(ImagingObject* self, PyObject* args)
|
_chop_screen(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -2000,7 +2039,7 @@ _chop_screen(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingChopScreen(self->image, imagep->image));
|
return PyImagingNew(ImagingChopScreen(self->image, imagep->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_add(ImagingObject* self, PyObject* args)
|
_chop_add(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -2018,7 +2057,7 @@ _chop_add(ImagingObject* self, PyObject* args)
|
||||||
scale, offset));
|
scale, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_subtract(ImagingObject* self, PyObject* args)
|
_chop_subtract(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -2036,7 +2075,7 @@ _chop_subtract(ImagingObject* self, PyObject* args)
|
||||||
scale, offset));
|
scale, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_and(ImagingObject* self, PyObject* args)
|
_chop_and(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -2047,7 +2086,7 @@ _chop_and(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingChopAnd(self->image, imagep->image));
|
return PyImagingNew(ImagingChopAnd(self->image, imagep->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_or(ImagingObject* self, PyObject* args)
|
_chop_or(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -2058,7 +2097,7 @@ _chop_or(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingChopOr(self->image, imagep->image));
|
return PyImagingNew(ImagingChopOr(self->image, imagep->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_xor(ImagingObject* self, PyObject* args)
|
_chop_xor(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -2069,7 +2108,7 @@ _chop_xor(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingChopXor(self->image, imagep->image));
|
return PyImagingNew(ImagingChopXor(self->image, imagep->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_add_modulo(ImagingObject* self, PyObject* args)
|
_chop_add_modulo(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -2080,7 +2119,7 @@ _chop_add_modulo(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingChopAddModulo(self->image, imagep->image));
|
return PyImagingNew(ImagingChopAddModulo(self->image, imagep->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_chop_subtract_modulo(ImagingObject* self, PyObject* args)
|
_chop_subtract_modulo(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingObject* imagep;
|
ImagingObject* imagep;
|
||||||
|
@ -2274,7 +2313,7 @@ _draw_dealloc(ImagingDrawObject* self)
|
||||||
|
|
||||||
extern int PyPath_Flatten(PyObject* data, double **xy);
|
extern int PyPath_Flatten(PyObject* data, double **xy);
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_ink(ImagingDrawObject* self, PyObject* args)
|
_draw_ink(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
INT32 ink = 0;
|
INT32 ink = 0;
|
||||||
|
@ -2289,7 +2328,7 @@ _draw_ink(ImagingDrawObject* self, PyObject* args)
|
||||||
return PyInt_FromLong((int) ink);
|
return PyInt_FromLong((int) ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_arc(ImagingDrawObject* self, PyObject* args)
|
_draw_arc(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int x0, y0, x1, y1;
|
int x0, y0, x1, y1;
|
||||||
|
@ -2309,7 +2348,7 @@ _draw_arc(ImagingDrawObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_bitmap(ImagingDrawObject* self, PyObject* args)
|
_draw_bitmap(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
double *xy;
|
double *xy;
|
||||||
|
@ -2346,7 +2385,7 @@ _draw_bitmap(ImagingDrawObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_chord(ImagingDrawObject* self, PyObject* args)
|
_draw_chord(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int x0, y0, x1, y1;
|
int x0, y0, x1, y1;
|
||||||
|
@ -2364,7 +2403,7 @@ _draw_chord(ImagingDrawObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_ellipse(ImagingDrawObject* self, PyObject* args)
|
_draw_ellipse(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
double* xy;
|
double* xy;
|
||||||
|
@ -2391,7 +2430,7 @@ _draw_ellipse(ImagingDrawObject* self, PyObject* args)
|
||||||
self->image->image, (int) xy[0], (int) xy[1], (int) xy[2], (int) xy[3],
|
self->image->image, (int) xy[0], (int) xy[1], (int) xy[2], (int) xy[3],
|
||||||
&ink, fill, self->blend
|
&ink, fill, self->blend
|
||||||
);
|
);
|
||||||
|
|
||||||
free(xy);
|
free(xy);
|
||||||
|
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
|
@ -2401,7 +2440,7 @@ _draw_ellipse(ImagingDrawObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_line(ImagingDrawObject* self, PyObject* args)
|
_draw_line(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int x0, y0, x1, y1;
|
int x0, y0, x1, y1;
|
||||||
|
@ -2417,7 +2456,7 @@ _draw_line(ImagingDrawObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_lines(ImagingDrawObject* self, PyObject* args)
|
_draw_lines(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
double *xy;
|
double *xy;
|
||||||
|
@ -2470,7 +2509,7 @@ _draw_lines(ImagingDrawObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_point(ImagingDrawObject* self, PyObject* args)
|
_draw_point(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
|
@ -2485,7 +2524,7 @@ _draw_point(ImagingDrawObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_points(ImagingDrawObject* self, PyObject* args)
|
_draw_points(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
double *xy;
|
double *xy;
|
||||||
|
@ -2520,7 +2559,7 @@ _draw_points(ImagingDrawObject* self, PyObject* args)
|
||||||
/* from outline.c */
|
/* from outline.c */
|
||||||
extern ImagingOutline PyOutline_AsOutline(PyObject* outline);
|
extern ImagingOutline PyOutline_AsOutline(PyObject* outline);
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_outline(ImagingDrawObject* self, PyObject* args)
|
_draw_outline(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingOutline outline;
|
ImagingOutline outline;
|
||||||
|
@ -2547,7 +2586,7 @@ _draw_outline(ImagingDrawObject* self, PyObject* args)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_pieslice(ImagingDrawObject* self, PyObject* args)
|
_draw_pieslice(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int x0, y0, x1, y1;
|
int x0, y0, x1, y1;
|
||||||
|
@ -2565,7 +2604,7 @@ _draw_pieslice(ImagingDrawObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_polygon(ImagingDrawObject* self, PyObject* args)
|
_draw_polygon(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
double *xy;
|
double *xy;
|
||||||
|
@ -2611,7 +2650,7 @@ _draw_polygon(ImagingDrawObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_draw_rectangle(ImagingDrawObject* self, PyObject* args)
|
_draw_rectangle(ImagingDrawObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
double* xy;
|
double* xy;
|
||||||
|
@ -2638,7 +2677,7 @@ _draw_rectangle(ImagingDrawObject* self, PyObject* args)
|
||||||
self->image->image, (int) xy[0], (int) xy[1],
|
self->image->image, (int) xy[0], (int) xy[1],
|
||||||
(int) xy[2], (int) xy[3], &ink, fill, self->blend
|
(int) xy[2], (int) xy[3], &ink, fill, self->blend
|
||||||
);
|
);
|
||||||
|
|
||||||
free(xy);
|
free(xy);
|
||||||
|
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
|
@ -2749,7 +2788,7 @@ pixel_access_setitem(PixelAccessObject *self, PyObject *xy, PyObject *color)
|
||||||
|
|
||||||
#ifdef WITH_EFFECTS
|
#ifdef WITH_EFFECTS
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_effect_mandelbrot(ImagingObject* self, PyObject* args)
|
_effect_mandelbrot(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int xsize = 512;
|
int xsize = 512;
|
||||||
|
@ -2768,7 +2807,7 @@ _effect_mandelbrot(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingEffectMandelbrot(xsize, ysize, extent, quality));
|
return PyImagingNew(ImagingEffectMandelbrot(xsize, ysize, extent, quality));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_effect_noise(ImagingObject* self, PyObject* args)
|
_effect_noise(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int xsize, ysize;
|
int xsize, ysize;
|
||||||
|
@ -2779,7 +2818,7 @@ _effect_noise(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingEffectNoise(xsize, ysize, sigma));
|
return PyImagingNew(ImagingEffectNoise(xsize, ysize, sigma));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_effect_spread(ImagingObject* self, PyObject* args)
|
_effect_spread(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int dist;
|
int dist;
|
||||||
|
@ -2796,7 +2835,7 @@ _effect_spread(ImagingObject* self, PyObject* args)
|
||||||
/* UTILITIES */
|
/* UTILITIES */
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_crc32(PyObject* self, PyObject* args)
|
_crc32(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
unsigned char* buffer;
|
unsigned char* buffer;
|
||||||
|
@ -2817,7 +2856,7 @@ _crc32(PyObject* self, PyObject* args)
|
||||||
return Py_BuildValue("ii", (crc >> 16) & 0xFFFF, crc & 0xFFFF);
|
return Py_BuildValue("ii", (crc >> 16) & 0xFFFF, crc & 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_getcodecstatus(PyObject* self, PyObject* args)
|
_getcodecstatus(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
@ -2851,7 +2890,7 @@ _getcodecstatus(PyObject* self, PyObject* args)
|
||||||
|
|
||||||
#ifdef WITH_DEBUG
|
#ifdef WITH_DEBUG
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_save_ppm(ImagingObject* self, PyObject* args)
|
_save_ppm(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
char* filename;
|
char* filename;
|
||||||
|
@ -2925,10 +2964,12 @@ static struct PyMethodDef methods[] = {
|
||||||
{"fillband", (PyCFunction)_fillband, 1},
|
{"fillband", (PyCFunction)_fillband, 1},
|
||||||
|
|
||||||
{"setmode", (PyCFunction)im_setmode, 1},
|
{"setmode", (PyCFunction)im_setmode, 1},
|
||||||
|
|
||||||
{"getpalette", (PyCFunction)_getpalette, 1},
|
{"getpalette", (PyCFunction)_getpalette, 1},
|
||||||
|
{"getpalettemode", (PyCFunction)_getpalettemode, 1},
|
||||||
{"putpalette", (PyCFunction)_putpalette, 1},
|
{"putpalette", (PyCFunction)_putpalette, 1},
|
||||||
{"putpalettealpha", (PyCFunction)_putpalettealpha, 1},
|
{"putpalettealpha", (PyCFunction)_putpalettealpha, 1},
|
||||||
|
{"putpalettealphas", (PyCFunction)_putpalettealphas, 1},
|
||||||
|
|
||||||
#ifdef WITH_IMAGECHOPS
|
#ifdef WITH_IMAGECHOPS
|
||||||
/* Channel operations (ImageChops) */
|
/* Channel operations (ImageChops) */
|
||||||
|
@ -3324,7 +3365,7 @@ static PyMethodDef functions[] = {
|
||||||
#ifdef WITH_IMAGEPATH
|
#ifdef WITH_IMAGEPATH
|
||||||
{"path", (PyCFunction)PyPath_Create, 1},
|
{"path", (PyCFunction)PyPath_Create, 1},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Experimental arrow graphics stuff */
|
/* Experimental arrow graphics stuff */
|
||||||
#ifdef WITH_ARROW
|
#ifdef WITH_ARROW
|
||||||
{"outline", (PyCFunction)PyOutline_Create, 1},
|
{"outline", (PyCFunction)PyOutline_Create, 1},
|
||||||
|
@ -3361,6 +3402,13 @@ setup_module(PyObject* m) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
|
#include "zlib.h"
|
||||||
|
/* zip encoding strategies */
|
||||||
|
PyModule_AddIntConstant(m, "DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY);
|
||||||
|
PyModule_AddIntConstant(m, "FILTERED", Z_FILTERED);
|
||||||
|
PyModule_AddIntConstant(m, "HUFFMAN_ONLY", Z_HUFFMAN_ONLY);
|
||||||
|
PyModule_AddIntConstant(m, "RLE", Z_RLE);
|
||||||
|
PyModule_AddIntConstant(m, "FIXED", Z_FIXED);
|
||||||
{
|
{
|
||||||
extern const char* ImagingZipVersion(void);
|
extern const char* ImagingZipVersion(void);
|
||||||
PyDict_SetItemString(d, "zlib_version", PyUnicode_FromString(ImagingZipVersion()));
|
PyDict_SetItemString(d, "zlib_version", PyUnicode_FromString(ImagingZipVersion()));
|
||||||
|
|
16
encode.c
16
encode.c
|
@ -445,10 +445,14 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
|
||||||
char* mode;
|
char* mode;
|
||||||
char* rawmode;
|
char* rawmode;
|
||||||
int optimize = 0;
|
int optimize = 0;
|
||||||
|
int compress_level = -1;
|
||||||
|
int compress_type = -1;
|
||||||
char* dictionary = NULL;
|
char* dictionary = NULL;
|
||||||
int dictionary_size = 0;
|
int dictionary_size = 0;
|
||||||
if (!PyArg_ParseTuple(args, "ss|i"PY_ARG_BYTES_LENGTH, &mode, &rawmode,
|
if (!PyArg_ParseTuple(args, "ss|iii"PY_ARG_BYTES_LENGTH, &mode, &rawmode,
|
||||||
&optimize, &dictionary, &dictionary_size))
|
&optimize,
|
||||||
|
&compress_level, &compress_type,
|
||||||
|
&dictionary, &dictionary_size))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Copy to avoid referencing Python's memory, but there's no mechanism to
|
/* Copy to avoid referencing Python's memory, but there's no mechanism to
|
||||||
|
@ -477,6 +481,8 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
|
||||||
((ZIPSTATE*)encoder->state.context)->mode = ZIP_PNG_PALETTE;
|
((ZIPSTATE*)encoder->state.context)->mode = ZIP_PNG_PALETTE;
|
||||||
|
|
||||||
((ZIPSTATE*)encoder->state.context)->optimize = optimize;
|
((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 = dictionary;
|
||||||
((ZIPSTATE*)encoder->state.context)->dictionary_size = dictionary_size;
|
((ZIPSTATE*)encoder->state.context)->dictionary_size = dictionary_size;
|
||||||
|
|
||||||
|
@ -512,16 +518,16 @@ static unsigned int** get_qtables_arrays(PyObject* qtables) {
|
||||||
PyObject* table_data;
|
PyObject* table_data;
|
||||||
int i, j, num_tables;
|
int i, j, num_tables;
|
||||||
unsigned int **qarrays;
|
unsigned int **qarrays;
|
||||||
|
|
||||||
if (qtables == Py_None) {
|
if (qtables == Py_None) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PySequence_Check(qtables)) {
|
if (!PySequence_Check(qtables)) {
|
||||||
PyErr_SetString(PyExc_ValueError, "Invalid quantization tables");
|
PyErr_SetString(PyExc_ValueError, "Invalid quantization tables");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tables = PySequence_Fast(qtables, "expected a sequence");
|
tables = PySequence_Fast(qtables, "expected a sequence");
|
||||||
num_tables = PySequence_Size(qtables);
|
num_tables = PySequence_Size(qtables);
|
||||||
if (num_tables < 2 || num_tables > NUM_QUANT_TBLS) {
|
if (num_tables < 2 || num_tables > NUM_QUANT_TBLS) {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "Quant.h"
|
#include "Quant.h"
|
||||||
|
#include "QuantOctree.h"
|
||||||
|
|
||||||
#include "QuantDefines.h"
|
#include "QuantDefines.h"
|
||||||
#include "QuantHash.h"
|
#include "QuantHash.h"
|
||||||
|
@ -1485,6 +1486,8 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
|
||||||
int result;
|
int result;
|
||||||
unsigned long* newData;
|
unsigned long* newData;
|
||||||
Imaging imOut;
|
Imaging imOut;
|
||||||
|
int withAlpha = 0;
|
||||||
|
ImagingSectionCookie cookie;
|
||||||
|
|
||||||
if (!im)
|
if (!im)
|
||||||
return ImagingError_ModeError();
|
return ImagingError_ModeError();
|
||||||
|
@ -1494,9 +1497,13 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
|
||||||
return (Imaging) ImagingError_ValueError("bad number of colors");
|
return (Imaging) ImagingError_ValueError("bad number of colors");
|
||||||
|
|
||||||
if (strcmp(im->mode, "L") != 0 && strcmp(im->mode, "P") != 0 &&
|
if (strcmp(im->mode, "L") != 0 && strcmp(im->mode, "P") != 0 &&
|
||||||
strcmp(im->mode, "RGB"))
|
strcmp(im->mode, "RGB") != 0 && strcmp(im->mode, "RGBA") !=0)
|
||||||
return ImagingError_ModeError();
|
return ImagingError_ModeError();
|
||||||
|
|
||||||
|
/* only octree supports RGBA */
|
||||||
|
if (!strcmp(im->mode, "RGBA") && mode != 2)
|
||||||
|
return ImagingError_ModeError();
|
||||||
|
|
||||||
p = malloc(sizeof(Pixel) * im->xsize * im->ysize);
|
p = malloc(sizeof(Pixel) * im->xsize * im->ysize);
|
||||||
if (!p)
|
if (!p)
|
||||||
return ImagingError_MemoryError();
|
return ImagingError_MemoryError();
|
||||||
|
@ -1529,7 +1536,7 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
|
||||||
p[i].c.b = pp[v*4+2];
|
p[i].c.b = pp[v*4+2];
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!strcmp(im->mode, "RGB")) {
|
} else if (!strcmp(im->mode, "RGB") || !strcmp(im->mode, "RGBA")) {
|
||||||
/* true colour */
|
/* true colour */
|
||||||
|
|
||||||
for (i = y = 0; y < im->ysize; y++)
|
for (i = y = 0; y < im->ysize; y++)
|
||||||
|
@ -1541,6 +1548,8 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
|
||||||
return (Imaging) ImagingError_ValueError("internal error");
|
return (Imaging) ImagingError_ValueError("internal error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImagingSectionEnter(&cookie);
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 0:
|
case 0:
|
||||||
/* median cut */
|
/* median cut */
|
||||||
|
@ -1566,16 +1575,31 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
|
||||||
kmeans
|
kmeans
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!strcmp(im->mode, "RGBA")) {
|
||||||
|
withAlpha = 1;
|
||||||
|
}
|
||||||
|
result = quantize_octree(
|
||||||
|
p,
|
||||||
|
im->xsize*im->ysize,
|
||||||
|
colors,
|
||||||
|
&palette,
|
||||||
|
&paletteLength,
|
||||||
|
&newData,
|
||||||
|
withAlpha
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
result = 0;
|
result = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(p);
|
free(p);
|
||||||
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
|
||||||
imOut = ImagingNew("P", im->xsize, im->ysize);
|
imOut = ImagingNew("P", im->xsize, im->ysize);
|
||||||
|
ImagingSectionEnter(&cookie);
|
||||||
|
|
||||||
for (i = y = 0; y < im->ysize; y++)
|
for (i = y = 0; y < im->ysize; y++)
|
||||||
for (x=0; x < im->xsize; x++)
|
for (x=0; x < im->xsize; x++)
|
||||||
|
@ -1589,7 +1613,11 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
|
||||||
*pp++ = palette[i].c.r;
|
*pp++ = palette[i].c.r;
|
||||||
*pp++ = palette[i].c.g;
|
*pp++ = palette[i].c.g;
|
||||||
*pp++ = palette[i].c.b;
|
*pp++ = palette[i].c.b;
|
||||||
*pp++ = 255;
|
if (withAlpha) {
|
||||||
|
*pp++ = palette[i].c.a;
|
||||||
|
} else {
|
||||||
|
*pp++ = 255;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (; i < 256; i++) {
|
for (; i < 256; i++) {
|
||||||
*pp++ = 0;
|
*pp++ = 0;
|
||||||
|
@ -1598,7 +1626,12 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
|
||||||
*pp++ = 255;
|
*pp++ = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (withAlpha) {
|
||||||
|
strcpy(imOut->palette->mode, "RGBA");
|
||||||
|
}
|
||||||
|
|
||||||
free(palette);
|
free(palette);
|
||||||
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
return imOut;
|
return imOut;
|
||||||
|
|
||||||
|
|
454
libImaging/QuantOctree.c
Normal file
454
libImaging/QuantOctree.c
Normal file
|
@ -0,0 +1,454 @@
|
||||||
|
/* Copyright (c) 2010 Oliver Tonnhofer <olt@bogosoft.com>, Omniscale
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
// This file implements a variation of the octree color quantization algorithm.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Quant.h"
|
||||||
|
|
||||||
|
typedef struct _ColorBucket{
|
||||||
|
/* contains palette index when used for look up cube */
|
||||||
|
unsigned long count;
|
||||||
|
unsigned long r;
|
||||||
|
unsigned long g;
|
||||||
|
unsigned long b;
|
||||||
|
unsigned long a;
|
||||||
|
} *ColorBucket;
|
||||||
|
|
||||||
|
typedef struct _ColorCube{
|
||||||
|
unsigned int rBits, gBits, bBits, aBits;
|
||||||
|
unsigned int rWidth, gWidth, bWidth, aWidth;
|
||||||
|
unsigned int rOffset, gOffset, bOffset, aOffset;
|
||||||
|
|
||||||
|
long size;
|
||||||
|
ColorBucket buckets;
|
||||||
|
} *ColorCube;
|
||||||
|
|
||||||
|
#define MAX(a, b) (a)>(b) ? (a) : (b)
|
||||||
|
|
||||||
|
static ColorCube
|
||||||
|
new_color_cube(int r, int g, int b, int a) {
|
||||||
|
ColorCube cube;
|
||||||
|
|
||||||
|
cube = malloc(sizeof(struct _ColorCube));
|
||||||
|
if (!cube) return NULL;
|
||||||
|
|
||||||
|
cube->rBits = MAX(r, 0);
|
||||||
|
cube->gBits = MAX(g, 0);
|
||||||
|
cube->bBits = MAX(b, 0);
|
||||||
|
cube->aBits = MAX(a, 0);
|
||||||
|
|
||||||
|
/* the width of the cube for each dimension */
|
||||||
|
cube->rWidth = 1<<cube->rBits;
|
||||||
|
cube->gWidth = 1<<cube->gBits;
|
||||||
|
cube->bWidth = 1<<cube->bBits;
|
||||||
|
cube->aWidth = 1<<cube->aBits;
|
||||||
|
|
||||||
|
/* the offsets of each color */
|
||||||
|
|
||||||
|
cube->rOffset = cube->gBits + cube->bBits + cube->aBits;
|
||||||
|
cube->gOffset = cube->bBits + cube->aBits;
|
||||||
|
cube->bOffset = cube->aBits;
|
||||||
|
cube->aOffset = 0;
|
||||||
|
|
||||||
|
/* the number of color buckets */
|
||||||
|
cube->size = cube->rWidth * cube->gWidth * cube->bWidth * cube->aWidth;
|
||||||
|
cube->buckets = calloc(cube->size, sizeof(struct _ColorBucket));
|
||||||
|
|
||||||
|
if (!cube->buckets) {
|
||||||
|
free(cube);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return cube;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_color_cube(ColorCube cube) {
|
||||||
|
if (cube != NULL) {
|
||||||
|
free(cube->buckets);
|
||||||
|
free(cube);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
color_bucket_offset_pos(const ColorCube cube,
|
||||||
|
unsigned int r, unsigned int g, unsigned int b, unsigned int a)
|
||||||
|
{
|
||||||
|
return r<<cube->rOffset | g<<cube->gOffset | b<<cube->bOffset | a<<cube->aOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
color_bucket_offset(const ColorCube cube, const Pixel *p) {
|
||||||
|
unsigned int r = p->c.r>>(8-cube->rBits);
|
||||||
|
unsigned int g = p->c.g>>(8-cube->gBits);
|
||||||
|
unsigned int b = p->c.b>>(8-cube->bBits);
|
||||||
|
unsigned int a = p->c.a>>(8-cube->aBits);
|
||||||
|
return color_bucket_offset_pos(cube, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ColorBucket
|
||||||
|
color_bucket_from_cube(const ColorCube cube, const Pixel *p) {
|
||||||
|
unsigned int offset = color_bucket_offset(cube, p);
|
||||||
|
return &cube->buckets[offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_color_to_color_cube(const ColorCube cube, const Pixel *p) {
|
||||||
|
ColorBucket bucket = color_bucket_from_cube(cube, p);
|
||||||
|
bucket->count += 1;
|
||||||
|
bucket->r += p->c.r;
|
||||||
|
bucket->g += p->c.g;
|
||||||
|
bucket->b += p->c.b;
|
||||||
|
bucket->a += p->c.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
count_used_color_buckets(const ColorCube cube) {
|
||||||
|
long usedBuckets = 0;
|
||||||
|
long i;
|
||||||
|
for (i=0; i < cube->size; i++) {
|
||||||
|
if (cube->buckets[i].count > 0) {
|
||||||
|
usedBuckets += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return usedBuckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avg_color_from_color_bucket(const ColorBucket bucket, Pixel *dst) {
|
||||||
|
float count = bucket->count;
|
||||||
|
dst->c.r = (int)(bucket->r / count);
|
||||||
|
dst->c.g = (int)(bucket->g / count);
|
||||||
|
dst->c.b = (int)(bucket->b / count);
|
||||||
|
dst->c.a = (int)(bucket->a / count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_bucket_count(const ColorBucket a, const ColorBucket b) {
|
||||||
|
return b->count - a->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ColorBucket
|
||||||
|
create_sorted_color_palette(const ColorCube cube) {
|
||||||
|
ColorBucket buckets;
|
||||||
|
buckets = malloc(sizeof(struct _ColorBucket)*cube->size);
|
||||||
|
if (!buckets) return NULL;
|
||||||
|
memcpy(buckets, cube->buckets, sizeof(struct _ColorBucket)*cube->size);
|
||||||
|
|
||||||
|
qsort(buckets, cube->size, sizeof(struct _ColorBucket),
|
||||||
|
(int (*)(void const *, void const *))&compare_bucket_count);
|
||||||
|
|
||||||
|
return buckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_bucket_values(ColorBucket src, ColorBucket dst) {
|
||||||
|
dst->count += src->count;
|
||||||
|
dst->r += src->r;
|
||||||
|
dst->g += src->g;
|
||||||
|
dst->b += src->b;
|
||||||
|
dst->a += src->a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* expand or shrink a given cube to level */
|
||||||
|
static ColorCube copy_color_cube(const ColorCube cube,
|
||||||
|
int rBits, int gBits, int bBits, int aBits)
|
||||||
|
{
|
||||||
|
unsigned int r, g, b, a;
|
||||||
|
long src_pos, dst_pos;
|
||||||
|
unsigned int src_reduce[4] = {0}, dst_reduce[4] = {0};
|
||||||
|
unsigned int width[4];
|
||||||
|
ColorCube result;
|
||||||
|
|
||||||
|
result = new_color_cube(rBits, gBits, bBits, aBits);
|
||||||
|
if (!result) return NULL;
|
||||||
|
|
||||||
|
if (cube->rBits > rBits) {
|
||||||
|
dst_reduce[0] = cube->rBits - result->rBits;
|
||||||
|
width[0] = cube->rWidth;
|
||||||
|
} else {
|
||||||
|
src_reduce[0] = result->rBits - cube->rBits;
|
||||||
|
width[0] = result->rWidth;
|
||||||
|
}
|
||||||
|
if (cube->gBits > gBits) {
|
||||||
|
dst_reduce[1] = cube->gBits - result->gBits;
|
||||||
|
width[1] = cube->gWidth;
|
||||||
|
} else {
|
||||||
|
src_reduce[1] = result->gBits - cube->gBits;
|
||||||
|
width[1] = result->gWidth;
|
||||||
|
}
|
||||||
|
if (cube->bBits > bBits) {
|
||||||
|
dst_reduce[2] = cube->bBits - result->bBits;
|
||||||
|
width[2] = cube->bWidth;
|
||||||
|
} else {
|
||||||
|
src_reduce[2] = result->bBits - cube->bBits;
|
||||||
|
width[2] = result->bWidth;
|
||||||
|
}
|
||||||
|
if (cube->aBits > aBits) {
|
||||||
|
dst_reduce[3] = cube->aBits - result->aBits;
|
||||||
|
width[3] = cube->aWidth;
|
||||||
|
} else {
|
||||||
|
src_reduce[3] = result->aBits - cube->aBits;
|
||||||
|
width[3] = result->aWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (r=0; r<width[0]; r++) {
|
||||||
|
for (g=0; g<width[1]; g++) {
|
||||||
|
for (b=0; b<width[2]; b++) {
|
||||||
|
for (a=0; a<width[3]; a++) {
|
||||||
|
src_pos = color_bucket_offset_pos(cube,
|
||||||
|
r>>src_reduce[0],
|
||||||
|
g>>src_reduce[1],
|
||||||
|
b>>src_reduce[2],
|
||||||
|
a>>src_reduce[3]);
|
||||||
|
dst_pos = color_bucket_offset_pos(result,
|
||||||
|
r>>dst_reduce[0],
|
||||||
|
g>>dst_reduce[1],
|
||||||
|
b>>dst_reduce[2],
|
||||||
|
a>>dst_reduce[3]);
|
||||||
|
add_bucket_values(
|
||||||
|
&cube->buckets[src_pos],
|
||||||
|
&result->buckets[dst_pos]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
subtract_color_buckets(ColorCube cube, ColorBucket buckets, long nBuckets) {
|
||||||
|
ColorBucket minuend, subtrahend;
|
||||||
|
long i;
|
||||||
|
Pixel p;
|
||||||
|
for (i=0; i<nBuckets; i++) {
|
||||||
|
subtrahend = &buckets[i];
|
||||||
|
avg_color_from_color_bucket(subtrahend, &p);
|
||||||
|
minuend = color_bucket_from_cube(cube, &p);
|
||||||
|
minuend->count -= subtrahend->count;
|
||||||
|
minuend->r -= subtrahend->r;
|
||||||
|
minuend->g -= subtrahend->g;
|
||||||
|
minuend->b -= subtrahend->b;
|
||||||
|
minuend->a -= subtrahend->a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_lookup_value(const ColorCube cube, const Pixel *p, long value) {
|
||||||
|
ColorBucket bucket = color_bucket_from_cube(cube, p);
|
||||||
|
bucket->count = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
lookup_color(const ColorCube cube, const Pixel *p) {
|
||||||
|
ColorBucket bucket = color_bucket_from_cube(cube, p);
|
||||||
|
return bucket->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_lookup_buckets(ColorCube cube, ColorBucket palette, long nColors, long offset) {
|
||||||
|
long i;
|
||||||
|
Pixel p;
|
||||||
|
for (i=offset; i<offset+nColors; i++) {
|
||||||
|
avg_color_from_color_bucket(&palette[i], &p);
|
||||||
|
set_lookup_value(cube, &p, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorBucket
|
||||||
|
combined_palette(ColorBucket bucketsA, long nBucketsA, ColorBucket bucketsB, long nBucketsB) {
|
||||||
|
ColorBucket result;
|
||||||
|
result = malloc(sizeof(struct _ColorBucket)*(nBucketsA+nBucketsB));
|
||||||
|
memcpy(result, bucketsA, sizeof(struct _ColorBucket) * nBucketsA);
|
||||||
|
memcpy(&result[nBucketsA], bucketsB, sizeof(struct _ColorBucket) * nBucketsB);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Pixel *
|
||||||
|
create_palette_array(const ColorBucket palette, unsigned int paletteLength) {
|
||||||
|
Pixel *paletteArray;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
paletteArray = malloc(sizeof(Pixel)*paletteLength);
|
||||||
|
if (!paletteArray) return NULL;
|
||||||
|
|
||||||
|
for (i=0; i<paletteLength; i++) {
|
||||||
|
avg_color_from_color_bucket(&palette[i], &paletteArray[i]);
|
||||||
|
}
|
||||||
|
return paletteArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
map_image_pixels(const Pixel *pixelData,
|
||||||
|
unsigned long nPixels,
|
||||||
|
const ColorCube lookupCube,
|
||||||
|
unsigned long *pixelArray)
|
||||||
|
{
|
||||||
|
long i;
|
||||||
|
for (i=0; i<nPixels; i++) {
|
||||||
|
pixelArray[i] = lookup_color(lookupCube, &pixelData[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int CUBE_LEVELS[8] = {4, 4, 4, 0, 2, 2, 2, 0};
|
||||||
|
const int CUBE_LEVELS_ALPHA[8] = {3, 4, 3, 3, 2, 2, 2, 2};
|
||||||
|
|
||||||
|
int quantize_octree(Pixel *pixelData,
|
||||||
|
unsigned long nPixels,
|
||||||
|
unsigned long nQuantPixels,
|
||||||
|
Pixel **palette,
|
||||||
|
unsigned long *paletteLength,
|
||||||
|
unsigned long **quantizedPixels,
|
||||||
|
int withAlpha)
|
||||||
|
{
|
||||||
|
ColorCube fineCube = NULL;
|
||||||
|
ColorCube coarseCube = NULL;
|
||||||
|
ColorCube lookupCube = NULL;
|
||||||
|
ColorCube coarseLookupCube = NULL;
|
||||||
|
ColorBucket paletteBucketsCoarse = NULL;
|
||||||
|
ColorBucket paletteBucketsFine = NULL;
|
||||||
|
ColorBucket paletteBuckets = NULL;
|
||||||
|
unsigned long *qp = NULL;
|
||||||
|
long i;
|
||||||
|
long nCoarseColors, nFineColors, nAlreadySubtracted;
|
||||||
|
const int *cubeBits;
|
||||||
|
|
||||||
|
if (withAlpha) {
|
||||||
|
cubeBits = CUBE_LEVELS_ALPHA;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cubeBits = CUBE_LEVELS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create two color cubes, one fine grained with 8x16x8=1024
|
||||||
|
colors buckets and a coarse with 4x4x4=64 color buckets.
|
||||||
|
The coarse one guarantes that there are color buckets available for
|
||||||
|
the whole color range (assuming nQuantPixels > 64).
|
||||||
|
|
||||||
|
For a quantization to 256 colors all 64 coarse colors will be used
|
||||||
|
plus the 192 most used color buckets from the fine color cube.
|
||||||
|
The average of all colors within one bucket is used as the actual
|
||||||
|
color for that bucket.
|
||||||
|
|
||||||
|
For images with alpha the cubes gets a forth dimension,
|
||||||
|
8x16x8x8 and 4x4x4x4.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* create fine cube */
|
||||||
|
fineCube = new_color_cube(cubeBits[0], cubeBits[1],
|
||||||
|
cubeBits[2], cubeBits[3]);
|
||||||
|
if (!fineCube) goto error;
|
||||||
|
for (i=0; i<nPixels; i++) {
|
||||||
|
add_color_to_color_cube(fineCube, &pixelData[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create coarse cube */
|
||||||
|
coarseCube = copy_color_cube(fineCube, cubeBits[4], cubeBits[5],
|
||||||
|
cubeBits[6], cubeBits[7]);
|
||||||
|
if (!coarseCube) goto error;
|
||||||
|
nCoarseColors = count_used_color_buckets(coarseCube);
|
||||||
|
|
||||||
|
/* limit to nQuantPixels */
|
||||||
|
if (nCoarseColors > nQuantPixels)
|
||||||
|
nCoarseColors = nQuantPixels;
|
||||||
|
|
||||||
|
/* how many space do we have in our palette for fine colors? */
|
||||||
|
nFineColors = nQuantPixels - nCoarseColors;
|
||||||
|
|
||||||
|
/* create fine color palette */
|
||||||
|
paletteBucketsFine = create_sorted_color_palette(fineCube);
|
||||||
|
if (!paletteBucketsFine) goto error;
|
||||||
|
|
||||||
|
/* remove the used fine colors from the coarse cube */
|
||||||
|
subtract_color_buckets(coarseCube, paletteBucketsFine, nFineColors);
|
||||||
|
|
||||||
|
/* did the substraction cleared one or more coarse bucket? */
|
||||||
|
while (nCoarseColors > count_used_color_buckets(coarseCube)) {
|
||||||
|
/* then we can use the free buckets for fine colors */
|
||||||
|
nAlreadySubtracted = nFineColors;
|
||||||
|
nCoarseColors = count_used_color_buckets(coarseCube);
|
||||||
|
nFineColors = nQuantPixels - nCoarseColors;
|
||||||
|
subtract_color_buckets(coarseCube, &paletteBucketsFine[nAlreadySubtracted],
|
||||||
|
nFineColors-nAlreadySubtracted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create our palette buckets with fine and coarse combined */
|
||||||
|
paletteBucketsCoarse = create_sorted_color_palette(coarseCube);
|
||||||
|
if (!paletteBucketsCoarse) goto error;
|
||||||
|
paletteBuckets = combined_palette(paletteBucketsCoarse, nCoarseColors,
|
||||||
|
paletteBucketsFine, nFineColors);
|
||||||
|
|
||||||
|
free(paletteBucketsFine);
|
||||||
|
paletteBucketsFine = NULL;
|
||||||
|
free(paletteBucketsCoarse);
|
||||||
|
paletteBucketsCoarse = NULL;
|
||||||
|
|
||||||
|
/* add all coarse colors to our coarse lookup cube. */
|
||||||
|
coarseLookupCube = new_color_cube(cubeBits[4], cubeBits[5],
|
||||||
|
cubeBits[6], cubeBits[7]);
|
||||||
|
if (!coarseLookupCube) goto error;
|
||||||
|
add_lookup_buckets(coarseLookupCube, paletteBuckets, nCoarseColors, 0);
|
||||||
|
|
||||||
|
/* expand coarse cube (64) to larger fine cube (4k). the value of each
|
||||||
|
coarse bucket is then present in the according 64 fine buckets. */
|
||||||
|
lookupCube = copy_color_cube(coarseLookupCube, cubeBits[0], cubeBits[1],
|
||||||
|
cubeBits[2], cubeBits[3]);
|
||||||
|
if (!lookupCube) goto error;
|
||||||
|
|
||||||
|
/* add fine colors to the lookup cube */
|
||||||
|
add_lookup_buckets(lookupCube, paletteBuckets, nFineColors, nCoarseColors);
|
||||||
|
|
||||||
|
/* create result pixles and map palatte indices */
|
||||||
|
qp = malloc(sizeof(Pixel)*nPixels);
|
||||||
|
if (!qp) goto error;
|
||||||
|
map_image_pixels(pixelData, nPixels, lookupCube, qp);
|
||||||
|
|
||||||
|
/* convert palette buckets to RGB pixel palette */
|
||||||
|
*palette = create_palette_array(paletteBuckets, nQuantPixels);
|
||||||
|
if (!(*palette)) goto error;
|
||||||
|
|
||||||
|
*quantizedPixels = qp;
|
||||||
|
*paletteLength = nQuantPixels;
|
||||||
|
|
||||||
|
free_color_cube(coarseCube);
|
||||||
|
free_color_cube(fineCube);
|
||||||
|
free_color_cube(lookupCube);
|
||||||
|
free_color_cube(coarseLookupCube);
|
||||||
|
free(paletteBuckets);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error:
|
||||||
|
/* everything is initialized to NULL
|
||||||
|
so we are safe to call free */
|
||||||
|
free(qp);
|
||||||
|
free_color_cube(lookupCube);
|
||||||
|
free_color_cube(coarseLookupCube);
|
||||||
|
free(paletteBucketsCoarse);
|
||||||
|
free(paletteBucketsFine);
|
||||||
|
free_color_cube(coarseCube);
|
||||||
|
free_color_cube(fineCube);
|
||||||
|
return 0;
|
||||||
|
}
|
12
libImaging/QuantOctree.h
Normal file
12
libImaging/QuantOctree.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef __QUANT_OCTREE_H__
|
||||||
|
#define __QUANT_OCTREE_H__
|
||||||
|
|
||||||
|
int quantize_octree(Pixel *,
|
||||||
|
unsigned long,
|
||||||
|
unsigned long,
|
||||||
|
Pixel **,
|
||||||
|
unsigned long *,
|
||||||
|
unsigned long **,
|
||||||
|
int);
|
||||||
|
|
||||||
|
#endif
|
|
@ -27,6 +27,11 @@ typedef struct {
|
||||||
|
|
||||||
/* Optimize (max compression) SLOW!!! */
|
/* Optimize (max compression) SLOW!!! */
|
||||||
int optimize;
|
int optimize;
|
||||||
|
|
||||||
|
/* 0 no compression, 9 best compression, -1 default compression */
|
||||||
|
int compress_level;
|
||||||
|
/* compression strategy Z_XXX */
|
||||||
|
int compress_type;
|
||||||
|
|
||||||
/* Predefined dictionary (experimental) */
|
/* Predefined dictionary (experimental) */
|
||||||
char* dictionary;
|
char* dictionary;
|
||||||
|
|
|
@ -26,6 +26,7 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
{
|
{
|
||||||
ZIPSTATE* context = (ZIPSTATE*) state->context;
|
ZIPSTATE* context = (ZIPSTATE*) state->context;
|
||||||
int err;
|
int err;
|
||||||
|
int compress_level, compress_type;
|
||||||
UINT8* ptr;
|
UINT8* ptr;
|
||||||
int i, bpp, s, sum;
|
int i, bpp, s, sum;
|
||||||
ImagingSectionCookie cookie;
|
ImagingSectionCookie cookie;
|
||||||
|
@ -73,17 +74,25 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
context->z_stream.next_in = 0;
|
context->z_stream.next_in = 0;
|
||||||
context->z_stream.avail_in = 0;
|
context->z_stream.avail_in = 0;
|
||||||
|
|
||||||
|
compress_level = (context->optimize) ? Z_BEST_COMPRESSION
|
||||||
|
: context->compress_level;
|
||||||
|
|
||||||
|
if (context->compress_type == -1) {
|
||||||
|
compress_type = (context->mode == ZIP_PNG) ? Z_FILTERED
|
||||||
|
: Z_DEFAULT_STRATEGY;
|
||||||
|
} else {
|
||||||
|
compress_type = context->compress_type;
|
||||||
|
}
|
||||||
|
|
||||||
err = deflateInit2(&context->z_stream,
|
err = deflateInit2(&context->z_stream,
|
||||||
/* compression level */
|
/* compression level */
|
||||||
(context->optimize) ? Z_BEST_COMPRESSION
|
compress_level,
|
||||||
: Z_DEFAULT_COMPRESSION,
|
|
||||||
/* compression method */
|
/* compression method */
|
||||||
Z_DEFLATED,
|
Z_DEFLATED,
|
||||||
/* compression memory resources */
|
/* compression memory resources */
|
||||||
15, 9,
|
15, 9,
|
||||||
/* compression strategy (image data are filtered)*/
|
/* compression strategy (image data are filtered)*/
|
||||||
(context->mode == ZIP_PNG) ? Z_FILTERED
|
compress_type);
|
||||||
: Z_DEFAULT_STRATEGY);
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
state->errcode = IMAGING_CODEC_CONFIG;
|
state->errcode = IMAGING_CODEC_CONFIG;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -22,7 +22,7 @@ _LIB_IMAGING = (
|
||||||
"Geometry", "GetBBox", "GifDecode", "GifEncode", "HexDecode",
|
"Geometry", "GetBBox", "GifDecode", "GifEncode", "HexDecode",
|
||||||
"Histo", "JpegDecode", "JpegEncode", "LzwDecode", "Matrix",
|
"Histo", "JpegDecode", "JpegEncode", "LzwDecode", "Matrix",
|
||||||
"ModeFilter", "MspDecode", "Negative", "Offset", "Pack",
|
"ModeFilter", "MspDecode", "Negative", "Offset", "Pack",
|
||||||
"PackDecode", "Palette", "Paste", "Quant", "QuantHash",
|
"PackDecode", "Palette", "Paste", "Quant", "QuantOctree", "QuantHash",
|
||||||
"QuantHeap", "PcdDecode", "PcxDecode", "PcxEncode", "Point",
|
"QuantHeap", "PcdDecode", "PcxDecode", "PcxEncode", "Point",
|
||||||
"RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
|
"RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
|
||||||
"TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
|
"TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user