2010-07-31 06:52:47 +04:00
|
|
|
/*
|
|
|
|
* The Python Imaging Library.
|
|
|
|
*
|
|
|
|
* the imaging library bindings
|
|
|
|
*
|
|
|
|
* history:
|
|
|
|
* 1995-09-24 fl Created
|
|
|
|
* 1996-03-24 fl Ready for first public release (release 0.0)
|
|
|
|
* 1996-03-25 fl Added fromstring (for Jack's "img" library)
|
|
|
|
* 1996-03-28 fl Added channel operations
|
|
|
|
* 1996-03-31 fl Added point operation
|
|
|
|
* 1996-04-08 fl Added new/new_block/new_array factories
|
|
|
|
* 1996-04-13 fl Added decoders
|
|
|
|
* 1996-05-04 fl Added palette hack
|
|
|
|
* 1996-05-12 fl Compile cleanly as C++
|
|
|
|
* 1996-05-19 fl Added matrix conversions, gradient fills
|
|
|
|
* 1996-05-27 fl Added display_mode
|
|
|
|
* 1996-07-22 fl Added getbbox, offset
|
|
|
|
* 1996-07-23 fl Added sequence semantics
|
|
|
|
* 1996-08-13 fl Added logical operators, point mode
|
|
|
|
* 1996-08-16 fl Modified paste interface
|
|
|
|
* 1996-09-06 fl Added putdata methods, use abstract interface
|
|
|
|
* 1996-11-01 fl Added xbm encoder
|
|
|
|
* 1996-11-04 fl Added experimental path stuff, draw_lines, etc
|
|
|
|
* 1996-12-10 fl Added zip decoder, crc32 interface
|
|
|
|
* 1996-12-14 fl Added modulo arithmetics
|
|
|
|
* 1996-12-29 fl Added zip encoder
|
|
|
|
* 1997-01-03 fl Added fli and msp decoders
|
|
|
|
* 1997-01-04 fl Added experimental sun_rle and tga_rle decoders
|
|
|
|
* 1997-01-05 fl Added gif encoder, getpalette hack
|
|
|
|
* 1997-02-23 fl Added histogram mask
|
|
|
|
* 1997-05-12 fl Minor tweaks to match the IFUNC95 interface
|
|
|
|
* 1997-05-21 fl Added noise generator, spread effect
|
|
|
|
* 1997-06-05 fl Added mandelbrot generator
|
|
|
|
* 1997-08-02 fl Modified putpalette to coerce image mode if necessary
|
|
|
|
* 1998-01-11 fl Added INT32 support
|
|
|
|
* 1998-01-22 fl Fixed draw_points to draw the last point too
|
|
|
|
* 1998-06-28 fl Added getpixel, getink, draw_ink
|
|
|
|
* 1998-07-12 fl Added getextrema
|
|
|
|
* 1998-07-17 fl Added point conversion to arbitrary formats
|
|
|
|
* 1998-09-21 fl Added support for resampling filters
|
|
|
|
* 1998-09-22 fl Added support for quad transform
|
|
|
|
* 1998-12-29 fl Added support for arcs, chords, and pieslices
|
|
|
|
* 1999-01-10 fl Added some experimental arrow graphics stuff
|
|
|
|
* 1999-02-06 fl Added draw_bitmap, font acceleration stuff
|
|
|
|
* 2001-04-17 fl Fixed some egcs compiler nits
|
|
|
|
* 2001-09-17 fl Added screen grab primitives (win32)
|
|
|
|
* 2002-03-09 fl Added stretch primitive
|
|
|
|
* 2002-03-10 fl Fixed filter handling in rotate
|
|
|
|
* 2002-06-06 fl Added I, F, and RGB support to putdata
|
|
|
|
* 2002-06-08 fl Added rankfilter
|
|
|
|
* 2002-06-09 fl Added support for user-defined filter kernels
|
|
|
|
* 2002-11-19 fl Added clipboard grab primitives (win32)
|
|
|
|
* 2002-12-11 fl Added draw context
|
|
|
|
* 2003-04-26 fl Tweaks for Python 2.3 beta 1
|
|
|
|
* 2003-05-21 fl Added createwindow primitive (win32)
|
|
|
|
* 2003-09-13 fl Added thread section hooks
|
|
|
|
* 2003-09-15 fl Added expand helper
|
|
|
|
* 2003-09-26 fl Added experimental LA support
|
|
|
|
* 2004-02-21 fl Handle zero-size images in quantize
|
|
|
|
* 2004-06-05 fl Added ptr attribute (used to access Imaging objects)
|
|
|
|
* 2004-06-05 fl Don't crash when fetching pixels from zero-wide images
|
|
|
|
* 2004-09-17 fl Added getcolors
|
|
|
|
* 2004-10-04 fl Added modefilter
|
|
|
|
* 2005-10-02 fl Added access proxy
|
|
|
|
* 2006-06-18 fl Always draw last point in polyline
|
|
|
|
*
|
2013-03-11 23:33:04 +04:00
|
|
|
* Copyright (c) 1997-2006 by Secret Labs AB
|
2010-07-31 06:52:47 +04:00
|
|
|
* Copyright (c) 1995-2006 by Fredrik Lundh
|
|
|
|
*
|
|
|
|
* See the README file for information on usage and redistribution.
|
|
|
|
*/
|
|
|
|
|
2019-03-26 05:50:57 +03:00
|
|
|
#define PY_SSIZE_T_CLEAN
|
2010-07-31 06:52:47 +04:00
|
|
|
#include "Python.h"
|
|
|
|
|
2018-12-13 11:08:51 +03:00
|
|
|
#ifdef HAVE_LIBJPEG
|
|
|
|
#include "jconfig.h"
|
|
|
|
#endif
|
|
|
|
|
2013-03-14 04:27:24 +04:00
|
|
|
#ifdef HAVE_LIBZ
|
|
|
|
#include "zlib.h"
|
|
|
|
#endif
|
|
|
|
|
2019-12-28 01:57:49 +03:00
|
|
|
#ifdef HAVE_LIBTIFF
|
|
|
|
#ifndef _TIFFIO_
|
|
|
|
#include <tiffio.h>
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2020-09-16 08:10:28 +03:00
|
|
|
#include "libImaging/Imaging.h"
|
2010-07-31 06:52:47 +04:00
|
|
|
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
#define _USE_MATH_DEFINES
|
|
|
|
#include <math.h>
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
/* Configuration stuff. Feel free to undef things you don't need. */
|
|
|
|
#define WITH_IMAGECHOPS /* ImageChops support */
|
|
|
|
#define WITH_IMAGEDRAW /* ImageDraw support */
|
|
|
|
#define WITH_MAPPING /* use memory mapping to read some file formats */
|
|
|
|
#define WITH_IMAGEPATH /* ImagePath stuff */
|
|
|
|
#define WITH_ARROW /* arrow graphics stuff (experimental) */
|
|
|
|
#define WITH_EFFECTS /* special effects */
|
|
|
|
#define WITH_QUANTIZE /* quantization support */
|
|
|
|
#define WITH_RANKFILTER /* rank filter */
|
|
|
|
#define WITH_MODEFILTER /* mode filter */
|
|
|
|
#define WITH_THREADING /* "friendly" threading support */
|
|
|
|
#define WITH_UNSHARPMASK /* Kevin Cazabon's unsharpmask module */
|
|
|
|
|
2013-03-22 18:22:18 +04:00
|
|
|
#undef VERBOSE
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
#define B16(p, i) ((((int)p[(i)]) << 8) + p[(i) + 1])
|
|
|
|
#define L16(p, i) ((((int)p[(i) + 1]) << 8) + p[(i)])
|
|
|
|
#define S16(v) ((v) < 32768 ? (v) : ((v)-65536))
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2013-03-22 18:22:18 +04:00
|
|
|
/* OBJECT ADMINISTRATION */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD Imaging image;
|
|
|
|
ImagingAccess access;
|
|
|
|
} ImagingObject;
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyTypeObject Imaging_Type;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
#ifdef WITH_IMAGEDRAW
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
/* to write a character, cut out sxy from glyph data, place
|
|
|
|
at current position plus dxy, and advance by (dx, dy) */
|
|
|
|
int dx, dy;
|
|
|
|
int dx0, dy0, dx1, dy1;
|
|
|
|
int sx0, sy0, sx1, sy1;
|
|
|
|
} Glyph;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD ImagingObject *ref;
|
|
|
|
Imaging bitmap;
|
|
|
|
int ysize;
|
|
|
|
int baseline;
|
|
|
|
Glyph glyphs[256];
|
|
|
|
} ImagingFontObject;
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyTypeObject ImagingFont_Type;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD ImagingObject *image;
|
|
|
|
UINT8 ink[4];
|
|
|
|
int blend;
|
|
|
|
} ImagingDrawObject;
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyTypeObject ImagingDraw_Type;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD ImagingObject *image;
|
|
|
|
int readonly;
|
|
|
|
} PixelAccessObject;
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyTypeObject PixelAccess_Type;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
PyImagingNew(Imaging imOut) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!imOut) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
imagep = PyObject_New(ImagingObject, &Imaging_Type);
|
|
|
|
if (imagep == NULL) {
|
2013-11-26 04:25:06 +04:00
|
|
|
ImagingDelete(imOut);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERBOSE
|
|
|
|
printf("imaging %p allocated\n", imagep);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
imagep->image = imOut;
|
|
|
|
imagep->access = ImagingAccessNew(imOut);
|
|
|
|
|
|
|
|
return (PyObject *)imagep;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_dealloc(ImagingObject *imagep) {
|
|
|
|
#ifdef VERBOSE
|
|
|
|
printf("imaging %p deleted\n", imagep);
|
|
|
|
#endif
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (imagep->access) {
|
2013-11-26 04:25:06 +04:00
|
|
|
ImagingAccessDelete(imagep->image, imagep->access);
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
ImagingDelete(imagep->image);
|
|
|
|
PyObject_Del(imagep);
|
|
|
|
}
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
#define PyImaging_Check(op) (Py_TYPE(op) == &Imaging_Type)
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Imaging
|
|
|
|
PyImaging_AsImaging(PyObject *op) {
|
|
|
|
if (!PyImaging_Check(op)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_BadInternalCall();
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return ((ImagingObject *)op)->image;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* THREAD HANDLING */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void
|
|
|
|
ImagingSectionEnter(ImagingSectionCookie *cookie) {
|
|
|
|
#ifdef WITH_THREADING
|
|
|
|
*cookie = (PyThreadState *)PyEval_SaveThread();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ImagingSectionLeave(ImagingSectionCookie *cookie) {
|
|
|
|
#ifdef WITH_THREADING
|
|
|
|
PyEval_RestoreThread((PyThreadState *)*cookie);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* BUFFER HANDLING */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* Python compatibility API */
|
|
|
|
|
|
|
|
int
|
|
|
|
PyImaging_CheckBuffer(PyObject *buffer) {
|
2012-10-21 01:13:12 +04:00
|
|
|
return PyObject_CheckBuffer(buffer);
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2012-10-21 01:13:12 +04:00
|
|
|
int
|
|
|
|
PyImaging_GetBuffer(PyObject *buffer, Py_buffer *view) {
|
2010-07-31 06:52:47 +04:00
|
|
|
/* must call check_buffer first! */
|
2012-10-21 01:13:12 +04:00
|
|
|
return PyObject_GetBuffer(buffer, view, PyBUF_SIMPLE);
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* EXCEPTION REROUTING */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/* error messages */
|
|
|
|
static const char *must_be_sequence = "argument must be a sequence";
|
2016-04-12 10:51:55 +03:00
|
|
|
static const char *must_be_two_coordinates =
|
|
|
|
"coordinate list must contain exactly 2 coordinates";
|
2023-03-01 14:06:40 +03:00
|
|
|
static const char *incorrectly_ordered_x_coordinate =
|
|
|
|
"x1 must be greater than or equal to x0";
|
|
|
|
static const char *incorrectly_ordered_y_coordinate =
|
|
|
|
"y1 must be greater than or equal to y0";
|
2010-07-31 06:52:47 +04:00
|
|
|
static const char *wrong_mode = "unrecognized image mode";
|
|
|
|
static const char *wrong_raw_mode = "unrecognized raw mode";
|
|
|
|
static const char *outside_image = "image index out of range";
|
|
|
|
static const char *outside_palette = "palette index out of range";
|
2013-08-28 22:30:04 +04:00
|
|
|
static const char *wrong_palette_size = "invalid palette size";
|
2010-07-31 06:52:47 +04:00
|
|
|
static const char *no_palette = "image has no palette";
|
|
|
|
static const char *readonly = "image is readonly";
|
|
|
|
/* static const char* no_content = "image has no content"; */
|
|
|
|
|
|
|
|
void *
|
2020-04-07 09:58:21 +03:00
|
|
|
ImagingError_OSError(void) {
|
|
|
|
PyErr_SetString(PyExc_OSError, "error when accessing file");
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
ImagingError_MemoryError(void) {
|
|
|
|
return PyErr_NoMemory();
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
ImagingError_Mismatch(void) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "images do not match");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
ImagingError_ModeError(void) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "image has wrong mode");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
ImagingError_ValueError(const char *message) {
|
|
|
|
PyErr_SetString(
|
|
|
|
PyExc_ValueError, (message) ? (char *)message : "unrecognized argument value");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ImagingError_Clear(void) {
|
|
|
|
PyErr_Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2013-03-22 18:22:18 +04:00
|
|
|
/* HELPERS */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static int
|
|
|
|
getbands(const char *mode) {
|
|
|
|
Imaging im;
|
|
|
|
int bands;
|
|
|
|
|
|
|
|
/* FIXME: add primitive to libImaging to avoid extra allocation */
|
|
|
|
im = ImagingNew(mode, 0, 0);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!im) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return -1;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
bands = im->bands;
|
|
|
|
|
|
|
|
ImagingDelete(im);
|
|
|
|
|
|
|
|
return bands;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define TYPE_UINT8 (0x100 | sizeof(UINT8))
|
|
|
|
#define TYPE_INT32 (0x200 | sizeof(INT32))
|
2018-04-14 23:12:28 +03:00
|
|
|
#define TYPE_FLOAT16 (0x500 | sizeof(FLOAT16))
|
2010-07-31 06:52:47 +04:00
|
|
|
#define TYPE_FLOAT32 (0x300 | sizeof(FLOAT32))
|
|
|
|
#define TYPE_DOUBLE (0x400 | sizeof(double))
|
|
|
|
|
|
|
|
static void *
|
2016-03-16 14:47:18 +03:00
|
|
|
getlist(PyObject *arg, Py_ssize_t *length, const char *wrong_length, int type) {
|
2016-09-03 05:19:04 +03:00
|
|
|
/* - allocates and returns a c array of the items in the
|
2016-03-16 14:47:18 +03:00
|
|
|
python sequence arg.
|
|
|
|
- the size of the returned array is in length
|
2016-09-03 05:19:04 +03:00
|
|
|
- all of the arg items must be numeric items of the type
|
2016-03-16 14:47:18 +03:00
|
|
|
specified in type
|
|
|
|
- sequence length is checked against the length parameter IF
|
|
|
|
an error parameter is passed in wrong_length
|
2016-09-03 05:19:04 +03:00
|
|
|
- caller is responsible for freeing the memory
|
2016-03-16 14:47:18 +03:00
|
|
|
*/
|
|
|
|
|
2016-09-03 05:19:04 +03:00
|
|
|
Py_ssize_t i, n;
|
2016-03-16 14:47:18 +03:00
|
|
|
int itemp;
|
2014-07-24 01:37:04 +04:00
|
|
|
double dtemp;
|
2018-07-01 13:47:59 +03:00
|
|
|
FLOAT32 ftemp;
|
|
|
|
UINT8 *list;
|
2014-07-24 01:37:04 +04:00
|
|
|
PyObject *seq;
|
|
|
|
PyObject *op;
|
2015-10-16 19:48:01 +03:00
|
|
|
|
2018-04-14 17:06:54 +03:00
|
|
|
if (!PySequence_Check(arg)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_TypeError, must_be_sequence);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2018-04-14 17:06:54 +03:00
|
|
|
n = PySequence_Size(arg);
|
2010-07-31 06:52:47 +04:00
|
|
|
if (length && wrong_length && n != *length) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, wrong_length);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2016-03-16 14:47:18 +03:00
|
|
|
/* malloc check ok, type & ff is just a sizeof(something)
|
|
|
|
calloc checks for overflow */
|
|
|
|
list = calloc(n, type & 0xff);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!list) {
|
2020-12-20 05:00:10 +03:00
|
|
|
return ImagingError_MemoryError();
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2014-07-24 01:37:04 +04:00
|
|
|
seq = PySequence_Fast(arg, must_be_sequence);
|
2018-04-14 17:06:54 +03:00
|
|
|
if (!seq) {
|
2014-07-24 01:37:04 +04:00
|
|
|
free(list);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-10-16 19:48:01 +03:00
|
|
|
|
2014-07-24 02:16:23 +04:00
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
op = PySequence_Fast_GET_ITEM(seq, i);
|
2015-10-11 13:24:35 +03:00
|
|
|
// DRY, branch prediction is going to work _really_ well
|
|
|
|
// on this switch. And 3 fewer loops to copy/paste.
|
2014-07-24 02:16:23 +04:00
|
|
|
switch (type) {
|
|
|
|
case TYPE_UINT8:
|
2019-09-26 15:12:28 +03:00
|
|
|
itemp = PyLong_AsLong(op);
|
2018-07-01 13:47:59 +03:00
|
|
|
list[i] = CLIP8(itemp);
|
2014-07-24 02:16:23 +04:00
|
|
|
break;
|
|
|
|
case TYPE_INT32:
|
2019-09-26 15:12:28 +03:00
|
|
|
itemp = PyLong_AsLong(op);
|
2018-07-01 13:47:59 +03:00
|
|
|
memcpy(list + i * sizeof(INT32), &itemp, sizeof(itemp));
|
2014-07-24 02:16:23 +04:00
|
|
|
break;
|
|
|
|
case TYPE_FLOAT32:
|
2018-07-01 13:47:59 +03:00
|
|
|
ftemp = (FLOAT32)PyFloat_AsDouble(op);
|
|
|
|
memcpy(list + i * sizeof(ftemp), &ftemp, sizeof(ftemp));
|
2014-07-24 02:16:23 +04:00
|
|
|
break;
|
|
|
|
case TYPE_DOUBLE:
|
2014-07-24 01:37:04 +04:00
|
|
|
dtemp = PyFloat_AsDouble(op);
|
2018-07-01 13:47:59 +03:00
|
|
|
memcpy(list + i * sizeof(dtemp), &dtemp, sizeof(dtemp));
|
2014-07-24 02:16:23 +04:00
|
|
|
break;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2018-04-14 17:06:54 +03:00
|
|
|
Py_DECREF(seq);
|
|
|
|
|
|
|
|
if (PyErr_Occurred()) {
|
|
|
|
free(list);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (length) {
|
2010-07-31 06:52:47 +04:00
|
|
|
*length = n;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2018-04-14 23:12:28 +03:00
|
|
|
FLOAT32
|
|
|
|
float16tofloat32(const FLOAT16 in) {
|
|
|
|
UINT32 t1;
|
|
|
|
UINT32 t2;
|
|
|
|
UINT32 t3;
|
2018-04-15 01:20:57 +03:00
|
|
|
FLOAT32 out[1] = {0};
|
2018-04-14 23:12:28 +03:00
|
|
|
|
|
|
|
t1 = in & 0x7fff; // Non-sign bits
|
|
|
|
t2 = in & 0x8000; // Sign bit
|
|
|
|
t3 = in & 0x7c00; // Exponent
|
2018-07-01 13:50:33 +03:00
|
|
|
|
2018-04-14 23:12:28 +03:00
|
|
|
t1 <<= 13; // Align mantissa on MSB
|
|
|
|
t2 <<= 16; // Shift sign bit into position
|
|
|
|
|
|
|
|
t1 += 0x38000000; // Adjust bias
|
|
|
|
|
|
|
|
t1 = (t3 == 0 ? 0 : t1); // Denormals-as-zero
|
|
|
|
|
|
|
|
t1 |= t2; // Re-insert sign bit
|
|
|
|
|
2018-04-15 01:46:26 +03:00
|
|
|
memcpy(out, &t1, 4);
|
2018-04-15 01:20:57 +03:00
|
|
|
return out[0];
|
2018-04-14 23:12:28 +03:00
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
static inline PyObject *
|
|
|
|
getpixel(Imaging im, ImagingAccess access, int x, int y) {
|
|
|
|
union {
|
|
|
|
UINT8 b[4];
|
2013-12-20 09:39:18 +04:00
|
|
|
UINT16 h;
|
2010-07-31 06:52:47 +04:00
|
|
|
INT32 i;
|
|
|
|
FLOAT32 f;
|
|
|
|
} pixel;
|
2018-10-15 13:51:24 +03:00
|
|
|
|
|
|
|
if (x < 0) {
|
2018-10-14 17:12:58 +03:00
|
|
|
x = im->xsize + x;
|
|
|
|
}
|
2018-10-15 13:51:24 +03:00
|
|
|
if (y < 0) {
|
2018-10-14 17:12:58 +03:00
|
|
|
y = im->ysize + y;
|
|
|
|
}
|
2018-10-15 13:51:24 +03:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_IndexError, outside_image);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
access->get_pixel(im, x, y, &pixel);
|
|
|
|
|
|
|
|
switch (im->type) {
|
|
|
|
case IMAGING_TYPE_UINT8:
|
2013-11-26 04:25:06 +04:00
|
|
|
switch (im->bands) {
|
|
|
|
case 1:
|
2019-09-26 15:12:28 +03:00
|
|
|
return PyLong_FromLong(pixel.b[0]);
|
2013-11-26 04:25:06 +04:00
|
|
|
case 2:
|
|
|
|
return Py_BuildValue("BB", pixel.b[0], pixel.b[1]);
|
|
|
|
case 3:
|
|
|
|
return Py_BuildValue("BBB", pixel.b[0], pixel.b[1], pixel.b[2]);
|
|
|
|
case 4:
|
|
|
|
return Py_BuildValue(
|
|
|
|
"BBBB", pixel.b[0], pixel.b[1], pixel.b[2], pixel.b[3]);
|
|
|
|
}
|
|
|
|
break;
|
2010-07-31 06:52:47 +04:00
|
|
|
case IMAGING_TYPE_INT32:
|
2019-09-26 15:12:28 +03:00
|
|
|
return PyLong_FromLong(pixel.i);
|
2010-07-31 06:52:47 +04:00
|
|
|
case IMAGING_TYPE_FLOAT32:
|
2013-11-26 04:25:06 +04:00
|
|
|
return PyFloat_FromDouble(pixel.f);
|
2010-07-31 06:52:47 +04:00
|
|
|
case IMAGING_TYPE_SPECIAL:
|
2023-07-26 05:25:54 +03:00
|
|
|
if (im->bands == 1) {
|
2019-09-26 15:12:28 +03:00
|
|
|
return PyLong_FromLong(pixel.h);
|
2023-07-26 05:25:54 +03:00
|
|
|
} else {
|
|
|
|
return Py_BuildValue("BBB", pixel.b[0], pixel.b[1], pixel.b[2]);
|
2020-05-11 00:46:12 +03:00
|
|
|
}
|
2013-11-26 04:25:06 +04:00
|
|
|
break;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* unknown type */
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
getink(PyObject *color, Imaging im, char *ink) {
|
2016-03-11 09:14:03 +03:00
|
|
|
int g = 0, b = 0, a = 0;
|
2016-01-14 19:57:36 +03:00
|
|
|
double f = 0;
|
2016-03-11 09:14:03 +03:00
|
|
|
/* Windows 64 bit longs are 32 bits, and 0xFFFFFFFF (white) is a
|
2023-03-19 15:20:54 +03:00
|
|
|
Python long (not int) that raises an overflow error when trying
|
2016-03-11 09:14:03 +03:00
|
|
|
to return it into a 32 bit C long
|
|
|
|
*/
|
|
|
|
PY_LONG_LONG r = 0;
|
2018-07-01 13:47:59 +03:00
|
|
|
FLOAT32 ftmp;
|
|
|
|
INT32 itmp;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* fill ink buffer (four bytes) with something that can
|
|
|
|
be cast to either UINT8 or INT32 */
|
|
|
|
|
2016-01-14 19:57:36 +03:00
|
|
|
int rIsInt = 0;
|
2023-03-31 13:59:06 +03:00
|
|
|
int tupleSize = PyTuple_Check(color) ? PyTuple_GET_SIZE(color) : -1;
|
|
|
|
if (tupleSize == 1) {
|
|
|
|
color = PyTuple_GetItem(color, 0);
|
2020-09-20 07:23:05 +03:00
|
|
|
}
|
2015-08-22 15:29:23 +03:00
|
|
|
if (im->type == IMAGING_TYPE_UINT8 || im->type == IMAGING_TYPE_INT32 ||
|
|
|
|
im->type == IMAGING_TYPE_SPECIAL) {
|
2020-08-20 00:43:43 +03:00
|
|
|
if (PyLong_Check(color)) {
|
|
|
|
r = PyLong_AsLongLong(color);
|
|
|
|
if (r == -1 && PyErr_Occurred()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-01-14 19:57:36 +03:00
|
|
|
rIsInt = 1;
|
2023-03-19 16:30:10 +03:00
|
|
|
} else if (im->bands == 1) {
|
2020-09-22 01:36:29 +03:00
|
|
|
PyErr_SetString(
|
|
|
|
PyExc_TypeError, "color must be int or single-element tuple");
|
2020-08-20 00:43:43 +03:00
|
|
|
return NULL;
|
2023-03-31 13:59:06 +03:00
|
|
|
} else if (tupleSize == -1) {
|
2023-03-19 16:30:10 +03:00
|
|
|
PyErr_SetString(PyExc_TypeError, "color must be int or tuple");
|
|
|
|
return NULL;
|
2016-01-14 19:57:36 +03:00
|
|
|
}
|
2015-08-22 15:29:23 +03:00
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
switch (im->type) {
|
|
|
|
case IMAGING_TYPE_UINT8:
|
|
|
|
/* unsigned integer */
|
|
|
|
if (im->bands == 1) {
|
|
|
|
/* unsigned integer, single layer */
|
2016-01-14 19:57:36 +03:00
|
|
|
if (rIsInt != 1) {
|
2023-03-19 15:20:54 +03:00
|
|
|
if (tupleSize != 1) {
|
2021-05-19 13:19:57 +03:00
|
|
|
PyErr_SetString(PyExc_TypeError, "color must be int or single-element tuple");
|
|
|
|
return NULL;
|
|
|
|
} else if (!PyArg_ParseTuple(color, "L", &r)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2021-01-03 06:17:51 +03:00
|
|
|
}
|
2018-07-14 04:41:02 +03:00
|
|
|
ink[0] = (char)CLIP8(r);
|
2010-07-31 06:52:47 +04:00
|
|
|
ink[1] = ink[2] = ink[3] = 0;
|
2021-01-03 06:17:51 +03:00
|
|
|
} else {
|
2016-01-14 19:57:36 +03:00
|
|
|
if (rIsInt) {
|
2010-07-31 06:52:47 +04:00
|
|
|
/* compatibility: ABGR */
|
|
|
|
a = (UINT8)(r >> 24);
|
|
|
|
b = (UINT8)(r >> 16);
|
|
|
|
g = (UINT8)(r >> 8);
|
|
|
|
r = (UINT8)r;
|
|
|
|
} else {
|
2023-03-19 15:20:54 +03:00
|
|
|
a = 255;
|
2010-07-31 06:52:47 +04:00
|
|
|
if (im->bands == 2) {
|
2021-05-19 13:19:57 +03:00
|
|
|
if (tupleSize != 1 && tupleSize != 2) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, "color must be int, or tuple of one or two elements");
|
|
|
|
return NULL;
|
|
|
|
} else if (!PyArg_ParseTuple(color, "L|i", &r, &a)) {
|
2016-01-14 19:57:36 +03:00
|
|
|
return NULL;
|
2021-01-03 06:17:51 +03:00
|
|
|
}
|
|
|
|
g = b = r;
|
|
|
|
} else {
|
2021-05-19 13:19:57 +03:00
|
|
|
if (tupleSize != 3 && tupleSize != 4) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, "color must be int, or tuple of one, three or four elements");
|
|
|
|
return NULL;
|
|
|
|
} else if (!PyArg_ParseTuple(color, "Lii|i", &r, &g, &b, &a)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2021-01-03 06:17:51 +03:00
|
|
|
}
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
2018-07-14 04:41:02 +03:00
|
|
|
ink[0] = (char)CLIP8(r);
|
|
|
|
ink[1] = (char)CLIP8(g);
|
|
|
|
ink[2] = (char)CLIP8(b);
|
|
|
|
ink[3] = (char)CLIP8(a);
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
return ink;
|
|
|
|
case IMAGING_TYPE_INT32:
|
|
|
|
/* signed integer */
|
2018-07-01 13:47:59 +03:00
|
|
|
itmp = r;
|
|
|
|
memcpy(ink, &itmp, sizeof(itmp));
|
2010-07-31 06:52:47 +04:00
|
|
|
return ink;
|
|
|
|
case IMAGING_TYPE_FLOAT32:
|
|
|
|
/* floating point */
|
|
|
|
f = PyFloat_AsDouble(color);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (f == -1.0 && PyErr_Occurred()) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2018-07-01 13:47:59 +03:00
|
|
|
ftmp = f;
|
|
|
|
memcpy(ink, &ftmp, sizeof(ftmp));
|
2010-07-31 06:52:47 +04:00
|
|
|
return ink;
|
|
|
|
case IMAGING_TYPE_SPECIAL:
|
|
|
|
if (strncmp(im->mode, "I;16", 4) == 0) {
|
|
|
|
ink[0] = (UINT8)r;
|
|
|
|
ink[1] = (UINT8)(r >> 8);
|
|
|
|
ink[2] = ink[3] = 0;
|
|
|
|
return ink;
|
2023-03-19 16:30:10 +03:00
|
|
|
} else {
|
|
|
|
if (rIsInt) {
|
|
|
|
b = (UINT8)(r >> 16);
|
|
|
|
g = (UINT8)(r >> 8);
|
|
|
|
r = (UINT8)r;
|
|
|
|
} else if (tupleSize != 3) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, "color must be int, or tuple of one or three elements");
|
|
|
|
return NULL;
|
2023-07-26 05:25:54 +03:00
|
|
|
} else if (!PyArg_ParseTuple(color, "iiL", &b, &g, &r)) {
|
2023-03-19 16:30:10 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (!strcmp(im->mode, "BGR;15")) {
|
|
|
|
UINT16 v = ((((UINT16)r) << 7) & 0x7c00) +
|
|
|
|
((((UINT16)g) << 2) & 0x03e0) +
|
|
|
|
((((UINT16)b) >> 3) & 0x001f);
|
|
|
|
|
|
|
|
ink[0] = (UINT8)v;
|
|
|
|
ink[1] = (UINT8)(v >> 8);
|
|
|
|
ink[2] = ink[3] = 0;
|
|
|
|
return ink;
|
|
|
|
} else if (!strcmp(im->mode, "BGR;16")) {
|
|
|
|
UINT16 v = ((((UINT16)r) << 8) & 0xf800) +
|
|
|
|
((((UINT16)g) << 3) & 0x07e0) +
|
|
|
|
((((UINT16)b) >> 3) & 0x001f);
|
|
|
|
ink[0] = (UINT8)v;
|
|
|
|
ink[1] = (UINT8)(v >> 8);
|
|
|
|
ink[2] = ink[3] = 0;
|
|
|
|
return ink;
|
|
|
|
} else if (!strcmp(im->mode, "BGR;24")) {
|
|
|
|
ink[0] = (UINT8)b;
|
|
|
|
ink[1] = (UINT8)g;
|
|
|
|
ink[2] = (UINT8)r;
|
|
|
|
ink[3] = 0;
|
|
|
|
return ink;
|
|
|
|
}
|
2021-01-03 06:17:51 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
PyErr_SetString(PyExc_ValueError, wrong_mode);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2013-03-22 18:22:18 +04:00
|
|
|
/* FACTORIES */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_fill(PyObject *self, PyObject *args) {
|
|
|
|
char *mode;
|
|
|
|
int xsize, ysize;
|
|
|
|
PyObject *color;
|
|
|
|
char buffer[4];
|
|
|
|
Imaging im;
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
xsize = ysize = 256;
|
|
|
|
color = NULL;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "s|(ii)O", &mode, &xsize, &ysize, &color)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2017-08-06 13:32:46 +03:00
|
|
|
im = ImagingNewDirty(mode, xsize, ysize);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!im) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-01-31 19:42:00 +03:00
|
|
|
buffer[0] = buffer[1] = buffer[2] = buffer[3] = 0;
|
2010-07-31 06:52:47 +04:00
|
|
|
if (color) {
|
|
|
|
if (!getink(color, im, buffer)) {
|
|
|
|
ImagingDelete(im);
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-01-31 19:42:00 +03:00
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
(void)ImagingFill(im, buffer);
|
|
|
|
|
|
|
|
return PyImagingNew(im);
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_new(PyObject *self, PyObject *args) {
|
|
|
|
char *mode;
|
|
|
|
int xsize, ysize;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingNew(mode, xsize, ysize));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_new_block(PyObject *self, PyObject *args) {
|
|
|
|
char *mode;
|
|
|
|
int xsize, ysize;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingNewBlock(mode, xsize, ysize));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_linear_gradient(PyObject *self, PyObject *args) {
|
|
|
|
char *mode;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "s", &mode)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingFillLinearGradient(mode));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_radial_gradient(PyObject *self, PyObject *args) {
|
|
|
|
char *mode;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "s", &mode)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingFillRadialGradient(mode));
|
|
|
|
}
|
|
|
|
|
2012-12-04 19:44:26 +04:00
|
|
|
static PyObject *
|
|
|
|
_alpha_composite(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep1;
|
|
|
|
ImagingObject *imagep2;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(
|
2020-05-10 12:56:36 +03:00
|
|
|
args, "O!O!", &Imaging_Type, &imagep1, &Imaging_Type, &imagep2)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2012-12-04 19:44:26 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingAlphaComposite(imagep1->image, imagep2->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_blend(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep1;
|
|
|
|
ImagingObject *imagep2;
|
|
|
|
double alpha;
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
alpha = 0.5;
|
|
|
|
if (!PyArg_ParseTuple(
|
2013-11-26 04:25:06 +04:00
|
|
|
args, "O!O!|d", &Imaging_Type, &imagep1, &Imaging_Type, &imagep2, &alpha)) {
|
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingBlend(imagep1->image, imagep2->image, (float)alpha));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2018-03-26 11:26:51 +03:00
|
|
|
/* METHODS */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
2018-03-26 11:26:51 +03:00
|
|
|
static INT16 *
|
|
|
|
_prepare_lut_table(PyObject *table, Py_ssize_t table_size) {
|
|
|
|
int i;
|
2018-04-15 00:33:15 +03:00
|
|
|
Py_buffer buffer_info;
|
2018-04-14 23:12:28 +03:00
|
|
|
INT32 data_type = TYPE_FLOAT32;
|
2018-04-15 00:33:15 +03:00
|
|
|
float item = 0;
|
|
|
|
void *table_data = NULL;
|
|
|
|
int free_table_data = 0;
|
2018-03-26 11:26:51 +03:00
|
|
|
INT16 *prepared;
|
|
|
|
|
|
|
|
/* NOTE: This value should be the same as in ColorLUT.c */
|
|
|
|
#define PRECISION_BITS (16 - 8 - 2)
|
|
|
|
|
2018-04-15 00:33:15 +03:00
|
|
|
const char *wrong_size =
|
|
|
|
("The table should have table_channels * "
|
|
|
|
"size1D * size2D * size3D float items.");
|
|
|
|
|
|
|
|
if (PyObject_CheckBuffer(table)) {
|
|
|
|
if (!PyObject_GetBuffer(table, &buffer_info, PyBUF_CONTIG_RO | PyBUF_FORMAT)) {
|
|
|
|
if (buffer_info.ndim == 1 && buffer_info.shape[0] == table_size) {
|
|
|
|
if (strlen(buffer_info.format) == 1) {
|
|
|
|
switch (buffer_info.format[0]) {
|
|
|
|
case 'e':
|
|
|
|
data_type = TYPE_FLOAT16;
|
|
|
|
table_data = buffer_info.buf;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
data_type = TYPE_FLOAT32;
|
|
|
|
table_data = buffer_info.buf;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
data_type = TYPE_DOUBLE;
|
|
|
|
table_data = buffer_info.buf;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PyBuffer_Release(&buffer_info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-26 11:26:51 +03:00
|
|
|
if (!table_data) {
|
2018-04-15 00:33:15 +03:00
|
|
|
free_table_data = 1;
|
|
|
|
table_data = getlist(table, &table_size, wrong_size, TYPE_FLOAT32);
|
|
|
|
if (!table_data) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-03-26 11:26:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* malloc check ok, max is 2 * 4 * 65**3 = 2197000 */
|
|
|
|
prepared = (INT16 *)malloc(sizeof(INT16) * table_size);
|
|
|
|
if (!prepared) {
|
2020-05-10 12:56:36 +03:00
|
|
|
if (free_table_data) {
|
2018-07-01 13:50:33 +03:00
|
|
|
free(table_data);
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2020-12-20 05:00:10 +03:00
|
|
|
return (INT16 *)ImagingError_MemoryError();
|
2018-03-26 11:26:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < table_size; i++) {
|
2018-07-01 13:47:59 +03:00
|
|
|
FLOAT16 htmp;
|
|
|
|
double dtmp;
|
2018-04-14 23:12:28 +03:00
|
|
|
switch (data_type) {
|
|
|
|
case TYPE_FLOAT16:
|
2018-07-01 13:47:59 +03:00
|
|
|
memcpy(&htmp, ((char *)table_data) + i * sizeof(htmp), sizeof(htmp));
|
|
|
|
item = float16tofloat32(htmp);
|
2018-04-14 23:12:28 +03:00
|
|
|
break;
|
|
|
|
case TYPE_FLOAT32:
|
2018-07-01 13:47:59 +03:00
|
|
|
memcpy(
|
|
|
|
&item, ((char *)table_data) + i * sizeof(FLOAT32), sizeof(FLOAT32));
|
2018-04-14 23:12:28 +03:00
|
|
|
break;
|
|
|
|
case TYPE_DOUBLE:
|
2018-07-01 13:47:59 +03:00
|
|
|
memcpy(&dtmp, ((char *)table_data) + i * sizeof(dtmp), sizeof(dtmp));
|
|
|
|
item = (FLOAT32)dtmp;
|
2018-04-14 23:12:28 +03:00
|
|
|
break;
|
|
|
|
}
|
2018-03-26 11:26:51 +03:00
|
|
|
/* Max value for INT16 */
|
2018-04-14 23:12:28 +03:00
|
|
|
if (item >= (0x7fff - 0.5) / (255 << PRECISION_BITS)) {
|
2018-03-26 11:26:51 +03:00
|
|
|
prepared[i] = 0x7fff;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Min value for INT16 */
|
2018-04-14 23:12:28 +03:00
|
|
|
if (item <= (-0x8000 + 0.5) / (255 << PRECISION_BITS)) {
|
2018-03-26 11:26:51 +03:00
|
|
|
prepared[i] = -0x8000;
|
|
|
|
continue;
|
|
|
|
}
|
2018-04-14 23:12:28 +03:00
|
|
|
if (item < 0) {
|
|
|
|
prepared[i] = item * (255 << PRECISION_BITS) - 0.5;
|
2018-03-26 11:26:51 +03:00
|
|
|
} else {
|
2018-04-14 23:12:28 +03:00
|
|
|
prepared[i] = item * (255 << PRECISION_BITS) + 0.5;
|
2018-03-26 11:26:51 +03:00
|
|
|
}
|
|
|
|
}
|
2018-04-21 09:35:58 +03:00
|
|
|
|
2018-03-26 11:26:51 +03:00
|
|
|
#undef PRECISION_BITS
|
2018-04-15 00:33:15 +03:00
|
|
|
if (free_table_data) {
|
|
|
|
free(table_data);
|
|
|
|
}
|
2018-03-26 11:26:51 +03:00
|
|
|
return prepared;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_color_lut_3d(ImagingObject *self, PyObject *args) {
|
|
|
|
char *mode;
|
|
|
|
int filter;
|
|
|
|
int table_channels;
|
|
|
|
int size1D, size2D, size3D;
|
|
|
|
PyObject *table;
|
|
|
|
|
|
|
|
INT16 *prepared_table;
|
|
|
|
Imaging imOut;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(
|
|
|
|
args,
|
|
|
|
"siiiiiO:color_lut_3d",
|
|
|
|
&mode,
|
|
|
|
&filter,
|
|
|
|
&table_channels,
|
|
|
|
&size1D,
|
|
|
|
&size2D,
|
|
|
|
&size3D,
|
|
|
|
&table)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* actually, it is trilinear */
|
|
|
|
if (filter != IMAGING_TRANSFORM_BILINEAR) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "Only LINEAR filter is supported.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (1 > table_channels || table_channels > 4) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "table_channels should be from 1 to 4");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (2 > size1D || size1D > 65 || 2 > size2D || size2D > 65 || 2 > size3D ||
|
|
|
|
size3D > 65) {
|
|
|
|
PyErr_SetString(
|
|
|
|
PyExc_ValueError, "Table size in any dimension should be from 2 to 65");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
prepared_table =
|
|
|
|
_prepare_lut_table(table, table_channels * size1D * size2D * size3D);
|
|
|
|
if (!prepared_table) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
imOut = ImagingNewDirty(mode, self->image->xsize, self->image->ysize);
|
|
|
|
if (!imOut) {
|
|
|
|
free(prepared_table);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-04-21 09:35:58 +03:00
|
|
|
if (!ImagingColorLUT3D_linear(
|
|
|
|
imOut,
|
|
|
|
self->image,
|
2018-03-26 11:26:51 +03:00
|
|
|
table_channels,
|
|
|
|
size1D,
|
|
|
|
size2D,
|
|
|
|
size3D,
|
|
|
|
prepared_table)) {
|
|
|
|
free(prepared_table);
|
|
|
|
ImagingDelete(imOut);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(prepared_table);
|
|
|
|
|
|
|
|
return PyImagingNew(imOut);
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_convert(ImagingObject *self, PyObject *args) {
|
|
|
|
char *mode;
|
|
|
|
int dither = 0;
|
|
|
|
ImagingObject *paletteimage = NULL;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "s|iO", &mode, &dither, &paletteimage)) {
|
2013-03-26 14:24:07 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2013-11-26 04:25:06 +04:00
|
|
|
if (paletteimage != NULL) {
|
|
|
|
if (!PyImaging_Check(paletteimage)) {
|
|
|
|
PyObject_Print((PyObject *)paletteimage, stderr, 0);
|
|
|
|
PyErr_SetString(
|
|
|
|
PyExc_ValueError, "palette argument must be image with mode 'P'");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (paletteimage->image->palette == NULL) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "null palette");
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2018-03-27 03:45:00 +03:00
|
|
|
return PyImagingNew(ImagingConvert(
|
|
|
|
self->image, mode, paletteimage ? paletteimage->image->palette : NULL, dither));
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_convert2(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep1;
|
|
|
|
ImagingObject *imagep2;
|
|
|
|
if (!PyArg_ParseTuple(
|
2020-05-10 12:56:36 +03:00
|
|
|
args, "O!O!", &Imaging_Type, &imagep1, &Imaging_Type, &imagep2)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!ImagingConvert2(imagep1->image, imagep2->image)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_convert_matrix(ImagingObject *self, PyObject *args) {
|
|
|
|
char *mode;
|
|
|
|
float m[12];
|
|
|
|
if (!PyArg_ParseTuple(args, "s(ffff)", &mode, m + 0, m + 1, m + 2, m + 3)) {
|
2013-11-27 00:21:50 +04:00
|
|
|
PyErr_Clear();
|
2015-09-15 11:01:04 +03:00
|
|
|
if (!PyArg_ParseTuple(
|
|
|
|
args,
|
|
|
|
"s(ffffffffffff)",
|
|
|
|
&mode,
|
|
|
|
m + 0,
|
|
|
|
m + 1,
|
|
|
|
m + 2,
|
|
|
|
m + 3,
|
|
|
|
m + 4,
|
|
|
|
m + 5,
|
|
|
|
m + 6,
|
|
|
|
m + 7,
|
|
|
|
m + 8,
|
|
|
|
m + 9,
|
|
|
|
m + 10,
|
|
|
|
m + 11)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return PyImagingNew(ImagingConvertMatrix(self->image, mode, m));
|
|
|
|
}
|
|
|
|
|
2013-11-27 00:24:19 +04:00
|
|
|
static PyObject *
|
|
|
|
_convert_transparent(ImagingObject *self, PyObject *args) {
|
|
|
|
char *mode;
|
|
|
|
int r, g, b;
|
2013-11-27 01:04:10 +04:00
|
|
|
if (PyArg_ParseTuple(args, "s(iii)", &mode, &r, &g, &b)) {
|
|
|
|
return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, g, b));
|
2013-11-27 00:24:19 +04:00
|
|
|
}
|
2013-11-27 01:04:10 +04:00
|
|
|
PyErr_Clear();
|
|
|
|
if (PyArg_ParseTuple(args, "si", &mode, &r)) {
|
|
|
|
return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, 0, 0));
|
|
|
|
}
|
|
|
|
return NULL;
|
2013-11-27 00:24:19 +04:00
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_copy(ImagingObject *self, PyObject *args) {
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "")) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingCopy(self->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_crop(ImagingObject *self, PyObject *args) {
|
|
|
|
int x0, y0, x1, y1;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "(iiii)", &x0, &y0, &x1, &y1)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingCrop(self->image, x0, y0, x1, y1));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2014-03-17 18:50:58 +04:00
|
|
|
_expand_image(ImagingObject *self, PyObject *args) {
|
2010-07-31 06:52:47 +04:00
|
|
|
int x, y;
|
2023-06-10 08:57:05 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ii", &x, &y)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2023-06-10 08:57:05 +03:00
|
|
|
return PyImagingNew(ImagingExpand(self->image, x, y));
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_filter(ImagingObject *self, PyObject *args) {
|
|
|
|
PyObject *imOut;
|
2016-03-16 14:47:18 +03:00
|
|
|
Py_ssize_t kernelsize;
|
2010-07-31 06:52:47 +04:00
|
|
|
FLOAT32 *kerneldata;
|
|
|
|
|
2017-08-07 01:11:05 +03:00
|
|
|
int xsize, ysize, i;
|
2010-07-31 06:52:47 +04:00
|
|
|
float divisor, offset;
|
|
|
|
PyObject *kernel = NULL;
|
|
|
|
if (!PyArg_ParseTuple(
|
|
|
|
args, "(ii)ffO", &xsize, &ysize, &divisor, &offset, &kernel)) {
|
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
/* get user-defined kernel */
|
|
|
|
kerneldata = getlist(kernel, &kernelsize, NULL, TYPE_FLOAT32);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!kerneldata) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2016-03-16 14:47:18 +03:00
|
|
|
if (kernelsize != (Py_ssize_t)xsize * (Py_ssize_t)ysize) {
|
2010-07-31 06:52:47 +04:00
|
|
|
free(kerneldata);
|
|
|
|
return ImagingError_ValueError("bad kernel size");
|
|
|
|
}
|
|
|
|
|
2017-08-07 01:11:05 +03:00
|
|
|
for (i = 0; i < kernelsize; ++i) {
|
|
|
|
kerneldata[i] /= divisor;
|
|
|
|
}
|
|
|
|
|
|
|
|
imOut = PyImagingNew(ImagingFilter(self->image, xsize, ysize, kerneldata, offset));
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
free(kerneldata);
|
|
|
|
|
|
|
|
return imOut;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WITH_UNSHARPMASK
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_gaussian_blur(ImagingObject *self, PyObject *args) {
|
|
|
|
Imaging imIn;
|
|
|
|
Imaging imOut;
|
|
|
|
|
2023-08-12 05:09:20 +03:00
|
|
|
float xradius, yradius;
|
2014-10-25 16:36:41 +04:00
|
|
|
int passes = 3;
|
2023-08-12 05:09:20 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "(ff)|i", &xradius, &yradius, &passes)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
imIn = self->image;
|
2017-08-06 13:32:46 +03:00
|
|
|
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!imOut) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2023-08-12 05:09:20 +03:00
|
|
|
if (!ImagingGaussianBlur(imOut, imIn, xradius, yradius, passes)) {
|
2018-09-13 13:22:11 +03:00
|
|
|
ImagingDelete(imOut);
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2018-09-13 13:22:11 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(imOut);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_getpalette(ImagingObject *self, PyObject *args) {
|
|
|
|
PyObject *palette;
|
2022-02-16 01:56:13 +03:00
|
|
|
int palettesize;
|
2010-07-31 06:52:47 +04:00
|
|
|
int bits;
|
|
|
|
ImagingShuffler pack;
|
|
|
|
|
|
|
|
char *mode = "RGB";
|
|
|
|
char *rawmode = "RGB";
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "|ss", &mode, &rawmode)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
if (!self->image->palette) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, no_palette);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
pack = ImagingFindPacker(mode, rawmode, &bits);
|
|
|
|
if (!pack) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, wrong_raw_mode);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2022-02-16 01:56:13 +03:00
|
|
|
palettesize = self->image->palette->size;
|
2012-10-14 08:47:30 +04:00
|
|
|
palette = PyBytes_FromStringAndSize(NULL, palettesize * bits / 8);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!palette) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2012-10-14 08:47:30 +04:00
|
|
|
pack(
|
2013-11-26 04:25:06 +04:00
|
|
|
(UINT8 *)PyBytes_AsString(palette), self->image->palette->palette, palettesize);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return palette;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2021-05-11 13:19:17 +03:00
|
|
|
_getpalettemode(ImagingObject *self) {
|
2013-03-11 23:33:04 +04:00
|
|
|
if (!self->image->palette) {
|
2013-03-22 18:22:18 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, no_palette);
|
|
|
|
return NULL;
|
2013-03-11 23:33:04 +04:00
|
|
|
}
|
|
|
|
|
2013-03-12 23:19:08 +04:00
|
|
|
return PyUnicode_FromString(self->image->palette->mode);
|
2013-03-11 23:33:04 +04:00
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
static inline int
|
|
|
|
_getxy(PyObject *xy, int *x, int *y) {
|
|
|
|
PyObject *value;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyTuple_Check(xy) || PyTuple_GET_SIZE(xy) != 2) {
|
2010-07-31 06:52:47 +04:00
|
|
|
goto badarg;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
value = PyTuple_GET_ITEM(xy, 0);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (PyLong_Check(value)) {
|
2019-09-26 15:12:28 +03:00
|
|
|
*x = PyLong_AS_LONG(value);
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (PyFloat_Check(value)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
*x = (int)PyFloat_AS_DOUBLE(value);
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2021-01-14 13:31:25 +03:00
|
|
|
PyObject *int_value = PyObject_CallMethod(value, "__int__", NULL);
|
|
|
|
if (int_value != NULL && PyLong_Check(int_value)) {
|
|
|
|
*x = PyLong_AS_LONG(int_value);
|
|
|
|
} else {
|
|
|
|
goto badval;
|
|
|
|
}
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
value = PyTuple_GET_ITEM(xy, 1);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (PyLong_Check(value)) {
|
2019-09-26 15:12:28 +03:00
|
|
|
*y = PyLong_AS_LONG(value);
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (PyFloat_Check(value)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
*y = (int)PyFloat_AS_DOUBLE(value);
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2021-01-14 13:31:25 +03:00
|
|
|
PyObject *int_value = PyObject_CallMethod(value, "__int__", NULL);
|
|
|
|
if (int_value != NULL && PyLong_Check(int_value)) {
|
|
|
|
*y = PyLong_AS_LONG(int_value);
|
|
|
|
} else {
|
|
|
|
goto badval;
|
|
|
|
}
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
badarg:
|
|
|
|
PyErr_SetString(PyExc_TypeError, "argument must be sequence of length 2");
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
badval:
|
|
|
|
PyErr_SetString(PyExc_TypeError, "an integer is required");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_getpixel(ImagingObject *self, PyObject *args) {
|
|
|
|
PyObject *xy;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
if (PyTuple_GET_SIZE(args) != 1) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, "argument 1 must be sequence of length 2");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
xy = PyTuple_GET_ITEM(args, 0);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (_getxy(xy, &x, &y)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
if (self->access == NULL) {
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
return getpixel(self->image, self->access, x, y);
|
|
|
|
}
|
|
|
|
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
union hist_extrema {
|
|
|
|
UINT8 u[2];
|
|
|
|
INT32 i[2];
|
|
|
|
FLOAT32 f[2];
|
|
|
|
};
|
|
|
|
|
|
|
|
static union hist_extrema *
|
|
|
|
parse_histogram_extremap(
|
|
|
|
ImagingObject *self, PyObject *extremap, union hist_extrema *ep) {
|
2010-07-31 06:52:47 +04:00
|
|
|
int i0, i1;
|
|
|
|
double f0, f1;
|
|
|
|
|
|
|
|
if (extremap) {
|
|
|
|
switch (self->image->type) {
|
|
|
|
case IMAGING_TYPE_UINT8:
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(extremap, "ii", &i0, &i1)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
ep->u[0] = CLIP8(i0);
|
|
|
|
ep->u[1] = CLIP8(i1);
|
2010-07-31 06:52:47 +04:00
|
|
|
break;
|
|
|
|
case IMAGING_TYPE_INT32:
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(extremap, "ii", &i0, &i1)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
ep->i[0] = i0;
|
|
|
|
ep->i[1] = i1;
|
2010-07-31 06:52:47 +04:00
|
|
|
break;
|
|
|
|
case IMAGING_TYPE_FLOAT32:
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(extremap, "dd", &f0, &f1)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2021-01-03 06:17:51 +03:00
|
|
|
}
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
ep->f[0] = (FLOAT32)f0;
|
|
|
|
ep->f[1] = (FLOAT32)f1;
|
2021-01-03 06:17:51 +03:00
|
|
|
break;
|
|
|
|
default:
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return ep;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_histogram(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingHistogram h;
|
|
|
|
PyObject *list;
|
|
|
|
int i;
|
|
|
|
union hist_extrema extrema;
|
|
|
|
union hist_extrema *ep;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
PyObject *extremap = NULL;
|
|
|
|
ImagingObject *maskp = NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "|OO!", &extremap, &Imaging_Type, &maskp)) {
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
|
|
|
|
/* Using a var to avoid allocations. */
|
|
|
|
ep = parse_histogram_extremap(self, extremap, &extrema);
|
2010-07-31 06:52:47 +04:00
|
|
|
h = ImagingGetHistogram(self->image, (maskp) ? maskp->image : NULL, ep);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!h) {
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Build an integer list containing the histogram */
|
|
|
|
list = PyList_New(h->bands * 256);
|
2023-03-10 09:37:06 +03:00
|
|
|
if (list == NULL) {
|
2023-03-29 23:54:01 +03:00
|
|
|
ImagingHistogramDelete(h);
|
2023-03-10 09:37:06 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
for (i = 0; i < h->bands * 256; i++) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyObject *item;
|
2019-09-26 15:12:28 +03:00
|
|
|
item = PyLong_FromLong(h->histogram[i]);
|
2013-11-26 04:25:06 +04:00
|
|
|
if (item == NULL) {
|
|
|
|
Py_DECREF(list);
|
|
|
|
list = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PyList_SetItem(list, i, item);
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
/* Destroy the histogram structure */
|
2010-07-31 06:52:47 +04:00
|
|
|
ImagingHistogramDelete(h);
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
static PyObject *
|
|
|
|
_entropy(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingHistogram h;
|
|
|
|
int idx, length;
|
|
|
|
long sum;
|
2019-03-27 14:04:51 +03:00
|
|
|
double entropy, fsum, p;
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
union hist_extrema extrema;
|
|
|
|
union hist_extrema *ep;
|
|
|
|
|
|
|
|
PyObject *extremap = NULL;
|
|
|
|
ImagingObject *maskp = NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "|OO!", &extremap, &Imaging_Type, &maskp)) {
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
|
|
|
|
/* Using a local var to avoid allocations. */
|
|
|
|
ep = parse_histogram_extremap(self, extremap, &extrema);
|
|
|
|
h = ImagingGetHistogram(self->image, (maskp) ? maskp->image : NULL, ep);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!h) {
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
|
|
|
|
/* Calculate the histogram entropy */
|
|
|
|
/* First, sum the histogram data */
|
|
|
|
length = h->bands * 256;
|
|
|
|
sum = 0;
|
|
|
|
for (idx = 0; idx < length; idx++) {
|
|
|
|
sum += h->histogram[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next, normalize the histogram data, */
|
|
|
|
/* using the histogram sum value */
|
|
|
|
fsum = (double)sum;
|
2019-03-27 14:04:51 +03:00
|
|
|
entropy = 0.0;
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
for (idx = 0; idx < length; idx++) {
|
|
|
|
p = (double)h->histogram[idx] / fsum;
|
|
|
|
if (p != 0.0) {
|
2019-03-27 14:04:51 +03:00
|
|
|
entropy += p * log(p) * M_LOG2E;
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Destroy the histogram structure */
|
|
|
|
ImagingHistogramDelete(h);
|
|
|
|
|
2019-03-27 14:04:51 +03:00
|
|
|
return PyFloat_FromDouble(-entropy);
|
Added an `image.entropy()` method
This calculates the entropy for the image, based on the histogram.
Because this uses image histogram data directly, the existing C
function underpinning the `image.histogram()` method was abstracted
into a static function to parse extrema tuple arguments, and a new
C function was added to calculate image entropy, making use of the
new static extrema function.
The extrema-parsing function was written by @homm, based on the
macro abstraction I wrote, during the discussion of my first
entropy-method pull request: https://git.io/fhodS
The new `image.entropy()` method is based on `image.histogram()`,
and will accept the same arguments to calculate the histogram data
it will use to assess the entropy of the image.
The algorithm and methodology is based on existing Python code:
* https://git.io/fhmIU
... A test case in the `Tests/` directory, and doctest lines in
`selftest.py`, have both been added and checked.
Changes proposed in this pull request:
* Added “math.h” include to _imaging.c
* The addition of an `image.entropy()` method to the `Image`
Python class,
* The abstraction of the extrema-parsing logic of of the C
function `_histogram` into a static function, and
* The use of that static function in both the `_histogram` and
`_entropy` C functions.
* Minor documentation addenda in the docstrings for both the
`image.entropy()` and `image.histogram()` methods were also
added.
* Removed outdated boilerplate from testing code
* Removed unused “unittest” import
2019-01-25 20:38:11 +03:00
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
#ifdef WITH_MODEFILTER
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_modefilter(ImagingObject *self, PyObject *args) {
|
|
|
|
int size;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "i", &size)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingModeFilter(self->image, size));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_offset(ImagingObject *self, PyObject *args) {
|
|
|
|
int xoffset, yoffset;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ii", &xoffset, &yoffset)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingOffset(self->image, xoffset, yoffset));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_paste(ImagingObject *self, PyObject *args) {
|
|
|
|
int status;
|
|
|
|
char ink[4];
|
|
|
|
|
|
|
|
PyObject *source;
|
|
|
|
int x0, y0, x1, y1;
|
|
|
|
ImagingObject *maskp = NULL;
|
|
|
|
if (!PyArg_ParseTuple(
|
2020-05-10 12:56:36 +03:00
|
|
|
args, "O(iiii)|O!", &source, &x0, &y0, &x1, &y1, &Imaging_Type, &maskp)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (PyImaging_Check(source)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
status = ImagingPaste(
|
|
|
|
self->image,
|
|
|
|
PyImaging_AsImaging(source),
|
|
|
|
(maskp) ? maskp->image : NULL,
|
|
|
|
x0,
|
|
|
|
y0,
|
|
|
|
x1,
|
|
|
|
y1);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
|
|
|
if (!getink(source, self->image, ink)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
status = ImagingFill2(
|
|
|
|
self->image, ink, (maskp) ? maskp->image : NULL, x0, y0, x1, y1);
|
|
|
|
}
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (status < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_point(ImagingObject *self, PyObject *args) {
|
|
|
|
static const char *wrong_number = "wrong number of lut entries";
|
|
|
|
|
2016-03-16 14:47:18 +03:00
|
|
|
Py_ssize_t n;
|
|
|
|
int i, bands;
|
2010-07-31 06:52:47 +04:00
|
|
|
Imaging im;
|
|
|
|
|
|
|
|
PyObject *list;
|
|
|
|
char *mode;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "Oz", &list, &mode)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
if (mode && !strcmp(mode, "F")) {
|
|
|
|
FLOAT32 *data;
|
|
|
|
|
|
|
|
/* map from 8-bit data to floating point */
|
|
|
|
n = 256;
|
|
|
|
data = getlist(list, &n, wrong_number, TYPE_FLOAT32);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!data) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
im = ImagingPoint(self->image, mode, (void *)data);
|
|
|
|
free(data);
|
|
|
|
|
|
|
|
} else if (!strcmp(self->image->mode, "I") && mode && !strcmp(mode, "L")) {
|
|
|
|
UINT8 *data;
|
|
|
|
|
|
|
|
/* map from 16-bit subset of 32-bit data to 8-bit */
|
|
|
|
/* FIXME: support arbitrary number of entries (requires API change) */
|
|
|
|
n = 65536;
|
|
|
|
data = getlist(list, &n, wrong_number, TYPE_UINT8);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!data) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
im = ImagingPoint(self->image, mode, (void *)data);
|
|
|
|
free(data);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
INT32 *data;
|
|
|
|
UINT8 lut[1024];
|
|
|
|
|
|
|
|
if (mode) {
|
|
|
|
bands = getbands(mode);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (bands < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
|
|
|
} else {
|
2010-07-31 06:52:47 +04:00
|
|
|
bands = self->image->bands;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* map to integer data */
|
|
|
|
n = 256 * bands;
|
|
|
|
data = getlist(list, &n, wrong_number, TYPE_INT32);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!data) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (mode && !strcmp(mode, "I")) {
|
2010-07-31 06:52:47 +04:00
|
|
|
im = ImagingPoint(self->image, mode, (void *)data);
|
2020-05-10 12:56:36 +03:00
|
|
|
} else if (mode && bands > 1) {
|
2010-07-31 06:52:47 +04:00
|
|
|
for (i = 0; i < 256; i++) {
|
2018-04-21 11:14:05 +03:00
|
|
|
lut[i * 4] = CLIP8(data[i]);
|
|
|
|
lut[i * 4 + 1] = CLIP8(data[i + 256]);
|
|
|
|
lut[i * 4 + 2] = CLIP8(data[i + 512]);
|
2020-05-11 00:46:12 +03:00
|
|
|
if (n > 768) {
|
2018-04-21 11:14:05 +03:00
|
|
|
lut[i * 4 + 3] = CLIP8(data[i + 768]);
|
2020-05-11 00:46:12 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
im = ImagingPoint(self->image, mode, (void *)lut);
|
|
|
|
} else {
|
|
|
|
/* map individual bands */
|
2020-05-10 12:56:36 +03:00
|
|
|
for (i = 0; i < n; i++) {
|
2018-04-21 11:14:05 +03:00
|
|
|
lut[i] = CLIP8(data[i]);
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
im = ImagingPoint(self->image, mode, (void *)lut);
|
|
|
|
}
|
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return PyImagingNew(im);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_point_transform(ImagingObject *self, PyObject *args) {
|
|
|
|
double scale = 1.0;
|
|
|
|
double offset = 0.0;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "|dd", &scale, &offset)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingPointTransform(self->image, scale, offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_putdata(ImagingObject *self, PyObject *args) {
|
|
|
|
Imaging image;
|
2013-12-05 10:07:11 +04:00
|
|
|
// i & n are # pixels, require py_ssize_t. x can be as large as n. y, just because.
|
|
|
|
Py_ssize_t n, i, x, y;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
PyObject *data;
|
2015-04-16 17:27:57 +03:00
|
|
|
PyObject *seq = NULL;
|
2014-07-24 02:38:11 +04:00
|
|
|
PyObject *op;
|
2010-07-31 06:52:47 +04:00
|
|
|
double scale = 1.0;
|
|
|
|
double offset = 0.0;
|
2012-10-16 00:03:09 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O|dd", &data, &scale, &offset)) {
|
2012-10-16 00:03:09 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
if (!PySequence_Check(data)) {
|
2013-12-05 10:07:11 +04:00
|
|
|
PyErr_SetString(PyExc_TypeError, must_be_sequence);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
image = self->image;
|
|
|
|
|
|
|
|
n = PyObject_Length(data);
|
2019-01-26 02:11:22 +03:00
|
|
|
if (n > (Py_ssize_t)image->xsize * (Py_ssize_t)image->ysize) {
|
2013-12-05 10:07:11 +04:00
|
|
|
PyErr_SetString(PyExc_TypeError, "too many data entries");
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2021-12-28 01:38:10 +03:00
|
|
|
#define set_value_to_item(seq, i) \
|
|
|
|
op = PySequence_Fast_GET_ITEM(seq, i); \
|
|
|
|
if (PySequence_Check(op)) { \
|
|
|
|
PyErr_SetString(PyExc_TypeError, "sequence must be flattened"); \
|
|
|
|
return NULL; \
|
|
|
|
} else { \
|
|
|
|
value = PyFloat_AsDouble(op); \
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
if (image->image8) {
|
2012-10-14 08:47:30 +04:00
|
|
|
if (PyBytes_Check(data)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
unsigned char *p;
|
2012-10-14 08:47:30 +04:00
|
|
|
p = (unsigned char *)PyBytes_AS_STRING(data);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (scale == 1.0 && offset == 0.0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
/* Plain string data */
|
|
|
|
for (i = y = 0; i < n; i += image->xsize, y++) {
|
|
|
|
x = n - i;
|
2020-05-11 00:46:12 +03:00
|
|
|
if (x > (int)image->xsize) {
|
2010-07-31 06:52:47 +04:00
|
|
|
x = image->xsize;
|
2020-05-11 00:46:12 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
memcpy(image->image8[y], p + i, x);
|
|
|
|
}
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2010-07-31 06:52:47 +04:00
|
|
|
/* Scaled and clipped string data */
|
|
|
|
for (i = x = y = 0; i < n; i++) {
|
2018-04-21 11:14:05 +03:00
|
|
|
image->image8[y][x] = CLIP8((int)(p[i] * scale + offset));
|
2020-05-11 00:46:12 +03:00
|
|
|
if (++x >= (int)image->xsize) {
|
2010-07-31 06:52:47 +04:00
|
|
|
x = 0, y++;
|
2020-05-11 00:46:12 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
} else {
|
2014-07-24 02:38:11 +04:00
|
|
|
seq = PySequence_Fast(data, must_be_sequence);
|
|
|
|
if (!seq) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, must_be_sequence);
|
|
|
|
return NULL;
|
|
|
|
}
|
2021-12-28 01:38:10 +03:00
|
|
|
double value;
|
2023-07-26 12:13:56 +03:00
|
|
|
if (image->bands == 1) {
|
2023-10-07 09:09:17 +03:00
|
|
|
int bigendian = 0;
|
|
|
|
if (image->type == IMAGING_TYPE_SPECIAL) {
|
2023-10-07 10:00:29 +03:00
|
|
|
// I;16*
|
2023-10-07 09:09:17 +03:00
|
|
|
bigendian = strcmp(image->mode, "I;16B") == 0;
|
|
|
|
}
|
2023-07-26 12:13:56 +03:00
|
|
|
for (i = x = y = 0; i < n; i++) {
|
|
|
|
set_value_to_item(seq, i);
|
|
|
|
if (scale != 1.0 || offset != 0.0) {
|
|
|
|
value = value * scale + offset;
|
|
|
|
}
|
|
|
|
if (image->type == IMAGING_TYPE_SPECIAL) {
|
|
|
|
image->image8[y][x * 2 + (bigendian ? 1 : 0)] = CLIP8((int)value % 256);
|
|
|
|
image->image8[y][x * 2 + (bigendian ? 0 : 1)] = CLIP8((int)value >> 8);
|
|
|
|
} else {
|
|
|
|
image->image8[y][x] = (UINT8)CLIP8(value);
|
|
|
|
}
|
|
|
|
if (++x >= (int)image->xsize) {
|
|
|
|
x = 0, y++;
|
|
|
|
}
|
2014-07-24 02:38:11 +04:00
|
|
|
}
|
2023-07-26 12:13:56 +03:00
|
|
|
} else {
|
|
|
|
// BGR;*
|
|
|
|
int b;
|
|
|
|
for (i = x = y = 0; i < n; i++) {
|
|
|
|
char ink[4];
|
|
|
|
|
|
|
|
op = PySequence_Fast_GET_ITEM(seq, i);
|
|
|
|
if (!op || !getink(op, image, ink)) {
|
|
|
|
Py_DECREF(seq);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* FIXME: what about scale and offset? */
|
|
|
|
for (b = 0; b < image->pixelsize; b++) {
|
|
|
|
image->image8[y][x * image->pixelsize + b] = ink[b];
|
|
|
|
}
|
|
|
|
if (++x >= (int)image->xsize) {
|
|
|
|
x = 0, y++;
|
|
|
|
}
|
2014-07-24 02:38:11 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
PyErr_Clear(); /* Avoid weird exceptions */
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* 32-bit images */
|
2014-07-24 02:38:11 +04:00
|
|
|
seq = PySequence_Fast(data, must_be_sequence);
|
|
|
|
if (!seq) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, must_be_sequence);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
switch (image->type) {
|
|
|
|
case IMAGING_TYPE_INT32:
|
|
|
|
for (i = x = y = 0; i < n; i++) {
|
2021-12-28 01:38:10 +03:00
|
|
|
double value;
|
|
|
|
set_value_to_item(seq, i);
|
2010-07-31 06:52:47 +04:00
|
|
|
IMAGING_PIXEL_INT32(image, x, y) =
|
2021-12-28 01:38:10 +03:00
|
|
|
(INT32)(value * scale + offset);
|
2014-07-24 02:38:11 +04:00
|
|
|
if (++x >= (int)image->xsize) {
|
2010-07-31 06:52:47 +04:00
|
|
|
x = 0, y++;
|
2021-01-03 06:17:51 +03:00
|
|
|
}
|
2014-07-24 02:38:11 +04:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
PyErr_Clear(); /* Avoid weird exceptions */
|
|
|
|
break;
|
|
|
|
case IMAGING_TYPE_FLOAT32:
|
|
|
|
for (i = x = y = 0; i < n; i++) {
|
2021-12-28 01:38:10 +03:00
|
|
|
double value;
|
|
|
|
set_value_to_item(seq, i);
|
2010-07-31 06:52:47 +04:00
|
|
|
IMAGING_PIXEL_FLOAT32(image, x, y) =
|
2021-12-28 01:38:10 +03:00
|
|
|
(FLOAT32)(value * scale + offset);
|
2014-07-24 02:38:11 +04:00
|
|
|
if (++x >= (int)image->xsize) {
|
2010-07-31 06:52:47 +04:00
|
|
|
x = 0, y++;
|
2021-01-03 06:17:51 +03:00
|
|
|
}
|
2014-07-24 02:38:11 +04:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
PyErr_Clear(); /* Avoid weird exceptions */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
for (i = x = y = 0; i < n; i++) {
|
2012-10-14 07:24:48 +04:00
|
|
|
union {
|
|
|
|
char ink[4];
|
|
|
|
INT32 inkint;
|
|
|
|
} u;
|
|
|
|
|
2016-01-31 19:42:00 +03:00
|
|
|
u.inkint = 0;
|
|
|
|
|
2014-11-14 01:56:59 +03:00
|
|
|
op = PySequence_Fast_GET_ITEM(seq, i);
|
2012-10-14 07:24:48 +04:00
|
|
|
if (!op || !getink(op, image, u.ink)) {
|
2015-04-16 17:27:57 +03:00
|
|
|
Py_DECREF(seq);
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* FIXME: what about scale and offset? */
|
2012-10-14 07:24:48 +04:00
|
|
|
image->image32[y][x] = u.inkint;
|
2014-07-24 02:38:11 +04:00
|
|
|
if (++x >= (int)image->xsize) {
|
2010-07-31 06:52:47 +04:00
|
|
|
x = 0, y++;
|
2021-01-03 06:17:51 +03:00
|
|
|
}
|
2014-07-24 02:38:11 +04:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
PyErr_Clear(); /* Avoid weird exceptions */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-16 17:27:57 +03:00
|
|
|
Py_XDECREF(seq);
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WITH_QUANTIZE
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_quantize(ImagingObject *self, PyObject *args) {
|
|
|
|
int colours = 256;
|
|
|
|
int method = 0;
|
|
|
|
int kmeans = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "|iii", &colours, &method, &kmeans)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
if (!self->image->xsize || !self->image->ysize) {
|
|
|
|
/* no content; return an empty image */
|
|
|
|
return PyImagingNew(ImagingNew("P", self->image->xsize, self->image->ysize));
|
|
|
|
}
|
|
|
|
|
|
|
|
return PyImagingNew(ImagingQuantize(self->image, colours, method, kmeans));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_putpalette(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingShuffler unpack;
|
|
|
|
int bits;
|
|
|
|
|
2022-02-14 12:28:47 +03:00
|
|
|
char *rawmode, *palette_mode;
|
2010-07-31 06:52:47 +04:00
|
|
|
UINT8 *palette;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t palettesize;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "sy#", &rawmode, &palette, &palettesize)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2019-03-20 00:13:56 +03:00
|
|
|
if (strcmp(self->image->mode, "L") && strcmp(self->image->mode, "LA") &&
|
|
|
|
strcmp(self->image->mode, "P") && strcmp(self->image->mode, "PA")) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, wrong_mode);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2022-02-14 12:28:47 +03:00
|
|
|
palette_mode = strncmp("RGBA", rawmode, 4) == 0 ? "RGBA" : "RGB";
|
|
|
|
unpack = ImagingFindUnpacker(palette_mode, rawmode, &bits);
|
2010-07-31 06:52:47 +04:00
|
|
|
if (!unpack) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, wrong_raw_mode);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2013-08-28 22:30:04 +04:00
|
|
|
if (palettesize * 8 / bits > 256) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, wrong_palette_size);
|
|
|
|
return NULL;
|
2013-08-28 22:30:04 +04:00
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
ImagingPaletteDelete(self->image->palette);
|
|
|
|
|
2019-05-11 07:43:48 +03:00
|
|
|
strcpy(self->image->mode, strlen(self->image->mode) == 2 ? "PA" : "P");
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2022-02-14 12:28:47 +03:00
|
|
|
self->image->palette = ImagingPaletteNew(palette_mode);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2022-02-16 01:56:13 +03:00
|
|
|
self->image->palette->size = palettesize * 8 / bits;
|
|
|
|
unpack(self->image->palette->palette, palette, self->image->palette->size);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2022-02-16 01:56:13 +03:00
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_putpalettealpha(ImagingObject *self, PyObject *args) {
|
|
|
|
int index;
|
|
|
|
int alpha = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "i|i", &index, &alpha)) {
|
2013-03-26 14:24:07 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
if (!self->image->palette) {
|
2013-03-26 14:24:07 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, no_palette);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (index < 0 || index >= 256) {
|
2013-03-26 14:24:07 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, outside_palette);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
2013-02-01 20:52:22 +04:00
|
|
|
|
2013-03-11 22:02:54 +04:00
|
|
|
strcpy(self->image->palette->mode, "RGBA");
|
|
|
|
self->image->palette->palette[index * 4 + 3] = (UINT8)alpha;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
|
|
|
_putpalettealphas(ImagingObject *self, PyObject *args) {
|
|
|
|
int i;
|
|
|
|
UINT8 *values;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t length;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "y#", &values, &length)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2013-03-11 23:33:04 +04:00
|
|
|
|
|
|
|
if (!self->image->palette) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, no_palette);
|
|
|
|
return NULL;
|
2013-03-11 23:33:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (length > 256) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, outside_palette);
|
|
|
|
return NULL;
|
2013-03-11 23:33:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(self->image->palette->mode, "RGBA");
|
|
|
|
for (i = 0; i < length; i++) {
|
2013-11-26 04:25:06 +04:00
|
|
|
self->image->palette->palette[i * 4 + 3] = (UINT8)values[i];
|
2013-03-11 23:33:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_putpixel(ImagingObject *self, PyObject *args) {
|
|
|
|
Imaging im;
|
|
|
|
char ink[4];
|
|
|
|
|
|
|
|
int x, y;
|
|
|
|
PyObject *color;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "(ii)O", &x, &y, &color)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
im = self->image;
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2018-10-15 13:51:24 +03:00
|
|
|
if (x < 0) {
|
|
|
|
x = im->xsize + x;
|
|
|
|
}
|
|
|
|
if (y < 0) {
|
|
|
|
y = im->ysize + y;
|
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_IndexError, outside_image);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!getink(color, im, ink)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (self->access) {
|
2010-07-31 06:52:47 +04:00
|
|
|
self->access->put_pixel(im, x, y, ink);
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WITH_RANKFILTER
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_rankfilter(ImagingObject *self, PyObject *args) {
|
|
|
|
int size, rank;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ii", &size, &rank)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingRankFilter(self->image, size, rank));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_resize(ImagingObject *self, PyObject *args) {
|
|
|
|
Imaging imIn;
|
|
|
|
Imaging imOut;
|
|
|
|
|
|
|
|
int xsize, ysize;
|
|
|
|
int filter = IMAGING_TRANSFORM_NEAREST;
|
2016-11-30 20:01:28 +03:00
|
|
|
float box[4] = {0, 0, 0, 0};
|
2018-01-27 09:02:56 +03:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
imIn = self->image;
|
2016-11-30 20:01:28 +03:00
|
|
|
box[2] = imIn->xsize;
|
|
|
|
box[3] = imIn->ysize;
|
2018-01-27 09:02:56 +03:00
|
|
|
|
2016-11-24 04:40:54 +03:00
|
|
|
if (!PyArg_ParseTuple(
|
|
|
|
args,
|
|
|
|
"(ii)|i(ffff)",
|
|
|
|
&xsize,
|
|
|
|
&ysize,
|
|
|
|
&filter,
|
2020-05-10 12:56:36 +03:00
|
|
|
&box[0],
|
|
|
|
&box[1],
|
|
|
|
&box[2],
|
|
|
|
&box[3])) {
|
2016-11-24 04:40:54 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-02-04 17:57:57 +03:00
|
|
|
if (xsize < 1 || ysize < 1) {
|
|
|
|
return ImagingError_ValueError("height and width must be > 0");
|
|
|
|
}
|
|
|
|
|
2016-11-30 20:01:28 +03:00
|
|
|
if (box[0] < 0 || box[1] < 0) {
|
2016-12-02 16:46:54 +03:00
|
|
|
return ImagingError_ValueError("box offset can't be negative");
|
2016-11-24 04:40:54 +03:00
|
|
|
}
|
|
|
|
|
2016-11-30 20:01:28 +03:00
|
|
|
if (box[2] > imIn->xsize || box[3] > imIn->ysize) {
|
2016-12-02 16:46:54 +03:00
|
|
|
return ImagingError_ValueError("box can't exceed original image size");
|
2016-11-24 04:40:54 +03:00
|
|
|
}
|
|
|
|
|
2017-08-11 19:36:46 +03:00
|
|
|
if (box[2] - box[0] < 0 || box[3] - box[1] < 0) {
|
2016-12-02 16:46:54 +03:00
|
|
|
return ImagingError_ValueError("box can't be empty");
|
2016-11-24 04:40:54 +03:00
|
|
|
}
|
|
|
|
|
2017-08-31 19:18:48 +03:00
|
|
|
// If box's coordinates are int and box size matches requested size
|
2017-08-31 22:28:43 +03:00
|
|
|
if (box[0] - (int)box[0] == 0 && box[2] - box[0] == xsize &&
|
|
|
|
box[1] - (int)box[1] == 0 && box[3] - box[1] == ysize) {
|
2017-08-31 19:18:48 +03:00
|
|
|
imOut = ImagingCrop(imIn, box[0], box[1], box[2], box[3]);
|
2016-06-02 21:58:42 +03:00
|
|
|
} else if (filter == IMAGING_TRANSFORM_NEAREST) {
|
2022-11-04 00:57:39 +03:00
|
|
|
double a[8];
|
2014-11-04 12:31:36 +03:00
|
|
|
|
|
|
|
memset(a, 0, sizeof a);
|
2016-11-30 20:01:28 +03:00
|
|
|
a[0] = (double)(box[2] - box[0]) / xsize;
|
|
|
|
a[4] = (double)(box[3] - box[1]) / ysize;
|
|
|
|
a[2] = box[0];
|
|
|
|
a[5] = box[1];
|
2014-11-04 12:31:36 +03:00
|
|
|
|
2017-08-06 13:32:46 +03:00
|
|
|
imOut = ImagingNewDirty(imIn->mode, xsize, ysize);
|
2014-11-04 12:31:36 +03:00
|
|
|
|
2016-06-02 15:47:27 +03:00
|
|
|
imOut = ImagingTransform(
|
|
|
|
imOut, imIn, IMAGING_TRANSFORM_AFFINE, 0, 0, xsize, ysize, a, filter, 1);
|
2014-11-04 12:31:36 +03:00
|
|
|
} else {
|
2016-11-30 20:01:28 +03:00
|
|
|
imOut = ImagingResample(imIn, xsize, ysize, filter, box);
|
2014-11-04 12:31:36 +03:00
|
|
|
}
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
return PyImagingNew(imOut);
|
|
|
|
}
|
|
|
|
|
2019-11-24 04:13:48 +03:00
|
|
|
static PyObject *
|
|
|
|
_reduce(ImagingObject *self, PyObject *args) {
|
|
|
|
Imaging imIn;
|
|
|
|
Imaging imOut;
|
|
|
|
|
|
|
|
int xscale, yscale;
|
2019-12-02 04:32:08 +03:00
|
|
|
int box[4] = {0, 0, 0, 0};
|
2019-11-24 04:13:48 +03:00
|
|
|
|
|
|
|
imIn = self->image;
|
2019-12-02 04:32:08 +03:00
|
|
|
box[2] = imIn->xsize;
|
|
|
|
box[3] = imIn->ysize;
|
2019-11-24 04:13:48 +03:00
|
|
|
|
2019-12-02 04:32:08 +03:00
|
|
|
if (!PyArg_ParseTuple(
|
|
|
|
args,
|
|
|
|
"(ii)|(iiii)",
|
|
|
|
&xscale,
|
|
|
|
&yscale,
|
2020-05-10 12:56:36 +03:00
|
|
|
&box[0],
|
|
|
|
&box[1],
|
|
|
|
&box[2],
|
|
|
|
&box[3])) {
|
2019-11-24 04:13:48 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2019-11-24 04:13:48 +03:00
|
|
|
|
|
|
|
if (xscale < 1 || yscale < 1) {
|
|
|
|
return ImagingError_ValueError("scale must be > 0");
|
|
|
|
}
|
|
|
|
|
2019-12-02 04:32:08 +03:00
|
|
|
if (box[0] < 0 || box[1] < 0) {
|
|
|
|
return ImagingError_ValueError("box offset can't be negative");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (box[2] > imIn->xsize || box[3] > imIn->ysize) {
|
|
|
|
return ImagingError_ValueError("box can't exceed original image size");
|
|
|
|
}
|
|
|
|
|
2019-12-05 03:24:38 +03:00
|
|
|
if (box[2] <= box[0] || box[3] <= box[1]) {
|
2019-12-02 04:32:08 +03:00
|
|
|
return ImagingError_ValueError("box can't be empty");
|
|
|
|
}
|
|
|
|
|
2019-11-25 23:34:52 +03:00
|
|
|
if (xscale == 1 && yscale == 1) {
|
2019-12-02 04:32:08 +03:00
|
|
|
imOut = ImagingCrop(imIn, box[0], box[1], box[2], box[3]);
|
2019-11-25 23:34:52 +03:00
|
|
|
} else {
|
2019-12-02 04:32:08 +03:00
|
|
|
// Change box format: (left, top, width, height)
|
|
|
|
box[2] -= box[0];
|
|
|
|
box[3] -= box[1];
|
|
|
|
imOut = ImagingReduce(imIn, xscale, yscale, box);
|
2019-11-25 23:34:52 +03:00
|
|
|
}
|
2019-11-24 04:13:48 +03:00
|
|
|
|
|
|
|
return PyImagingNew(imOut);
|
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
#define IS_RGB(mode) \
|
|
|
|
(!strcmp(mode, "RGB") || !strcmp(mode, "RGBA") || !strcmp(mode, "RGBX"))
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
im_setmode(ImagingObject *self, PyObject *args) {
|
|
|
|
/* attempt to modify the mode of an image in place */
|
|
|
|
|
|
|
|
Imaging im;
|
|
|
|
|
|
|
|
char *mode;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t modelen;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "s#:setmode", &mode, &modelen)) {
|
2019-11-24 04:13:48 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
im = self->image;
|
|
|
|
|
|
|
|
/* move all logic in here to the libImaging primitive */
|
|
|
|
|
|
|
|
if (!strcmp(im->mode, mode)) {
|
|
|
|
; /* same mode; always succeeds */
|
|
|
|
} else if (IS_RGB(im->mode) && IS_RGB(mode)) {
|
|
|
|
/* color to color */
|
|
|
|
strcpy(im->mode, mode);
|
|
|
|
im->bands = modelen;
|
2020-05-11 00:46:12 +03:00
|
|
|
if (!strcmp(mode, "RGBA")) {
|
2010-07-31 06:52:47 +04:00
|
|
|
(void)ImagingFillBand(im, 3, 255);
|
2020-05-11 00:46:12 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
} else {
|
|
|
|
/* trying doing an in-place conversion */
|
2020-05-11 00:46:12 +03:00
|
|
|
if (!ImagingConvertInPlace(im, mode)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-11 00:46:12 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (self->access) {
|
2010-07-31 06:52:47 +04:00
|
|
|
ImagingAccessDelete(im, self->access);
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
self->access = ImagingAccessNew(im);
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_transform2(ImagingObject *self, PyObject *args) {
|
|
|
|
static const char *wrong_number = "wrong number of matrix entries";
|
|
|
|
|
|
|
|
Imaging imOut;
|
2016-03-16 14:47:18 +03:00
|
|
|
Py_ssize_t n;
|
2010-07-31 06:52:47 +04:00
|
|
|
double *a;
|
|
|
|
|
|
|
|
ImagingObject *imagep;
|
|
|
|
int x0, y0, x1, y1;
|
|
|
|
int method;
|
|
|
|
PyObject *data;
|
|
|
|
int filter = IMAGING_TRANSFORM_NEAREST;
|
|
|
|
int fill = 1;
|
|
|
|
if (!PyArg_ParseTuple(
|
|
|
|
args,
|
|
|
|
"(iiii)O!iO|ii",
|
|
|
|
&x0,
|
|
|
|
&y0,
|
|
|
|
&x1,
|
|
|
|
&y1,
|
2017-11-11 19:31:37 +03:00
|
|
|
&Imaging_Type,
|
|
|
|
&imagep,
|
2010-07-31 06:52:47 +04:00
|
|
|
&method,
|
|
|
|
&data,
|
2020-05-10 12:56:36 +03:00
|
|
|
&filter,
|
|
|
|
&fill)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
switch (method) {
|
|
|
|
case IMAGING_TRANSFORM_AFFINE:
|
|
|
|
n = 6;
|
|
|
|
break;
|
|
|
|
case IMAGING_TRANSFORM_PERSPECTIVE:
|
|
|
|
n = 8;
|
|
|
|
break;
|
|
|
|
case IMAGING_TRANSFORM_QUAD:
|
|
|
|
n = 8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
n = -1; /* force error */
|
|
|
|
}
|
|
|
|
|
|
|
|
a = getlist(data, &n, wrong_number, TYPE_DOUBLE);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!a) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-06-02 15:47:27 +03:00
|
|
|
imOut = ImagingTransform(
|
|
|
|
self->image, imagep->image, method, x0, y0, x1, y1, a, filter, fill);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
free(a);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!imOut) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_transpose(ImagingObject *self, PyObject *args) {
|
|
|
|
Imaging imIn;
|
|
|
|
Imaging imOut;
|
|
|
|
|
|
|
|
int op;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "i", &op)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
imIn = self->image;
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
switch (op) {
|
|
|
|
case 0: /* flip left right */
|
|
|
|
case 1: /* flip top bottom */
|
|
|
|
case 3: /* rotate 180 */
|
2017-08-06 13:32:46 +03:00
|
|
|
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
2010-07-31 06:52:47 +04:00
|
|
|
break;
|
|
|
|
case 2: /* rotate 90 */
|
|
|
|
case 4: /* rotate 270 */
|
2014-11-07 03:37:12 +03:00
|
|
|
case 5: /* transpose */
|
2017-09-11 22:58:22 +03:00
|
|
|
case 6: /* transverse */
|
2017-08-06 13:32:46 +03:00
|
|
|
imOut = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize);
|
2010-07-31 06:52:47 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
PyErr_SetString(PyExc_ValueError, "No such transpose operation");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (imOut) {
|
2010-07-31 06:52:47 +04:00
|
|
|
switch (op) {
|
|
|
|
case 0:
|
|
|
|
(void)ImagingFlipLeftRight(imOut, imIn);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
(void)ImagingFlipTopBottom(imOut, imIn);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
(void)ImagingRotate90(imOut, imIn);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
(void)ImagingRotate180(imOut, imIn);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
(void)ImagingRotate270(imOut, imIn);
|
|
|
|
break;
|
2014-11-07 03:37:12 +03:00
|
|
|
case 5:
|
|
|
|
(void)ImagingTranspose(imOut, imIn);
|
|
|
|
break;
|
2017-09-11 01:47:47 +03:00
|
|
|
case 6:
|
2017-09-11 22:58:22 +03:00
|
|
|
(void)ImagingTransverse(imOut, imIn);
|
2017-09-11 01:47:47 +03:00
|
|
|
break;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(imOut);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WITH_UNSHARPMASK
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_unsharp_mask(ImagingObject *self, PyObject *args) {
|
|
|
|
Imaging imIn;
|
|
|
|
Imaging imOut;
|
|
|
|
|
|
|
|
float radius;
|
|
|
|
int percent, threshold;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "fii", &radius, &percent, &threshold)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
imIn = self->image;
|
2017-08-06 13:32:46 +03:00
|
|
|
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!imOut) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!ImagingUnsharpMask(imOut, imIn, radius, percent, threshold)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(imOut);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-10-12 16:30:00 +04:00
|
|
|
static PyObject *
|
|
|
|
_box_blur(ImagingObject *self, PyObject *args) {
|
|
|
|
Imaging imIn;
|
|
|
|
Imaging imOut;
|
|
|
|
|
2023-08-12 05:09:20 +03:00
|
|
|
float xradius, yradius;
|
2014-10-19 00:14:26 +04:00
|
|
|
int n = 1;
|
2023-08-12 05:09:20 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "(ff)|i", &xradius, &yradius, &n)) {
|
2014-10-12 16:30:00 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-10-12 16:30:00 +04:00
|
|
|
|
|
|
|
imIn = self->image;
|
2017-08-06 13:32:46 +03:00
|
|
|
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!imOut) {
|
2014-10-12 16:30:00 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-10-12 16:30:00 +04:00
|
|
|
|
2023-08-12 05:09:20 +03:00
|
|
|
if (!ImagingBoxBlur(imOut, imIn, xradius, yradius, n)) {
|
2018-09-13 13:22:11 +03:00
|
|
|
ImagingDelete(imOut);
|
2014-10-12 16:30:00 +04:00
|
|
|
return NULL;
|
2018-09-13 13:22:11 +03:00
|
|
|
}
|
2014-10-12 16:30:00 +04:00
|
|
|
|
|
|
|
return PyImagingNew(imOut);
|
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2021-05-11 13:19:17 +03:00
|
|
|
_isblock(ImagingObject *self) {
|
2017-10-02 11:49:48 +03:00
|
|
|
return PyBool_FromLong(self->image->block != NULL);
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2023-04-29 08:02:11 +03:00
|
|
|
_getbbox(ImagingObject *self, PyObject *args) {
|
2010-07-31 06:52:47 +04:00
|
|
|
int bbox[4];
|
2023-04-29 08:02:11 +03:00
|
|
|
|
2023-04-29 12:11:02 +03:00
|
|
|
int alpha_only = 1;
|
|
|
|
if (!PyArg_ParseTuple(args, "|i", &alpha_only)) {
|
2023-04-29 08:02:11 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-04-29 12:11:02 +03:00
|
|
|
if (!ImagingGetBBox(self->image, bbox, alpha_only)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return Py_BuildValue("iiii", bbox[0], bbox[1], bbox[2], bbox[3]);
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_getcolors(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingColorItem *items;
|
|
|
|
int i, colors;
|
|
|
|
PyObject *out;
|
|
|
|
|
|
|
|
int maxcolors = 256;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "i:getcolors", &maxcolors)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
items = ImagingGetColors(self->image, maxcolors, &colors);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!items) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
if (colors > maxcolors) {
|
|
|
|
out = Py_None;
|
|
|
|
Py_INCREF(out);
|
|
|
|
} else {
|
|
|
|
out = PyList_New(colors);
|
2023-03-10 09:37:06 +03:00
|
|
|
if (out == NULL) {
|
2023-03-29 23:54:01 +03:00
|
|
|
free(items);
|
2023-03-10 09:37:06 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
for (i = 0; i < colors; i++) {
|
|
|
|
ImagingColorItem *v = &items[i];
|
|
|
|
PyObject *item = Py_BuildValue(
|
|
|
|
"iN", v->count, getpixel(self->image, self->access, v->x, v->y));
|
|
|
|
PyList_SetItem(out, i, item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(items);
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2021-05-11 13:19:17 +03:00
|
|
|
_getextrema(ImagingObject *self) {
|
2010-07-31 06:52:47 +04:00
|
|
|
union {
|
|
|
|
UINT8 u[2];
|
|
|
|
INT32 i[2];
|
|
|
|
FLOAT32 f[2];
|
2018-09-17 18:30:42 +03:00
|
|
|
UINT16 s[2];
|
2010-07-31 06:52:47 +04:00
|
|
|
} extrema;
|
|
|
|
int status;
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
status = ImagingGetExtrema(self->image, &extrema);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (status < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (status) {
|
2010-07-31 06:52:47 +04:00
|
|
|
switch (self->image->type) {
|
|
|
|
case IMAGING_TYPE_UINT8:
|
2013-03-08 22:16:22 +04:00
|
|
|
return Py_BuildValue("BB", extrema.u[0], extrema.u[1]);
|
2010-07-31 06:52:47 +04:00
|
|
|
case IMAGING_TYPE_INT32:
|
|
|
|
return Py_BuildValue("ii", extrema.i[0], extrema.i[1]);
|
|
|
|
case IMAGING_TYPE_FLOAT32:
|
|
|
|
return Py_BuildValue("dd", extrema.f[0], extrema.f[1]);
|
2018-09-17 18:30:42 +03:00
|
|
|
case IMAGING_TYPE_SPECIAL:
|
|
|
|
if (strcmp(self->image->mode, "I;16") == 0) {
|
|
|
|
return Py_BuildValue("HH", extrema.s[0], extrema.s[1]);
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2021-05-11 13:19:17 +03:00
|
|
|
_getprojection(ImagingObject *self) {
|
2010-07-31 06:52:47 +04:00
|
|
|
unsigned char *xprofile;
|
|
|
|
unsigned char *yprofile;
|
|
|
|
PyObject *result;
|
|
|
|
|
2016-03-16 14:47:18 +03:00
|
|
|
/* malloc check ok */
|
2010-07-31 06:52:47 +04:00
|
|
|
xprofile = malloc(self->image->xsize);
|
|
|
|
yprofile = malloc(self->image->ysize);
|
|
|
|
|
|
|
|
if (xprofile == NULL || yprofile == NULL) {
|
2013-11-26 04:25:06 +04:00
|
|
|
free(xprofile);
|
|
|
|
free(yprofile);
|
2020-12-20 05:00:10 +03:00
|
|
|
return ImagingError_MemoryError();
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ImagingGetProjection(
|
|
|
|
self->image, (unsigned char *)xprofile, (unsigned char *)yprofile);
|
|
|
|
|
2019-09-26 15:12:28 +03:00
|
|
|
result = Py_BuildValue(
|
|
|
|
"y#y#",
|
2019-03-26 05:50:57 +03:00
|
|
|
xprofile,
|
|
|
|
(Py_ssize_t)self->image->xsize,
|
|
|
|
yprofile,
|
|
|
|
(Py_ssize_t)self->image->ysize);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
free(xprofile);
|
|
|
|
free(yprofile);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_getband(ImagingObject *self, PyObject *args) {
|
|
|
|
int band;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "i", &band)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingGetBand(self->image, band));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_fillband(ImagingObject *self, PyObject *args) {
|
|
|
|
int band;
|
|
|
|
int color;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "ii", &band, &color)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!ImagingFillBand(self->image, band, color)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_putband(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
int band;
|
|
|
|
if (!PyArg_ParseTuple(args, "O!i", &Imaging_Type, &imagep, &band)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!ImagingPutBand(self->image, imagep->image, band)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2017-08-12 19:08:07 +03:00
|
|
|
static PyObject *
|
|
|
|
_merge(PyObject *self, PyObject *args) {
|
|
|
|
char *mode;
|
|
|
|
ImagingObject *band0 = NULL;
|
|
|
|
ImagingObject *band1 = NULL;
|
|
|
|
ImagingObject *band2 = NULL;
|
|
|
|
ImagingObject *band3 = NULL;
|
|
|
|
Imaging bands[4] = {NULL, NULL, NULL, NULL};
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(
|
|
|
|
args,
|
|
|
|
"sO!|O!O!O!",
|
|
|
|
&mode,
|
|
|
|
&Imaging_Type,
|
|
|
|
&band0,
|
|
|
|
&Imaging_Type,
|
|
|
|
&band1,
|
2020-05-10 12:56:36 +03:00
|
|
|
&Imaging_Type,
|
|
|
|
&band2,
|
|
|
|
&Imaging_Type,
|
|
|
|
&band3)) {
|
2017-08-12 19:08:07 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2017-08-12 19:08:07 +03:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (band0) {
|
|
|
|
bands[0] = band0->image;
|
|
|
|
}
|
|
|
|
if (band1) {
|
|
|
|
bands[1] = band1->image;
|
|
|
|
}
|
|
|
|
if (band2) {
|
|
|
|
bands[2] = band2->image;
|
|
|
|
}
|
|
|
|
if (band3) {
|
|
|
|
bands[3] = band3->image;
|
|
|
|
}
|
2017-08-12 19:08:07 +03:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingMerge(mode, bands));
|
|
|
|
}
|
|
|
|
|
2017-08-12 03:43:19 +03:00
|
|
|
static PyObject *
|
2021-05-11 13:19:17 +03:00
|
|
|
_split(ImagingObject *self) {
|
2017-08-12 03:43:19 +03:00
|
|
|
int fails = 0;
|
|
|
|
Py_ssize_t i;
|
|
|
|
PyObject *list;
|
|
|
|
PyObject *imaging_object;
|
|
|
|
Imaging bands[4] = {NULL, NULL, NULL, NULL};
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!ImagingSplit(self->image, bands)) {
|
2017-08-12 03:43:19 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2017-08-12 03:43:19 +03:00
|
|
|
|
|
|
|
list = PyTuple_New(self->image->bands);
|
|
|
|
for (i = 0; i < self->image->bands; i++) {
|
|
|
|
imaging_object = PyImagingNew(bands[i]);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!imaging_object) {
|
2017-08-12 03:43:19 +03:00
|
|
|
fails += 1;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2017-08-12 03:43:19 +03:00
|
|
|
PyTuple_SET_ITEM(list, i, imaging_object);
|
|
|
|
}
|
|
|
|
if (fails) {
|
|
|
|
Py_DECREF(list);
|
|
|
|
list = NULL;
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
#ifdef WITH_IMAGECHOPS
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2021-05-11 13:19:17 +03:00
|
|
|
_chop_invert(ImagingObject *self) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return PyImagingNew(ImagingNegative(self->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_lighter(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopLighter(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_darker(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopDarker(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_difference(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopDifference(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_multiply(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopMultiply(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_screen(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopScreen(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_add(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
float scale;
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
scale = 1.0;
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "O!|fi", &Imaging_Type, &imagep, &scale, &offset)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopAdd(self->image, imagep->image, scale, offset));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_subtract(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
float scale;
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
scale = 1.0;
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "O!|fi", &Imaging_Type, &imagep, &scale, &offset)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopSubtract(self->image, imagep->image, scale, offset));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_and(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopAnd(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_or(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopOr(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_xor(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopXor(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_add_modulo(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopAddModulo(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_chop_subtract_modulo(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopSubtractModulo(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
2019-11-22 16:03:59 +03:00
|
|
|
static PyObject *
|
2019-12-25 22:23:32 +03:00
|
|
|
_chop_soft_light(ImagingObject *self, PyObject *args) {
|
2019-11-22 16:03:59 +03:00
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2019-11-22 16:03:59 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2019-11-22 16:03:59 +03:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopSoftLight(self->image, imagep->image));
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
2019-12-25 22:23:32 +03:00
|
|
|
_chop_hard_light(ImagingObject *self, PyObject *args) {
|
2019-11-22 16:03:59 +03:00
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2019-11-22 16:03:59 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2019-11-22 16:03:59 +03:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingChopHardLight(self->image, imagep->image));
|
|
|
|
}
|
2019-11-22 16:30:43 +03:00
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_chop_overlay(ImagingObject *self, PyObject *args) {
|
|
|
|
ImagingObject *imagep;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
|
2019-11-22 16:30:43 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2019-11-22 16:30:43 +03:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingOverlay(self->image, imagep->image));
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
#ifdef WITH_IMAGEDRAW
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_font_new(PyObject *self_, PyObject *args) {
|
|
|
|
ImagingFontObject *self;
|
|
|
|
int i, y0, y1;
|
|
|
|
static const char *wrong_length = "descriptor table has wrong size";
|
|
|
|
|
|
|
|
ImagingObject *imagep;
|
|
|
|
unsigned char *glyphdata;
|
2019-03-26 05:50:57 +03:00
|
|
|
Py_ssize_t glyphdata_length;
|
2019-09-26 15:12:28 +03:00
|
|
|
if (!PyArg_ParseTuple(
|
2020-05-10 12:56:36 +03:00
|
|
|
args, "O!y#", &Imaging_Type, &imagep, &glyphdata, &glyphdata_length)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
if (glyphdata_length != 256 * 20) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError, wrong_length);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
self = PyObject_New(ImagingFontObject, &ImagingFont_Type);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (self == NULL) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* glyph bitmap */
|
|
|
|
self->bitmap = imagep->image;
|
|
|
|
|
|
|
|
y0 = y1 = 0;
|
|
|
|
|
|
|
|
/* glyph glyphs */
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
self->glyphs[i].dx = S16(B16(glyphdata, 0));
|
|
|
|
self->glyphs[i].dy = S16(B16(glyphdata, 2));
|
|
|
|
self->glyphs[i].dx0 = S16(B16(glyphdata, 4));
|
|
|
|
self->glyphs[i].dy0 = S16(B16(glyphdata, 6));
|
|
|
|
self->glyphs[i].dx1 = S16(B16(glyphdata, 8));
|
|
|
|
self->glyphs[i].dy1 = S16(B16(glyphdata, 10));
|
|
|
|
self->glyphs[i].sx0 = S16(B16(glyphdata, 12));
|
|
|
|
self->glyphs[i].sy0 = S16(B16(glyphdata, 14));
|
|
|
|
self->glyphs[i].sx1 = S16(B16(glyphdata, 16));
|
|
|
|
self->glyphs[i].sy1 = S16(B16(glyphdata, 18));
|
2020-05-10 12:56:36 +03:00
|
|
|
if (self->glyphs[i].dy0 < y0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
y0 = self->glyphs[i].dy0;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
|
|
|
if (self->glyphs[i].dy1 > y1) {
|
2010-07-31 06:52:47 +04:00
|
|
|
y1 = self->glyphs[i].dy1;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
glyphdata += 20;
|
|
|
|
}
|
|
|
|
|
|
|
|
self->baseline = -y0;
|
|
|
|
self->ysize = y1 - y0;
|
|
|
|
|
|
|
|
/* keep a reference to the bitmap object */
|
|
|
|
Py_INCREF(imagep);
|
|
|
|
self->ref = imagep;
|
|
|
|
|
|
|
|
return (PyObject *)self;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_font_dealloc(ImagingFontObject *self) {
|
|
|
|
Py_XDECREF(self->ref);
|
|
|
|
PyObject_Del(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
textwidth(ImagingFontObject *self, const unsigned char *text) {
|
|
|
|
int xsize;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
for (xsize = 0; *text; text++) {
|
2010-07-31 06:52:47 +04:00
|
|
|
xsize += self->glyphs[*text].dx;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return xsize;
|
|
|
|
}
|
|
|
|
|
2014-02-05 09:16:19 +04:00
|
|
|
void
|
|
|
|
_font_text_asBytes(PyObject *encoded_string, unsigned char **text) {
|
2017-07-18 12:50:40 +03:00
|
|
|
/* Allocates *text, returns a 'new reference'. Caller is required to free */
|
|
|
|
|
2014-02-05 09:34:24 +04:00
|
|
|
PyObject *bytes = NULL;
|
2017-08-14 17:28:06 +03:00
|
|
|
Py_ssize_t len = 0;
|
2017-07-18 12:50:40 +03:00
|
|
|
char *buffer;
|
2014-02-05 09:34:24 +04:00
|
|
|
|
|
|
|
*text = NULL;
|
2014-02-05 09:16:19 +04:00
|
|
|
|
|
|
|
if (PyUnicode_CheckExact(encoded_string)) {
|
|
|
|
bytes = PyUnicode_AsLatin1String(encoded_string);
|
2017-11-02 23:46:17 +03:00
|
|
|
if (!bytes) {
|
|
|
|
return;
|
|
|
|
}
|
2017-07-18 12:50:40 +03:00
|
|
|
PyBytes_AsStringAndSize(bytes, &buffer, &len);
|
2014-02-05 09:34:24 +04:00
|
|
|
} else if (PyBytes_Check(encoded_string)) {
|
2017-07-18 12:50:40 +03:00
|
|
|
PyBytes_AsStringAndSize(encoded_string, &buffer, &len);
|
2014-02-05 09:16:19 +04:00
|
|
|
}
|
2017-07-18 12:50:40 +03:00
|
|
|
|
2017-11-02 15:56:08 +03:00
|
|
|
*text = calloc(len + 1, 1);
|
2017-10-04 13:56:20 +03:00
|
|
|
if (*text) {
|
|
|
|
memcpy(*text, buffer, len);
|
2017-11-02 23:46:17 +03:00
|
|
|
} else {
|
|
|
|
ImagingError_MemoryError();
|
2014-05-27 17:58:26 +04:00
|
|
|
}
|
2017-11-02 23:46:17 +03:00
|
|
|
if (bytes) {
|
2017-10-04 13:56:20 +03:00
|
|
|
Py_DECREF(bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
2014-02-05 09:16:19 +04:00
|
|
|
}
|
2014-05-27 17:58:26 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
static PyObject *
|
|
|
|
_font_getmask(ImagingFontObject *self, PyObject *args) {
|
|
|
|
Imaging im;
|
|
|
|
Imaging bitmap;
|
|
|
|
int x, b;
|
2014-02-05 08:41:27 +04:00
|
|
|
int i = 0;
|
2010-07-31 06:52:47 +04:00
|
|
|
int status;
|
|
|
|
Glyph *glyph;
|
|
|
|
|
2014-02-05 09:16:19 +04:00
|
|
|
PyObject *encoded_string;
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
unsigned char *text;
|
|
|
|
char *mode = "";
|
2014-02-05 09:16:19 +04:00
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "O|s:getmask", &encoded_string, &mode)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
_font_text_asBytes(encoded_string, &text);
|
|
|
|
if (!text) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2014-02-05 08:41:27 +04:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
im = ImagingNew(self->bitmap->mode, textwidth(self, text), self->ysize);
|
2014-02-05 08:41:27 +04:00
|
|
|
if (!im) {
|
2017-07-18 12:50:40 +03:00
|
|
|
free(text);
|
2020-12-20 04:28:52 +03:00
|
|
|
return ImagingError_MemoryError();
|
2014-02-05 08:41:27 +04:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
b = 0;
|
|
|
|
(void)ImagingFill(im, &b);
|
|
|
|
|
|
|
|
b = self->baseline;
|
2014-02-05 08:41:27 +04:00
|
|
|
for (x = 0; text[i]; i++) {
|
|
|
|
glyph = &self->glyphs[text[i]];
|
2010-07-31 06:52:47 +04:00
|
|
|
bitmap =
|
|
|
|
ImagingCrop(self->bitmap, glyph->sx0, glyph->sy0, glyph->sx1, glyph->sy1);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!bitmap) {
|
2010-07-31 06:52:47 +04:00
|
|
|
goto failed;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
status = ImagingPaste(
|
|
|
|
im,
|
|
|
|
bitmap,
|
|
|
|
NULL,
|
|
|
|
glyph->dx0 + x,
|
|
|
|
glyph->dy0 + b,
|
|
|
|
glyph->dx1 + x,
|
|
|
|
glyph->dy1 + b);
|
|
|
|
ImagingDelete(bitmap);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (status < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
goto failed;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
x = x + glyph->dx;
|
|
|
|
b = b + glyph->dy;
|
|
|
|
}
|
2017-07-18 12:50:40 +03:00
|
|
|
free(text);
|
2010-07-31 06:52:47 +04:00
|
|
|
return PyImagingNew(im);
|
|
|
|
|
|
|
|
failed:
|
2017-07-18 12:50:40 +03:00
|
|
|
free(text);
|
2010-07-31 06:52:47 +04:00
|
|
|
ImagingDelete(im);
|
2017-10-04 14:08:41 +03:00
|
|
|
Py_RETURN_NONE;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_font_getsize(ImagingFontObject *self, PyObject *args) {
|
|
|
|
unsigned char *text;
|
2014-02-05 09:16:19 +04:00
|
|
|
PyObject *encoded_string;
|
2017-07-18 12:50:40 +03:00
|
|
|
PyObject *val;
|
2014-02-05 09:16:19 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O:getsize", &encoded_string)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2014-02-05 09:16:19 +04:00
|
|
|
_font_text_asBytes(encoded_string, &text);
|
|
|
|
if (!text) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-07-18 12:50:40 +03:00
|
|
|
val = Py_BuildValue("ii", textwidth(self, text), self->ysize);
|
|
|
|
free(text);
|
|
|
|
return val;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct PyMethodDef _font_methods[] = {
|
2021-05-11 13:16:44 +03:00
|
|
|
{"getmask", (PyCFunction)_font_getmask, METH_VARARGS},
|
|
|
|
{"getsize", (PyCFunction)_font_getsize, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_draw_new(PyObject *self_, PyObject *args) {
|
|
|
|
ImagingDrawObject *self;
|
|
|
|
|
|
|
|
ImagingObject *imagep;
|
|
|
|
int blend = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O!|i", &Imaging_Type, &imagep, &blend)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
self = PyObject_New(ImagingDrawObject, &ImagingDraw_Type);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (self == NULL) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* keep a reference to the image object */
|
|
|
|
Py_INCREF(imagep);
|
|
|
|
self->image = imagep;
|
|
|
|
|
|
|
|
self->ink[0] = self->ink[1] = self->ink[2] = self->ink[3] = 0;
|
|
|
|
|
|
|
|
self->blend = blend;
|
|
|
|
|
|
|
|
return (PyObject *)self;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_draw_dealloc(ImagingDrawObject *self) {
|
|
|
|
Py_XDECREF(self->image);
|
|
|
|
PyObject_Del(self);
|
|
|
|
}
|
|
|
|
|
2016-03-16 14:37:49 +03:00
|
|
|
extern Py_ssize_t
|
|
|
|
PyPath_Flatten(PyObject *data, double **xy);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_ink(ImagingDrawObject *self, PyObject *args) {
|
|
|
|
INT32 ink = 0;
|
|
|
|
PyObject *color;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "O", &color)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!getink(color, self->image->image, (char *)&ink)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2019-09-26 15:12:28 +03:00
|
|
|
return PyLong_FromLong((int)ink);
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_arc(ImagingDrawObject *self, PyObject *args) {
|
2014-05-27 17:58:26 +04:00
|
|
|
double *xy;
|
2016-03-16 14:37:49 +03:00
|
|
|
Py_ssize_t n;
|
2014-05-27 17:58:26 +04:00
|
|
|
|
|
|
|
PyObject *data;
|
2010-07-31 06:52:47 +04:00
|
|
|
int ink;
|
2018-04-13 08:37:54 +03:00
|
|
|
int width = 0;
|
2015-12-08 16:28:52 +03:00
|
|
|
float start, end;
|
2020-06-29 17:21:33 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "Offi|i", &data, &start, &end, &ink, &width)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2014-05-27 17:58:26 +04:00
|
|
|
n = PyPath_Flatten(data, &xy);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2014-05-27 17:58:26 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-05-27 17:58:26 +04:00
|
|
|
if (n != 2) {
|
2016-04-12 10:51:55 +03:00
|
|
|
PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
|
2018-09-13 13:22:11 +03:00
|
|
|
free(xy);
|
2014-05-27 17:58:26 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2023-03-01 14:06:40 +03:00
|
|
|
if (xy[2] < xy[0]) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, incorrectly_ordered_x_coordinate);
|
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (xy[3] < xy[1]) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, incorrectly_ordered_y_coordinate);
|
2023-03-01 03:22:35 +03:00
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-05-27 17:58:26 +04:00
|
|
|
|
|
|
|
n = ImagingDrawArc(
|
|
|
|
self->image->image,
|
|
|
|
(int)xy[0],
|
|
|
|
(int)xy[1],
|
|
|
|
(int)xy[2],
|
|
|
|
(int)xy[3],
|
2020-06-29 17:21:33 +03:00
|
|
|
start,
|
|
|
|
end,
|
|
|
|
&ink,
|
|
|
|
width,
|
|
|
|
self->blend);
|
2014-05-27 17:58:26 +04:00
|
|
|
|
|
|
|
free(xy);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_bitmap(ImagingDrawObject *self, PyObject *args) {
|
|
|
|
double *xy;
|
2016-03-16 14:37:49 +03:00
|
|
|
Py_ssize_t n;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
PyObject *data;
|
|
|
|
ImagingObject *bitmap;
|
|
|
|
int ink;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "OO!i", &data, &Imaging_Type, &bitmap, &ink)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
n = PyPath_Flatten(data, &xy);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
if (n != 1) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(
|
|
|
|
PyExc_TypeError, "coordinate list must contain exactly 1 coordinate");
|
2018-09-13 13:22:11 +03:00
|
|
|
free(xy);
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
n = ImagingDrawBitmap(
|
|
|
|
self->image->image, (int)xy[0], (int)xy[1], bitmap->image, &ink, self->blend);
|
|
|
|
|
|
|
|
free(xy);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_chord(ImagingDrawObject *self, PyObject *args) {
|
2014-05-27 17:58:26 +04:00
|
|
|
double *xy;
|
2016-03-16 14:37:49 +03:00
|
|
|
Py_ssize_t n;
|
2014-05-27 17:58:26 +04:00
|
|
|
|
|
|
|
PyObject *data;
|
2010-07-31 06:52:47 +04:00
|
|
|
int ink, fill;
|
2018-04-13 08:37:54 +03:00
|
|
|
int width = 0;
|
2015-12-08 16:28:52 +03:00
|
|
|
float start, end;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "Offii|i", &data, &start, &end, &ink, &fill, &width)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2014-05-27 17:58:26 +04:00
|
|
|
n = PyPath_Flatten(data, &xy);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2014-05-27 17:58:26 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-05-27 17:58:26 +04:00
|
|
|
if (n != 2) {
|
2016-04-12 10:51:55 +03:00
|
|
|
PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
|
2018-09-13 13:22:11 +03:00
|
|
|
free(xy);
|
2014-05-27 17:58:26 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2023-03-01 14:06:40 +03:00
|
|
|
if (xy[2] < xy[0]) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, incorrectly_ordered_x_coordinate);
|
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (xy[3] < xy[1]) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, incorrectly_ordered_y_coordinate);
|
2023-03-01 03:22:35 +03:00
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-05-27 17:58:26 +04:00
|
|
|
|
|
|
|
n = ImagingDrawChord(
|
|
|
|
self->image->image,
|
|
|
|
(int)xy[0],
|
|
|
|
(int)xy[1],
|
|
|
|
(int)xy[2],
|
|
|
|
(int)xy[3],
|
2018-04-13 08:37:54 +03:00
|
|
|
start,
|
|
|
|
end,
|
|
|
|
&ink,
|
|
|
|
fill,
|
|
|
|
width,
|
|
|
|
self->blend);
|
2014-05-27 17:58:26 +04:00
|
|
|
|
|
|
|
free(xy);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_ellipse(ImagingDrawObject *self, PyObject *args) {
|
|
|
|
double *xy;
|
2016-03-16 14:37:49 +03:00
|
|
|
Py_ssize_t n;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
PyObject *data;
|
|
|
|
int ink;
|
|
|
|
int fill = 0;
|
2018-04-13 08:37:54 +03:00
|
|
|
int width = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "Oi|ii", &data, &ink, &fill, &width)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
n = PyPath_Flatten(data, &xy);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
if (n != 2) {
|
2016-04-12 10:51:55 +03:00
|
|
|
PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
|
2018-09-13 13:22:11 +03:00
|
|
|
free(xy);
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
2023-03-01 14:06:40 +03:00
|
|
|
if (xy[2] < xy[0]) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, incorrectly_ordered_x_coordinate);
|
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (xy[3] < xy[1]) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, incorrectly_ordered_y_coordinate);
|
2023-03-01 03:22:35 +03:00
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2014-05-27 17:58:26 +04:00
|
|
|
n = ImagingDrawEllipse(
|
|
|
|
self->image->image,
|
|
|
|
(int)xy[0],
|
|
|
|
(int)xy[1],
|
2013-11-26 04:25:06 +04:00
|
|
|
(int)xy[2],
|
|
|
|
(int)xy[3],
|
2018-04-13 08:37:54 +03:00
|
|
|
&ink,
|
|
|
|
fill,
|
|
|
|
width,
|
|
|
|
self->blend);
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
free(xy);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_lines(ImagingDrawObject *self, PyObject *args) {
|
|
|
|
double *xy;
|
2016-03-16 14:37:49 +03:00
|
|
|
Py_ssize_t i, n;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
PyObject *data;
|
|
|
|
int ink;
|
|
|
|
int width = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &width)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
n = PyPath_Flatten(data, &xy);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
if (width <= 1) {
|
|
|
|
double *p = NULL;
|
2018-04-12 18:15:27 +03:00
|
|
|
for (i = 0; i < n - 1; i++) {
|
2010-07-31 06:52:47 +04:00
|
|
|
p = &xy[i + i];
|
|
|
|
if (ImagingDrawLine(
|
|
|
|
self->image->image,
|
|
|
|
(int)p[0],
|
|
|
|
(int)p[1],
|
|
|
|
(int)p[2],
|
|
|
|
(int)p[3],
|
|
|
|
&ink,
|
|
|
|
self->blend) < 0) {
|
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2020-05-10 12:56:36 +03:00
|
|
|
if (p) { /* draw last point */
|
2010-07-31 06:52:47 +04:00
|
|
|
ImagingDrawPoint(
|
|
|
|
self->image->image, (int)p[2], (int)p[3], &ink, self->blend);
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
} else {
|
|
|
|
for (i = 0; i < n - 1; i++) {
|
|
|
|
double *p = &xy[i + i];
|
|
|
|
if (ImagingDrawWideLine(
|
|
|
|
self->image->image,
|
|
|
|
(int)p[0],
|
|
|
|
(int)p[1],
|
|
|
|
(int)p[2],
|
|
|
|
(int)p[3],
|
|
|
|
&ink,
|
|
|
|
width,
|
|
|
|
self->blend) < 0) {
|
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(xy);
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_points(ImagingDrawObject *self, PyObject *args) {
|
|
|
|
double *xy;
|
2016-03-16 14:37:49 +03:00
|
|
|
Py_ssize_t i, n;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
PyObject *data;
|
|
|
|
int ink;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "Oi", &data, &ink)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
n = PyPath_Flatten(data, &xy);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2013-03-22 18:22:18 +04:00
|
|
|
double *p = &xy[i + i];
|
|
|
|
if (ImagingDrawPoint(
|
|
|
|
self->image->image, (int)p[0], (int)p[1], &ink, self->blend) < 0) {
|
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
free(xy);
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-22 18:22:18 +04:00
|
|
|
#ifdef WITH_ARROW
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* from outline.c */
|
|
|
|
extern ImagingOutline
|
|
|
|
PyOutline_AsOutline(PyObject *outline);
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_outline(ImagingDrawObject *self, PyObject *args) {
|
|
|
|
ImagingOutline outline;
|
|
|
|
|
|
|
|
PyObject *outline_;
|
|
|
|
int ink;
|
|
|
|
int fill = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "Oi|i", &outline_, &ink, &fill)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
outline = PyOutline_AsOutline(outline_);
|
|
|
|
if (!outline) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, "expected outline object");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImagingDrawOutline(self->image->image, outline, &ink, fill, self->blend) < 0) {
|
2020-05-10 12:56:36 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_pieslice(ImagingDrawObject *self, PyObject *args) {
|
2014-05-27 17:58:26 +04:00
|
|
|
double *xy;
|
2016-03-16 14:37:49 +03:00
|
|
|
Py_ssize_t n;
|
2014-05-27 17:58:26 +04:00
|
|
|
|
|
|
|
PyObject *data;
|
2010-07-31 06:52:47 +04:00
|
|
|
int ink, fill;
|
2018-04-13 08:37:54 +03:00
|
|
|
int width = 0;
|
2015-12-08 16:28:52 +03:00
|
|
|
float start, end;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "Offii|i", &data, &start, &end, &ink, &fill, &width)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2014-05-27 17:58:26 +04:00
|
|
|
n = PyPath_Flatten(data, &xy);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2014-05-27 17:58:26 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2014-05-27 17:58:26 +04:00
|
|
|
if (n != 2) {
|
2016-04-12 10:51:55 +03:00
|
|
|
PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
|
2018-09-13 13:22:11 +03:00
|
|
|
free(xy);
|
2014-05-27 17:58:26 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2023-03-01 14:06:40 +03:00
|
|
|
if (xy[2] < xy[0]) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, incorrectly_ordered_x_coordinate);
|
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (xy[3] < xy[1]) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, incorrectly_ordered_y_coordinate);
|
2023-03-01 03:22:35 +03:00
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-05-27 17:58:26 +04:00
|
|
|
|
|
|
|
n = ImagingDrawPieslice(
|
|
|
|
self->image->image,
|
|
|
|
(int)xy[0],
|
|
|
|
(int)xy[1],
|
|
|
|
(int)xy[2],
|
|
|
|
(int)xy[3],
|
2018-04-13 08:37:54 +03:00
|
|
|
start,
|
|
|
|
end,
|
|
|
|
&ink,
|
|
|
|
fill,
|
|
|
|
width,
|
|
|
|
self->blend);
|
2014-05-27 17:58:26 +04:00
|
|
|
|
|
|
|
free(xy);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_polygon(ImagingDrawObject *self, PyObject *args) {
|
|
|
|
double *xy;
|
|
|
|
int *ixy;
|
2016-03-16 14:37:49 +03:00
|
|
|
Py_ssize_t n, i;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
PyObject *data;
|
|
|
|
int ink;
|
|
|
|
int fill = 0;
|
2021-11-16 14:02:54 +03:00
|
|
|
int width = 0;
|
|
|
|
if (!PyArg_ParseTuple(args, "Oi|ii", &data, &ink, &fill, &width)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
n = PyPath_Flatten(data, &xy);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
if (n < 2) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(
|
|
|
|
PyExc_TypeError, "coordinate list must contain at least 2 coordinates");
|
2018-09-13 13:22:11 +03:00
|
|
|
free(xy);
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy list of vertices to array */
|
2016-03-16 14:47:18 +03:00
|
|
|
ixy = (int *)calloc(n, 2 * sizeof(int));
|
2020-12-20 01:57:55 +03:00
|
|
|
if (ixy == NULL) {
|
|
|
|
free(xy);
|
2020-12-20 06:42:29 +03:00
|
|
|
return ImagingError_MemoryError();
|
2020-12-20 01:57:55 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2013-11-26 04:25:06 +04:00
|
|
|
ixy[i + i] = (int)xy[i + i];
|
|
|
|
ixy[i + i + 1] = (int)xy[i + i + 1];
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
free(xy);
|
|
|
|
|
2021-11-16 14:02:54 +03:00
|
|
|
if (ImagingDrawPolygon(self->image->image, n, ixy, &ink, fill, width, self->blend) < 0) {
|
2013-11-26 04:25:06 +04:00
|
|
|
free(ixy);
|
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
free(ixy);
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_draw_rectangle(ImagingDrawObject *self, PyObject *args) {
|
|
|
|
double *xy;
|
2016-03-16 14:37:49 +03:00
|
|
|
Py_ssize_t n;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
PyObject *data;
|
|
|
|
int ink;
|
|
|
|
int fill = 0;
|
2018-04-12 18:15:27 +03:00
|
|
|
int width = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "Oi|ii", &data, &ink, &fill, &width)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
n = PyPath_Flatten(data, &xy);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
if (n != 2) {
|
2016-04-12 10:51:55 +03:00
|
|
|
PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
|
2018-09-13 13:22:11 +03:00
|
|
|
free(xy);
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
2023-03-01 14:06:40 +03:00
|
|
|
if (xy[2] < xy[0]) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, incorrectly_ordered_x_coordinate);
|
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (xy[3] < xy[1]) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, incorrectly_ordered_y_coordinate);
|
2023-03-01 03:22:35 +03:00
|
|
|
free(xy);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2014-05-27 17:58:26 +04:00
|
|
|
n = ImagingDrawRectangle(
|
|
|
|
self->image->image,
|
2013-11-26 04:25:06 +04:00
|
|
|
(int)xy[0],
|
|
|
|
(int)xy[1],
|
2014-05-27 17:58:26 +04:00
|
|
|
(int)xy[2],
|
|
|
|
(int)xy[3],
|
2018-04-12 18:15:27 +03:00
|
|
|
&ink,
|
|
|
|
fill,
|
|
|
|
width,
|
|
|
|
self->blend);
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
free(xy);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (n < 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct PyMethodDef _draw_methods[] = {
|
|
|
|
#ifdef WITH_IMAGEDRAW
|
|
|
|
/* Graphics (ImageDraw) */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"draw_lines", (PyCFunction)_draw_lines, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#ifdef WITH_ARROW
|
2021-05-11 13:16:44 +03:00
|
|
|
{"draw_outline", (PyCFunction)_draw_outline, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
2021-05-11 13:16:44 +03:00
|
|
|
{"draw_polygon", (PyCFunction)_draw_polygon, METH_VARARGS},
|
|
|
|
{"draw_rectangle", (PyCFunction)_draw_rectangle, METH_VARARGS},
|
|
|
|
{"draw_points", (PyCFunction)_draw_points, METH_VARARGS},
|
|
|
|
{"draw_arc", (PyCFunction)_draw_arc, METH_VARARGS},
|
|
|
|
{"draw_bitmap", (PyCFunction)_draw_bitmap, METH_VARARGS},
|
|
|
|
{"draw_chord", (PyCFunction)_draw_chord, METH_VARARGS},
|
|
|
|
{"draw_ellipse", (PyCFunction)_draw_ellipse, METH_VARARGS},
|
|
|
|
{"draw_pieslice", (PyCFunction)_draw_pieslice, METH_VARARGS},
|
|
|
|
{"draw_ink", (PyCFunction)_draw_ink, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
pixel_access_new(ImagingObject *imagep, PyObject *args) {
|
|
|
|
PixelAccessObject *self;
|
|
|
|
|
|
|
|
int readonly = 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "|i", &readonly)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
self = PyObject_New(PixelAccessObject, &PixelAccess_Type);
|
2020-05-10 12:56:36 +03:00
|
|
|
if (self == NULL) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* keep a reference to the image object */
|
|
|
|
Py_INCREF(imagep);
|
|
|
|
self->image = imagep;
|
|
|
|
|
|
|
|
self->readonly = readonly;
|
|
|
|
|
|
|
|
return (PyObject *)self;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pixel_access_dealloc(PixelAccessObject *self) {
|
|
|
|
Py_XDECREF(self->image);
|
|
|
|
PyObject_Del(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
pixel_access_getitem(PixelAccessObject *self, PyObject *xy) {
|
|
|
|
int x, y;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (_getxy(xy, &x, &y)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return getpixel(self->image->image, self->image->access, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
pixel_access_setitem(PixelAccessObject *self, PyObject *xy, PyObject *color) {
|
|
|
|
Imaging im = self->image->image;
|
|
|
|
char ink[4];
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
if (self->readonly) {
|
|
|
|
(void)ImagingError_ValueError(readonly);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (_getxy(xy, &x, &y)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return -1;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2018-10-15 13:51:24 +03:00
|
|
|
if (x < 0) {
|
|
|
|
x = im->xsize + x;
|
|
|
|
}
|
|
|
|
if (y < 0) {
|
|
|
|
y = im->ysize + y;
|
|
|
|
}
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
|
2013-11-26 04:25:06 +04:00
|
|
|
PyErr_SetString(PyExc_IndexError, outside_image);
|
|
|
|
return -1;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!color) { /* FIXME: raise exception? */
|
2010-07-31 06:52:47 +04:00
|
|
|
return 0;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!getink(color, im, ink)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return -1;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
self->image->access->put_pixel(im, x, y, ink);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2013-03-22 18:22:18 +04:00
|
|
|
/* EFFECTS (experimental) */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
#ifdef WITH_EFFECTS
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_effect_mandelbrot(ImagingObject *self, PyObject *args) {
|
|
|
|
int xsize = 512;
|
|
|
|
int ysize = 512;
|
|
|
|
double extent[4];
|
|
|
|
int quality = 100;
|
|
|
|
|
|
|
|
extent[0] = -3;
|
|
|
|
extent[1] = -2.5;
|
|
|
|
extent[2] = 2;
|
|
|
|
extent[3] = 2.5;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(
|
|
|
|
args,
|
|
|
|
"|(ii)(dddd)i",
|
|
|
|
&xsize,
|
|
|
|
&ysize,
|
|
|
|
&extent[0],
|
|
|
|
&extent[1],
|
|
|
|
&extent[2],
|
|
|
|
&extent[3],
|
2020-05-10 12:56:36 +03:00
|
|
|
&quality)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingEffectMandelbrot(xsize, ysize, extent, quality));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_effect_noise(ImagingObject *self, PyObject *args) {
|
|
|
|
int xsize, ysize;
|
|
|
|
float sigma = 128;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "(ii)|f", &xsize, &ysize, &sigma)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingEffectNoise(xsize, ysize, sigma));
|
|
|
|
}
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_effect_spread(ImagingObject *self, PyObject *args) {
|
|
|
|
int dist;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "i", &dist)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return PyImagingNew(ImagingEffectSpread(self->image, dist));
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2013-03-22 18:22:18 +04:00
|
|
|
/* UTILITIES */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_getcodecstatus(PyObject *self, PyObject *args) {
|
|
|
|
int status;
|
|
|
|
char *msg;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "i", &status)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
switch (status) {
|
|
|
|
case IMAGING_CODEC_OVERRUN:
|
2013-11-26 04:25:06 +04:00
|
|
|
msg = "buffer overrun";
|
|
|
|
break;
|
2010-07-31 06:52:47 +04:00
|
|
|
case IMAGING_CODEC_BROKEN:
|
2013-11-26 04:25:06 +04:00
|
|
|
msg = "broken data stream";
|
|
|
|
break;
|
2010-07-31 06:52:47 +04:00
|
|
|
case IMAGING_CODEC_UNKNOWN:
|
2013-11-26 04:25:06 +04:00
|
|
|
msg = "unrecognized data stream contents";
|
|
|
|
break;
|
2010-07-31 06:52:47 +04:00
|
|
|
case IMAGING_CODEC_CONFIG:
|
2013-11-26 04:25:06 +04:00
|
|
|
msg = "codec configuration error";
|
|
|
|
break;
|
2010-07-31 06:52:47 +04:00
|
|
|
case IMAGING_CODEC_MEMORY:
|
2013-11-26 04:25:06 +04:00
|
|
|
msg = "out of memory";
|
|
|
|
break;
|
2010-07-31 06:52:47 +04:00
|
|
|
default:
|
2012-10-14 08:47:30 +04:00
|
|
|
Py_RETURN_NONE;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2012-10-14 08:47:30 +04:00
|
|
|
return PyUnicode_FromString(msg);
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2013-03-22 18:22:18 +04:00
|
|
|
/* DEBUGGING HELPERS */
|
2010-07-31 06:52:47 +04:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
2013-03-11 23:33:04 +04:00
|
|
|
static PyObject *
|
2010-07-31 06:52:47 +04:00
|
|
|
_save_ppm(ImagingObject *self, PyObject *args) {
|
|
|
|
char *filename;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "s", &filename)) {
|
2013-11-26 04:25:06 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!ImagingSavePPM(self->image, filename)) {
|
2010-07-31 06:52:47 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/* methods */
|
|
|
|
|
|
|
|
static struct PyMethodDef methods[] = {
|
|
|
|
|
|
|
|
/* Put commonly used methods first */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"getpixel", (PyCFunction)_getpixel, METH_VARARGS},
|
|
|
|
{"putpixel", (PyCFunction)_putpixel, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2021-05-11 13:16:44 +03:00
|
|
|
{"pixel_access", (PyCFunction)pixel_access_new, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Standard processing methods (Image) */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"color_lut_3d", (PyCFunction)_color_lut_3d, METH_VARARGS},
|
|
|
|
{"convert", (PyCFunction)_convert, METH_VARARGS},
|
|
|
|
{"convert2", (PyCFunction)_convert2, METH_VARARGS},
|
|
|
|
{"convert_matrix", (PyCFunction)_convert_matrix, METH_VARARGS},
|
|
|
|
{"convert_transparent", (PyCFunction)_convert_transparent, METH_VARARGS},
|
|
|
|
{"copy", (PyCFunction)_copy, METH_VARARGS},
|
|
|
|
{"crop", (PyCFunction)_crop, METH_VARARGS},
|
|
|
|
{"expand", (PyCFunction)_expand_image, METH_VARARGS},
|
|
|
|
{"filter", (PyCFunction)_filter, METH_VARARGS},
|
|
|
|
{"histogram", (PyCFunction)_histogram, METH_VARARGS},
|
|
|
|
{"entropy", (PyCFunction)_entropy, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#ifdef WITH_MODEFILTER
|
2021-05-11 13:16:44 +03:00
|
|
|
{"modefilter", (PyCFunction)_modefilter, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
2021-05-11 13:16:44 +03:00
|
|
|
{"offset", (PyCFunction)_offset, METH_VARARGS},
|
|
|
|
{"paste", (PyCFunction)_paste, METH_VARARGS},
|
|
|
|
{"point", (PyCFunction)_point, METH_VARARGS},
|
|
|
|
{"point_transform", (PyCFunction)_point_transform, METH_VARARGS},
|
|
|
|
{"putdata", (PyCFunction)_putdata, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#ifdef WITH_QUANTIZE
|
2021-05-11 13:16:44 +03:00
|
|
|
{"quantize", (PyCFunction)_quantize, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
#ifdef WITH_RANKFILTER
|
2021-05-11 13:16:44 +03:00
|
|
|
{"rankfilter", (PyCFunction)_rankfilter, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
2021-05-11 13:16:44 +03:00
|
|
|
{"resize", (PyCFunction)_resize, METH_VARARGS},
|
|
|
|
{"reduce", (PyCFunction)_reduce, METH_VARARGS},
|
|
|
|
{"transpose", (PyCFunction)_transpose, METH_VARARGS},
|
|
|
|
{"transform2", (PyCFunction)_transform2, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2021-05-11 13:19:17 +03:00
|
|
|
{"isblock", (PyCFunction)_isblock, METH_NOARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2023-04-29 08:02:11 +03:00
|
|
|
{"getbbox", (PyCFunction)_getbbox, METH_VARARGS},
|
2021-05-11 13:16:44 +03:00
|
|
|
{"getcolors", (PyCFunction)_getcolors, METH_VARARGS},
|
2021-05-11 13:19:17 +03:00
|
|
|
{"getextrema", (PyCFunction)_getextrema, METH_NOARGS},
|
|
|
|
{"getprojection", (PyCFunction)_getprojection, METH_NOARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2021-05-11 13:16:44 +03:00
|
|
|
{"getband", (PyCFunction)_getband, METH_VARARGS},
|
|
|
|
{"putband", (PyCFunction)_putband, METH_VARARGS},
|
2021-05-11 13:19:17 +03:00
|
|
|
{"split", (PyCFunction)_split, METH_NOARGS},
|
2021-05-11 13:16:44 +03:00
|
|
|
{"fillband", (PyCFunction)_fillband, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2021-05-11 13:16:44 +03:00
|
|
|
{"setmode", (PyCFunction)im_setmode, METH_VARARGS},
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2021-05-11 13:16:44 +03:00
|
|
|
{"getpalette", (PyCFunction)_getpalette, METH_VARARGS},
|
2021-05-11 13:19:17 +03:00
|
|
|
{"getpalettemode", (PyCFunction)_getpalettemode, METH_NOARGS},
|
2021-05-11 13:16:44 +03:00
|
|
|
{"putpalette", (PyCFunction)_putpalette, METH_VARARGS},
|
|
|
|
{"putpalettealpha", (PyCFunction)_putpalettealpha, METH_VARARGS},
|
|
|
|
{"putpalettealphas", (PyCFunction)_putpalettealphas, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
#ifdef WITH_IMAGECHOPS
|
|
|
|
/* Channel operations (ImageChops) */
|
2021-05-11 13:19:17 +03:00
|
|
|
{"chop_invert", (PyCFunction)_chop_invert, METH_NOARGS},
|
2021-05-11 13:16:44 +03:00
|
|
|
{"chop_lighter", (PyCFunction)_chop_lighter, METH_VARARGS},
|
|
|
|
{"chop_darker", (PyCFunction)_chop_darker, METH_VARARGS},
|
|
|
|
{"chop_difference", (PyCFunction)_chop_difference, METH_VARARGS},
|
|
|
|
{"chop_multiply", (PyCFunction)_chop_multiply, METH_VARARGS},
|
|
|
|
{"chop_screen", (PyCFunction)_chop_screen, METH_VARARGS},
|
|
|
|
{"chop_add", (PyCFunction)_chop_add, METH_VARARGS},
|
|
|
|
{"chop_subtract", (PyCFunction)_chop_subtract, METH_VARARGS},
|
|
|
|
{"chop_add_modulo", (PyCFunction)_chop_add_modulo, METH_VARARGS},
|
|
|
|
{"chop_subtract_modulo", (PyCFunction)_chop_subtract_modulo, METH_VARARGS},
|
|
|
|
{"chop_and", (PyCFunction)_chop_and, METH_VARARGS},
|
|
|
|
{"chop_or", (PyCFunction)_chop_or, METH_VARARGS},
|
|
|
|
{"chop_xor", (PyCFunction)_chop_xor, METH_VARARGS},
|
|
|
|
{"chop_soft_light", (PyCFunction)_chop_soft_light, METH_VARARGS},
|
|
|
|
{"chop_hard_light", (PyCFunction)_chop_hard_light, METH_VARARGS},
|
|
|
|
{"chop_overlay", (PyCFunction)_chop_overlay, METH_VARARGS},
|
2019-11-22 16:03:59 +03:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef WITH_UNSHARPMASK
|
|
|
|
/* Kevin Cazabon's unsharpmask extension */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"gaussian_blur", (PyCFunction)_gaussian_blur, METH_VARARGS},
|
|
|
|
{"unsharp_mask", (PyCFunction)_unsharp_mask, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
|
2021-05-11 13:16:44 +03:00
|
|
|
{"box_blur", (PyCFunction)_box_blur, METH_VARARGS},
|
2014-10-12 16:30:00 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
#ifdef WITH_EFFECTS
|
|
|
|
/* Special effects */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"effect_spread", (PyCFunction)_effect_spread, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Misc. */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"new_block", (PyCFunction)_new_block, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2021-05-11 13:16:44 +03:00
|
|
|
{"save_ppm", (PyCFunction)_save_ppm, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* attributes */
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyObject *
|
|
|
|
_getattr_mode(ImagingObject *self, void *closure) {
|
2012-10-14 08:47:30 +04:00
|
|
|
return PyUnicode_FromString(self->image->mode);
|
2012-10-13 20:53:07 +04:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyObject *
|
|
|
|
_getattr_size(ImagingObject *self, void *closure) {
|
2013-03-22 18:22:18 +04:00
|
|
|
return Py_BuildValue("ii", self->image->xsize, self->image->ysize);
|
2012-10-13 20:53:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_getattr_bands(ImagingObject *self, void *closure) {
|
2019-09-26 15:12:28 +03:00
|
|
|
return PyLong_FromLong(self->image->bands);
|
2012-10-13 20:53:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_getattr_id(ImagingObject *self, void *closure) {
|
2019-09-26 15:12:28 +03:00
|
|
|
return PyLong_FromSsize_t((Py_ssize_t)self->image);
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyObject *
|
|
|
|
_getattr_ptr(ImagingObject *self, void *closure) {
|
2012-10-14 08:47:30 +04:00
|
|
|
return PyCapsule_New(self->image, IMAGING_MAGIC, NULL);
|
2012-10-13 20:53:07 +04:00
|
|
|
}
|
|
|
|
|
2014-01-05 22:41:25 +04:00
|
|
|
static PyObject *
|
|
|
|
_getattr_unsafe_ptrs(ImagingObject *self, void *closure) {
|
2017-09-16 21:52:28 +03:00
|
|
|
return Py_BuildValue(
|
|
|
|
"(sn)(sn)(sn)",
|
2014-01-05 22:41:25 +04:00
|
|
|
"image8",
|
|
|
|
self->image->image8,
|
|
|
|
"image32",
|
|
|
|
self->image->image32,
|
2017-09-16 21:52:28 +03:00
|
|
|
"image",
|
|
|
|
self->image->image);
|
2014-01-05 22:41:25 +04:00
|
|
|
};
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static struct PyGetSetDef getsetters[] = {
|
|
|
|
{"mode", (getter)_getattr_mode},
|
|
|
|
{"size", (getter)_getattr_size},
|
|
|
|
{"bands", (getter)_getattr_bands},
|
|
|
|
{"id", (getter)_getattr_id},
|
|
|
|
{"ptr", (getter)_getattr_ptr},
|
2014-01-05 22:41:25 +04:00
|
|
|
{"unsafe_ptrs", (getter)_getattr_unsafe_ptrs},
|
2012-10-13 20:53:07 +04:00
|
|
|
{NULL}};
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* basic sequence semantics */
|
|
|
|
|
|
|
|
static Py_ssize_t
|
|
|
|
image_length(ImagingObject *self) {
|
|
|
|
Imaging im = self->image;
|
|
|
|
|
2013-12-05 08:59:33 +04:00
|
|
|
return (Py_ssize_t)im->xsize * im->ysize;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
image_item(ImagingObject *self, Py_ssize_t i) {
|
|
|
|
int x, y;
|
|
|
|
Imaging im = self->image;
|
|
|
|
|
|
|
|
if (im->xsize > 0) {
|
|
|
|
x = i % im->xsize;
|
|
|
|
y = i / im->xsize;
|
2020-05-10 12:56:36 +03:00
|
|
|
} else {
|
2010-07-31 06:52:47 +04:00
|
|
|
x = y = 0; /* leave it to getpixel to raise an exception */
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
return getpixel(im, self->access, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PySequenceMethods image_as_sequence = {
|
2012-10-31 02:38:05 +04:00
|
|
|
(lenfunc)image_length, /*sq_length*/
|
2010-07-31 06:52:47 +04:00
|
|
|
(binaryfunc)NULL, /*sq_concat*/
|
|
|
|
(ssizeargfunc)NULL, /*sq_repeat*/
|
|
|
|
(ssizeargfunc)image_item, /*sq_item*/
|
|
|
|
(ssizessizeargfunc)NULL, /*sq_slice*/
|
|
|
|
(ssizeobjargproc)NULL, /*sq_ass_item*/
|
|
|
|
(ssizessizeobjargproc)NULL, /*sq_ass_slice*/
|
|
|
|
};
|
|
|
|
|
|
|
|
/* type description */
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyTypeObject Imaging_Type = {
|
|
|
|
PyVarObject_HEAD_INIT(NULL, 0) "ImagingCore", /*tp_name*/
|
2023-07-02 08:52:08 +03:00
|
|
|
sizeof(ImagingObject), /*tp_basicsize*/
|
2013-03-22 18:22:18 +04:00
|
|
|
0, /*tp_itemsize*/
|
2010-07-31 06:52:47 +04:00
|
|
|
/* methods */
|
2013-03-22 18:22:18 +04:00
|
|
|
(destructor)_dealloc, /*tp_dealloc*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_vectorcall_offset*/
|
2012-10-13 20:53:07 +04:00
|
|
|
0, /*tp_getattr*/
|
|
|
|
0, /*tp_setattr*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_as_async*/
|
2012-10-13 20:53:07 +04:00
|
|
|
0, /*tp_repr*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_as_number*/
|
|
|
|
&image_as_sequence, /*tp_as_sequence*/
|
|
|
|
0, /*tp_as_mapping*/
|
2012-10-13 20:53:07 +04:00
|
|
|
0, /*tp_hash*/
|
|
|
|
0, /*tp_call*/
|
|
|
|
0, /*tp_str*/
|
|
|
|
0, /*tp_getattro*/
|
|
|
|
0, /*tp_setattro*/
|
|
|
|
0, /*tp_as_buffer*/
|
|
|
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
|
|
|
0, /*tp_doc*/
|
|
|
|
0, /*tp_traverse*/
|
|
|
|
0, /*tp_clear*/
|
|
|
|
0, /*tp_richcompare*/
|
|
|
|
0, /*tp_weaklistoffset*/
|
|
|
|
0, /*tp_iter*/
|
|
|
|
0, /*tp_iternext*/
|
|
|
|
methods, /*tp_methods*/
|
|
|
|
0, /*tp_members*/
|
|
|
|
getsetters, /*tp_getset*/
|
2010-07-31 06:52:47 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef WITH_IMAGEDRAW
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyTypeObject ImagingFont_Type = {
|
|
|
|
PyVarObject_HEAD_INIT(NULL, 0) "ImagingFont", /*tp_name*/
|
2023-07-02 08:52:08 +03:00
|
|
|
sizeof(ImagingFontObject), /*tp_basicsize*/
|
2013-03-22 18:22:18 +04:00
|
|
|
0, /*tp_itemsize*/
|
2010-07-31 06:52:47 +04:00
|
|
|
/* methods */
|
2013-03-22 18:22:18 +04:00
|
|
|
(destructor)_font_dealloc, /*tp_dealloc*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_vectorcall_offset*/
|
2012-10-13 20:53:07 +04:00
|
|
|
0, /*tp_getattr*/
|
|
|
|
0, /*tp_setattr*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_as_async*/
|
2012-10-13 20:53:07 +04:00
|
|
|
0, /*tp_repr*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_as_number*/
|
|
|
|
0, /*tp_as_sequence*/
|
|
|
|
0, /*tp_as_mapping*/
|
2012-10-13 20:53:07 +04:00
|
|
|
0, /*tp_hash*/
|
|
|
|
0, /*tp_call*/
|
|
|
|
0, /*tp_str*/
|
|
|
|
0, /*tp_getattro*/
|
|
|
|
0, /*tp_setattro*/
|
|
|
|
0, /*tp_as_buffer*/
|
|
|
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
|
|
|
0, /*tp_doc*/
|
|
|
|
0, /*tp_traverse*/
|
|
|
|
0, /*tp_clear*/
|
|
|
|
0, /*tp_richcompare*/
|
|
|
|
0, /*tp_weaklistoffset*/
|
|
|
|
0, /*tp_iter*/
|
|
|
|
0, /*tp_iternext*/
|
|
|
|
_font_methods, /*tp_methods*/
|
|
|
|
0, /*tp_members*/
|
|
|
|
0, /*tp_getset*/
|
2010-07-31 06:52:47 +04:00
|
|
|
};
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyTypeObject ImagingDraw_Type = {
|
|
|
|
PyVarObject_HEAD_INIT(NULL, 0) "ImagingDraw", /*tp_name*/
|
2023-07-02 08:52:08 +03:00
|
|
|
sizeof(ImagingDrawObject), /*tp_basicsize*/
|
2013-03-22 18:22:18 +04:00
|
|
|
0, /*tp_itemsize*/
|
2010-07-31 06:52:47 +04:00
|
|
|
/* methods */
|
2013-03-22 18:22:18 +04:00
|
|
|
(destructor)_draw_dealloc, /*tp_dealloc*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_vectorcall_offset*/
|
2012-10-13 20:53:07 +04:00
|
|
|
0, /*tp_getattr*/
|
|
|
|
0, /*tp_setattr*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_as_async*/
|
2012-10-13 20:53:07 +04:00
|
|
|
0, /*tp_repr*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_as_number*/
|
|
|
|
0, /*tp_as_sequence*/
|
|
|
|
0, /*tp_as_mapping*/
|
2012-10-13 20:53:07 +04:00
|
|
|
0, /*tp_hash*/
|
|
|
|
0, /*tp_call*/
|
|
|
|
0, /*tp_str*/
|
|
|
|
0, /*tp_getattro*/
|
|
|
|
0, /*tp_setattro*/
|
|
|
|
0, /*tp_as_buffer*/
|
|
|
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
|
|
|
0, /*tp_doc*/
|
|
|
|
0, /*tp_traverse*/
|
|
|
|
0, /*tp_clear*/
|
|
|
|
0, /*tp_richcompare*/
|
|
|
|
0, /*tp_weaklistoffset*/
|
|
|
|
0, /*tp_iter*/
|
|
|
|
0, /*tp_iternext*/
|
|
|
|
_draw_methods, /*tp_methods*/
|
|
|
|
0, /*tp_members*/
|
|
|
|
0, /*tp_getset*/
|
2010-07-31 06:52:47 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static PyMappingMethods pixel_access_as_mapping = {
|
2012-10-31 02:38:05 +04:00
|
|
|
(lenfunc)NULL, /*mp_length*/
|
2010-07-31 06:52:47 +04:00
|
|
|
(binaryfunc)pixel_access_getitem, /*mp_subscript*/
|
|
|
|
(objobjargproc)pixel_access_setitem, /*mp_ass_subscript*/
|
|
|
|
};
|
|
|
|
|
|
|
|
/* type description */
|
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
static PyTypeObject PixelAccess_Type = {
|
2023-07-02 08:52:08 +03:00
|
|
|
PyVarObject_HEAD_INIT(NULL, 0) "PixelAccess", /*tp_name*/
|
|
|
|
sizeof(PixelAccessObject), /*tp_basicsize*/
|
|
|
|
0, /*tp_itemsize*/
|
2010-07-31 06:52:47 +04:00
|
|
|
/* methods */
|
|
|
|
(destructor)pixel_access_dealloc, /*tp_dealloc*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_vectorcall_offset*/
|
2010-07-31 06:52:47 +04:00
|
|
|
0, /*tp_getattr*/
|
|
|
|
0, /*tp_setattr*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_as_async*/
|
2010-07-31 06:52:47 +04:00
|
|
|
0, /*tp_repr*/
|
2023-07-02 08:52:08 +03:00
|
|
|
0, /*tp_as_number*/
|
|
|
|
0, /*tp_as_sequence*/
|
|
|
|
&pixel_access_as_mapping, /*tp_as_mapping*/
|
2010-07-31 06:52:47 +04:00
|
|
|
0 /*tp_hash*/
|
|
|
|
};
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
2017-09-18 01:41:39 +03:00
|
|
|
static PyObject *
|
|
|
|
_get_stats(PyObject *self, PyObject *args) {
|
|
|
|
PyObject *d;
|
2023-03-22 00:44:52 +03:00
|
|
|
PyObject *v;
|
2017-09-18 01:41:39 +03:00
|
|
|
ImagingMemoryArena arena = &ImagingDefaultArena;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, ":get_stats")) {
|
2017-09-18 01:41:39 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2017-09-18 01:41:39 +03:00
|
|
|
|
|
|
|
d = PyDict_New();
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!d) {
|
2017-09-18 01:41:39 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2023-03-22 00:44:52 +03:00
|
|
|
v = PyLong_FromLong(arena->stats_new_count);
|
|
|
|
PyDict_SetItemString(d, "new_count", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2023-03-11 10:32:43 +03:00
|
|
|
|
2023-03-22 00:44:52 +03:00
|
|
|
v = PyLong_FromLong(arena->stats_allocated_blocks);
|
|
|
|
PyDict_SetItemString(d, "allocated_blocks", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2023-03-11 10:32:43 +03:00
|
|
|
|
2023-03-22 00:44:52 +03:00
|
|
|
v = PyLong_FromLong(arena->stats_reused_blocks);
|
|
|
|
PyDict_SetItemString(d, "reused_blocks", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2023-03-11 10:32:43 +03:00
|
|
|
|
2023-03-22 00:44:52 +03:00
|
|
|
v = PyLong_FromLong(arena->stats_reallocated_blocks);
|
|
|
|
PyDict_SetItemString(d, "reallocated_blocks", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2023-03-11 10:32:43 +03:00
|
|
|
|
2023-03-22 00:44:52 +03:00
|
|
|
v = PyLong_FromLong(arena->stats_freed_blocks);
|
|
|
|
PyDict_SetItemString(d, "freed_blocks", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2023-03-11 10:32:43 +03:00
|
|
|
|
2023-03-22 00:44:52 +03:00
|
|
|
v = PyLong_FromLong(arena->blocks_cached);
|
|
|
|
PyDict_SetItemString(d, "blocks_cached", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2017-09-18 01:41:39 +03:00
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_reset_stats(PyObject *self, PyObject *args) {
|
|
|
|
ImagingMemoryArena arena = &ImagingDefaultArena;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, ":reset_stats")) {
|
2017-09-18 01:41:39 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-01-27 09:02:56 +03:00
|
|
|
|
2017-09-18 01:41:39 +03:00
|
|
|
arena->stats_new_count = 0;
|
|
|
|
arena->stats_allocated_blocks = 0;
|
|
|
|
arena->stats_reused_blocks = 0;
|
|
|
|
arena->stats_reallocated_blocks = 0;
|
|
|
|
arena->stats_freed_blocks = 0;
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_get_alignment(PyObject *self, PyObject *args) {
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, ":get_alignment")) {
|
2017-09-18 01:41:39 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-01-27 09:02:56 +03:00
|
|
|
|
2019-09-26 15:12:28 +03:00
|
|
|
return PyLong_FromLong(ImagingDefaultArena.alignment);
|
2017-09-18 01:41:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_get_block_size(PyObject *self, PyObject *args) {
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, ":get_block_size")) {
|
2017-09-18 01:41:39 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-01-27 09:02:56 +03:00
|
|
|
|
2019-09-26 15:12:28 +03:00
|
|
|
return PyLong_FromLong(ImagingDefaultArena.block_size);
|
2017-09-18 01:41:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_get_blocks_max(PyObject *self, PyObject *args) {
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, ":get_blocks_max")) {
|
2017-09-18 01:41:39 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-01-27 09:02:56 +03:00
|
|
|
|
2019-09-26 15:12:28 +03:00
|
|
|
return PyLong_FromLong(ImagingDefaultArena.blocks_max);
|
2017-09-18 01:41:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_set_alignment(PyObject *self, PyObject *args) {
|
|
|
|
int alignment;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "i:set_alignment", &alignment)) {
|
2017-09-18 01:41:39 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-01-27 09:02:56 +03:00
|
|
|
|
2017-09-18 01:41:39 +03:00
|
|
|
if (alignment < 1 || alignment > 128) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "alignment should be from 1 to 128");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* Is power of two */
|
|
|
|
if (alignment & (alignment - 1)) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "alignment should be power of two");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImagingDefaultArena.alignment = alignment;
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_set_block_size(PyObject *self, PyObject *args) {
|
|
|
|
int block_size;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "i:set_block_size", &block_size)) {
|
2017-09-18 01:41:39 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-01-27 09:02:56 +03:00
|
|
|
|
2017-09-18 02:37:47 +03:00
|
|
|
if (block_size <= 0) {
|
2017-09-18 01:41:39 +03:00
|
|
|
PyErr_SetString(PyExc_ValueError, "block_size should be greater than 0");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (block_size & 0xfff) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "block_size should be multiple of 4096");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImagingDefaultArena.block_size = block_size;
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_set_blocks_max(PyObject *self, PyObject *args) {
|
|
|
|
int blocks_max;
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "i:set_blocks_max", &blocks_max)) {
|
2017-09-18 01:41:39 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-01-27 09:02:56 +03:00
|
|
|
|
2017-09-18 01:41:39 +03:00
|
|
|
if (blocks_max < 0) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "blocks_max should be greater than 0");
|
|
|
|
return NULL;
|
2020-12-22 08:06:44 +03:00
|
|
|
} else if (
|
|
|
|
(unsigned long)blocks_max >
|
|
|
|
SIZE_MAX / sizeof(ImagingDefaultArena.blocks_pool[0])) {
|
2019-03-08 21:30:35 +03:00
|
|
|
PyErr_SetString(PyExc_ValueError, "blocks_max is too large");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-09-18 01:41:39 +03:00
|
|
|
if (!ImagingMemorySetBlocksMax(&ImagingDefaultArena, blocks_max)) {
|
2020-12-20 04:28:52 +03:00
|
|
|
return ImagingError_MemoryError();
|
2017-09-18 01:41:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_clear_cache(PyObject *self, PyObject *args) {
|
2017-09-23 04:20:53 +03:00
|
|
|
int i = 0;
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (!PyArg_ParseTuple(args, "|i:clear_cache", &i)) {
|
2017-09-18 01:41:39 +03:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2018-01-27 09:02:56 +03:00
|
|
|
|
2017-09-23 04:20:53 +03:00
|
|
|
ImagingMemoryClearCache(&ImagingDefaultArena, i);
|
2017-09-18 01:41:39 +03:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
/* FIXME: this is something of a mess. Should replace this with
|
|
|
|
pluggable codecs, but not before PIL 1.2 */
|
|
|
|
|
|
|
|
/* Decoders (in decode.c) */
|
2016-08-11 02:16:32 +03:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_BcnDecoderNew(PyObject *self, PyObject *args);
|
2010-07-31 06:52:47 +04:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_BitDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_FliDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_GifDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_HexDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_JpegDecoderNew(PyObject *self, PyObject *args);
|
2014-03-12 20:25:59 +04:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_Jpeg2KDecoderNew(PyObject *self, PyObject *args);
|
2013-03-09 07:51:59 +04:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_LibTiffDecoderNew(PyObject *self, PyObject *args);
|
2010-07-31 06:52:47 +04:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_PackbitsDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_PcdDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_PcxDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_RawDecoderNew(PyObject *self, PyObject *args);
|
2017-07-22 10:34:06 +03:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_SgiRleDecoderNew(PyObject *self, PyObject *args);
|
2010-07-31 06:52:47 +04:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_SunRleDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_TgaRleDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_XbmDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_ZipDecoderNew(PyObject *self, PyObject *args);
|
|
|
|
|
|
|
|
/* Encoders (in encode.c) */
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_EpsEncoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_GifEncoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_JpegEncoderNew(PyObject *self, PyObject *args);
|
2014-03-13 22:27:16 +04:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args);
|
2010-07-31 06:52:47 +04:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_PcxEncoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_RawEncoderNew(PyObject *self, PyObject *args);
|
2018-06-15 23:01:06 +03:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_TgaRleEncoderNew(PyObject *self, PyObject *args);
|
2010-07-31 06:52:47 +04:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_XbmEncoderNew(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_ZipEncoderNew(PyObject *self, PyObject *args);
|
2013-03-09 07:51:59 +04:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Display support etc (in display.c) */
|
2014-05-09 23:05:30 +04:00
|
|
|
#ifdef _WIN32
|
2010-07-31 06:52:47 +04:00
|
|
|
extern PyObject *
|
|
|
|
PyImaging_CreateWindowWin32(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_DisplayWin32(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_DisplayModeWin32(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_GrabScreenWin32(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_GrabClipboardWin32(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_EventLoopWin32(PyObject *self, PyObject *args);
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_DrawWmf(PyObject *self, PyObject *args);
|
|
|
|
#endif
|
2019-09-19 19:57:59 +03:00
|
|
|
#ifdef HAVE_XCB
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_GrabScreenX11(PyObject *self, PyObject *args);
|
|
|
|
#endif
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Experimental path stuff (in path.c) */
|
|
|
|
extern PyObject *
|
|
|
|
PyPath_Create(ImagingObject *self, PyObject *args);
|
|
|
|
|
|
|
|
/* Experimental outline stuff (in outline.c) */
|
|
|
|
extern PyObject *
|
|
|
|
PyOutline_Create(ImagingObject *self, PyObject *args);
|
|
|
|
|
|
|
|
extern PyObject *
|
|
|
|
PyImaging_MapBuffer(PyObject *self, PyObject *args);
|
|
|
|
|
|
|
|
static PyMethodDef functions[] = {
|
|
|
|
|
|
|
|
/* Object factories */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"alpha_composite", (PyCFunction)_alpha_composite, METH_VARARGS},
|
|
|
|
{"blend", (PyCFunction)_blend, METH_VARARGS},
|
|
|
|
{"fill", (PyCFunction)_fill, METH_VARARGS},
|
|
|
|
{"new", (PyCFunction)_new, METH_VARARGS},
|
|
|
|
{"merge", (PyCFunction)_merge, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Functions */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"convert", (PyCFunction)_convert2, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Codecs */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"bcn_decoder", (PyCFunction)PyImaging_BcnDecoderNew, METH_VARARGS},
|
|
|
|
{"bit_decoder", (PyCFunction)PyImaging_BitDecoderNew, METH_VARARGS},
|
|
|
|
{"eps_encoder", (PyCFunction)PyImaging_EpsEncoderNew, METH_VARARGS},
|
|
|
|
{"fli_decoder", (PyCFunction)PyImaging_FliDecoderNew, METH_VARARGS},
|
|
|
|
{"gif_decoder", (PyCFunction)PyImaging_GifDecoderNew, METH_VARARGS},
|
|
|
|
{"gif_encoder", (PyCFunction)PyImaging_GifEncoderNew, METH_VARARGS},
|
|
|
|
{"hex_decoder", (PyCFunction)PyImaging_HexDecoderNew, METH_VARARGS},
|
|
|
|
{"hex_encoder", (PyCFunction)PyImaging_EpsEncoderNew, METH_VARARGS}, /* EPS=HEX! */
|
2010-07-31 06:52:47 +04:00
|
|
|
#ifdef HAVE_LIBJPEG
|
2021-05-11 13:16:44 +03:00
|
|
|
{"jpeg_decoder", (PyCFunction)PyImaging_JpegDecoderNew, METH_VARARGS},
|
|
|
|
{"jpeg_encoder", (PyCFunction)PyImaging_JpegEncoderNew, METH_VARARGS},
|
2014-03-12 20:25:59 +04:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_OPENJPEG
|
2021-05-11 13:16:44 +03:00
|
|
|
{"jpeg2k_decoder", (PyCFunction)PyImaging_Jpeg2KDecoderNew, METH_VARARGS},
|
|
|
|
{"jpeg2k_encoder", (PyCFunction)PyImaging_Jpeg2KEncoderNew, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
2013-03-09 07:51:59 +04:00
|
|
|
#ifdef HAVE_LIBTIFF
|
2021-05-11 13:16:44 +03:00
|
|
|
{"libtiff_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, METH_VARARGS},
|
|
|
|
{"libtiff_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, METH_VARARGS},
|
2013-03-09 07:51:59 +04:00
|
|
|
#endif
|
2021-05-11 13:16:44 +03:00
|
|
|
{"packbits_decoder", (PyCFunction)PyImaging_PackbitsDecoderNew, METH_VARARGS},
|
|
|
|
{"pcd_decoder", (PyCFunction)PyImaging_PcdDecoderNew, METH_VARARGS},
|
|
|
|
{"pcx_decoder", (PyCFunction)PyImaging_PcxDecoderNew, METH_VARARGS},
|
|
|
|
{"pcx_encoder", (PyCFunction)PyImaging_PcxEncoderNew, METH_VARARGS},
|
|
|
|
{"raw_decoder", (PyCFunction)PyImaging_RawDecoderNew, METH_VARARGS},
|
|
|
|
{"raw_encoder", (PyCFunction)PyImaging_RawEncoderNew, METH_VARARGS},
|
|
|
|
{"sgi_rle_decoder", (PyCFunction)PyImaging_SgiRleDecoderNew, METH_VARARGS},
|
|
|
|
{"sun_rle_decoder", (PyCFunction)PyImaging_SunRleDecoderNew, METH_VARARGS},
|
|
|
|
{"tga_rle_decoder", (PyCFunction)PyImaging_TgaRleDecoderNew, METH_VARARGS},
|
|
|
|
{"tga_rle_encoder", (PyCFunction)PyImaging_TgaRleEncoderNew, METH_VARARGS},
|
|
|
|
{"xbm_decoder", (PyCFunction)PyImaging_XbmDecoderNew, METH_VARARGS},
|
|
|
|
{"xbm_encoder", (PyCFunction)PyImaging_XbmEncoderNew, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#ifdef HAVE_LIBZ
|
2021-05-11 13:16:44 +03:00
|
|
|
{"zip_decoder", (PyCFunction)PyImaging_ZipDecoderNew, METH_VARARGS},
|
|
|
|
{"zip_encoder", (PyCFunction)PyImaging_ZipEncoderNew, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Memory mapping */
|
|
|
|
#ifdef WITH_MAPPING
|
2021-05-11 13:16:44 +03:00
|
|
|
{"map_buffer", (PyCFunction)PyImaging_MapBuffer, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Display support */
|
2014-05-09 23:05:30 +04:00
|
|
|
#ifdef _WIN32
|
2021-05-11 13:16:44 +03:00
|
|
|
{"display", (PyCFunction)PyImaging_DisplayWin32, METH_VARARGS},
|
|
|
|
{"display_mode", (PyCFunction)PyImaging_DisplayModeWin32, METH_VARARGS},
|
|
|
|
{"grabscreen_win32", (PyCFunction)PyImaging_GrabScreenWin32, METH_VARARGS},
|
|
|
|
{"grabclipboard_win32", (PyCFunction)PyImaging_GrabClipboardWin32, METH_VARARGS},
|
|
|
|
{"createwindow", (PyCFunction)PyImaging_CreateWindowWin32, METH_VARARGS},
|
|
|
|
{"eventloop", (PyCFunction)PyImaging_EventLoopWin32, METH_VARARGS},
|
|
|
|
{"drawwmf", (PyCFunction)PyImaging_DrawWmf, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
2019-09-19 19:57:59 +03:00
|
|
|
#ifdef HAVE_XCB
|
2021-05-11 13:16:44 +03:00
|
|
|
{"grabscreen_x11", (PyCFunction)PyImaging_GrabScreenX11, METH_VARARGS},
|
2019-09-19 19:57:59 +03:00
|
|
|
#endif
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Utilities */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"getcodecstatus", (PyCFunction)_getcodecstatus, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
/* Special effects (experimental) */
|
|
|
|
#ifdef WITH_EFFECTS
|
2021-05-11 13:16:44 +03:00
|
|
|
{"effect_mandelbrot", (PyCFunction)_effect_mandelbrot, METH_VARARGS},
|
|
|
|
{"effect_noise", (PyCFunction)_effect_noise, METH_VARARGS},
|
|
|
|
{"linear_gradient", (PyCFunction)_linear_gradient, METH_VARARGS},
|
|
|
|
{"radial_gradient", (PyCFunction)_radial_gradient, METH_VARARGS},
|
|
|
|
{"wedge", (PyCFunction)_linear_gradient, METH_VARARGS}, /* Compatibility */
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Drawing support stuff */
|
|
|
|
#ifdef WITH_IMAGEDRAW
|
2021-05-11 13:16:44 +03:00
|
|
|
{"font", (PyCFunction)_font_new, METH_VARARGS},
|
|
|
|
{"draw", (PyCFunction)_draw_new, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Experimental path stuff */
|
|
|
|
#ifdef WITH_IMAGEPATH
|
2021-05-11 13:16:44 +03:00
|
|
|
{"path", (PyCFunction)PyPath_Create, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
2013-03-11 23:33:04 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
/* Experimental arrow graphics stuff */
|
|
|
|
#ifdef WITH_ARROW
|
2021-05-11 13:16:44 +03:00
|
|
|
{"outline", (PyCFunction)PyOutline_Create, METH_VARARGS},
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
|
|
|
|
2017-09-18 01:41:39 +03:00
|
|
|
/* Resource management */
|
2021-05-11 13:16:44 +03:00
|
|
|
{"get_stats", (PyCFunction)_get_stats, METH_VARARGS},
|
|
|
|
{"reset_stats", (PyCFunction)_reset_stats, METH_VARARGS},
|
|
|
|
{"get_alignment", (PyCFunction)_get_alignment, METH_VARARGS},
|
|
|
|
{"get_block_size", (PyCFunction)_get_block_size, METH_VARARGS},
|
|
|
|
{"get_blocks_max", (PyCFunction)_get_blocks_max, METH_VARARGS},
|
|
|
|
{"set_alignment", (PyCFunction)_set_alignment, METH_VARARGS},
|
|
|
|
{"set_block_size", (PyCFunction)_set_block_size, METH_VARARGS},
|
|
|
|
{"set_blocks_max", (PyCFunction)_set_blocks_max, METH_VARARGS},
|
|
|
|
{"clear_cache", (PyCFunction)_clear_cache, METH_VARARGS},
|
2017-09-18 01:41:39 +03:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
|
};
|
|
|
|
|
2012-10-14 08:47:30 +04:00
|
|
|
static int
|
|
|
|
setup_module(PyObject *m) {
|
|
|
|
PyObject *d = PyModule_GetDict(m);
|
2017-06-21 15:36:56 +03:00
|
|
|
const char *version = (char *)PILLOW_VERSION;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2012-10-13 20:53:07 +04:00
|
|
|
/* Ready object types */
|
2020-05-10 12:56:36 +03:00
|
|
|
if (PyType_Ready(&Imaging_Type) < 0) {
|
2012-10-14 08:47:30 +04:00
|
|
|
return -1;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2012-10-14 08:47:30 +04:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
#ifdef WITH_IMAGEDRAW
|
2020-05-10 12:56:36 +03:00
|
|
|
if (PyType_Ready(&ImagingFont_Type) < 0) {
|
2012-10-14 08:47:30 +04:00
|
|
|
return -1;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2012-10-14 08:47:30 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (PyType_Ready(&ImagingDraw_Type) < 0) {
|
2012-10-14 08:47:30 +04:00
|
|
|
return -1;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
#endif
|
2020-05-10 12:56:36 +03:00
|
|
|
if (PyType_Ready(&PixelAccess_Type) < 0) {
|
2012-10-14 08:47:30 +04:00
|
|
|
return -1;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
ImagingAccessInit();
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBJPEG
|
|
|
|
{
|
|
|
|
extern const char *ImagingJpegVersion(void);
|
2023-03-22 00:44:52 +03:00
|
|
|
PyObject *v = PyUnicode_FromString(ImagingJpegVersion());
|
|
|
|
PyDict_SetItemString(d, "jpeglib_version", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-03-14 19:40:30 +04:00
|
|
|
#ifdef HAVE_OPENJPEG
|
|
|
|
{
|
|
|
|
extern const char *ImagingJpeg2KVersion(void);
|
2023-03-22 00:44:52 +03:00
|
|
|
PyObject *v = PyUnicode_FromString(ImagingJpeg2KVersion());
|
|
|
|
PyDict_SetItemString(d, "jp2klib_version", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2014-03-14 19:40:30 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-01-09 03:33:26 +03:00
|
|
|
PyObject *have_libjpegturbo;
|
2018-12-12 13:25:05 +03:00
|
|
|
#ifdef LIBJPEG_TURBO_VERSION
|
2021-01-09 03:33:26 +03:00
|
|
|
have_libjpegturbo = Py_True;
|
2023-03-22 00:44:52 +03:00
|
|
|
{
|
2020-06-14 06:35:43 +03:00
|
|
|
#define tostr1(a) #a
|
|
|
|
#define tostr(a) tostr1(a)
|
2023-03-22 00:44:52 +03:00
|
|
|
PyObject *v = PyUnicode_FromString(tostr(LIBJPEG_TURBO_VERSION));
|
|
|
|
PyDict_SetItemString(d, "libjpeg_turbo_version", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2020-06-14 06:35:43 +03:00
|
|
|
#undef tostr
|
|
|
|
#undef tostr1
|
2023-03-22 00:44:52 +03:00
|
|
|
}
|
2018-12-12 13:25:05 +03:00
|
|
|
#else
|
2021-01-09 03:33:26 +03:00
|
|
|
have_libjpegturbo = Py_False;
|
2018-12-12 13:25:05 +03:00
|
|
|
#endif
|
2021-01-09 03:33:26 +03:00
|
|
|
Py_INCREF(have_libjpegturbo);
|
|
|
|
PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", have_libjpegturbo);
|
2018-12-12 13:25:05 +03:00
|
|
|
|
2021-01-09 03:33:26 +03:00
|
|
|
PyObject *have_libimagequant;
|
2019-09-27 01:09:04 +03:00
|
|
|
#ifdef HAVE_LIBIMAGEQUANT
|
2021-01-09 03:33:26 +03:00
|
|
|
have_libimagequant = Py_True;
|
2020-06-14 06:35:43 +03:00
|
|
|
{
|
|
|
|
extern const char *ImagingImageQuantVersion(void);
|
2023-03-22 00:44:52 +03:00
|
|
|
PyObject *v = PyUnicode_FromString(ImagingImageQuantVersion());
|
|
|
|
PyDict_SetItemString(d, "imagequant_version", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2020-06-14 06:35:43 +03:00
|
|
|
}
|
2019-09-27 01:09:04 +03:00
|
|
|
#else
|
2021-01-09 03:33:26 +03:00
|
|
|
have_libimagequant = Py_False;
|
2019-09-27 01:09:04 +03:00
|
|
|
#endif
|
2021-01-09 03:33:26 +03:00
|
|
|
Py_INCREF(have_libimagequant);
|
|
|
|
PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", have_libimagequant);
|
2019-09-27 01:09:04 +03:00
|
|
|
|
2010-07-31 06:52:47 +04:00
|
|
|
#ifdef HAVE_LIBZ
|
2013-03-11 23:33:04 +04:00
|
|
|
/* 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);
|
2010-07-31 06:52:47 +04:00
|
|
|
{
|
|
|
|
extern const char *ImagingZipVersion(void);
|
2023-03-22 00:44:52 +03:00
|
|
|
PyObject *v = PyUnicode_FromString(ImagingZipVersion());
|
|
|
|
PyDict_SetItemString(d, "zlib_version", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
#endif
|
2012-10-14 08:47:30 +04:00
|
|
|
|
2018-10-25 11:36:49 +03:00
|
|
|
#ifdef HAVE_LIBTIFF
|
|
|
|
{
|
|
|
|
extern const char *ImagingTiffVersion(void);
|
2023-03-22 00:44:52 +03:00
|
|
|
PyObject *v = PyUnicode_FromString(ImagingTiffVersion());
|
|
|
|
PyDict_SetItemString(d, "libtiff_version", v ? v : Py_None);
|
|
|
|
Py_XDECREF(v);
|
2021-01-03 06:17:51 +03:00
|
|
|
|
2019-12-28 01:57:49 +03:00
|
|
|
// Test for libtiff 4.0 or later, excluding libtiff 3.9.6 and 3.9.7
|
2019-12-31 01:04:25 +03:00
|
|
|
PyObject *support_custom_tags;
|
2019-12-28 01:57:49 +03:00
|
|
|
#if TIFFLIB_VERSION >= 20111221 && TIFFLIB_VERSION != 20120218 && \
|
|
|
|
TIFFLIB_VERSION != 20120922
|
2019-12-31 01:04:25 +03:00
|
|
|
support_custom_tags = Py_True;
|
2019-12-28 01:57:49 +03:00
|
|
|
#else
|
2019-12-31 01:04:25 +03:00
|
|
|
support_custom_tags = Py_False;
|
2019-12-28 01:57:49 +03:00
|
|
|
#endif
|
2019-12-31 01:04:25 +03:00
|
|
|
PyDict_SetItemString(d, "libtiff_support_custom_tags", support_custom_tags);
|
2018-10-25 11:36:49 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-01-09 03:33:26 +03:00
|
|
|
PyObject *have_xcb;
|
2019-09-19 19:57:59 +03:00
|
|
|
#ifdef HAVE_XCB
|
2021-01-09 03:33:26 +03:00
|
|
|
have_xcb = Py_True;
|
2019-09-19 19:57:59 +03:00
|
|
|
#else
|
2021-01-09 03:33:26 +03:00
|
|
|
have_xcb = Py_False;
|
2019-09-19 19:57:59 +03:00
|
|
|
#endif
|
2021-01-09 03:33:26 +03:00
|
|
|
Py_INCREF(have_xcb);
|
|
|
|
PyModule_AddObject(m, "HAVE_XCB", have_xcb);
|
2019-09-19 19:57:59 +03:00
|
|
|
|
2023-03-11 10:32:43 +03:00
|
|
|
PyObject *pillow_version = PyUnicode_FromString(version);
|
2023-03-22 00:44:52 +03:00
|
|
|
PyDict_SetItemString(d, "PILLOW_VERSION", pillow_version ? pillow_version : Py_None);
|
2023-03-20 09:34:34 +03:00
|
|
|
Py_XDECREF(pillow_version);
|
2013-04-09 08:43:15 +04:00
|
|
|
|
2012-10-14 08:47:30 +04:00
|
|
|
return 0;
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
2012-10-14 08:47:30 +04:00
|
|
|
|
|
|
|
PyMODINIT_FUNC
|
|
|
|
PyInit__imaging(void) {
|
|
|
|
PyObject *m;
|
|
|
|
|
|
|
|
static PyModuleDef module_def = {
|
|
|
|
PyModuleDef_HEAD_INIT,
|
|
|
|
"_imaging", /* m_name */
|
|
|
|
NULL, /* m_doc */
|
|
|
|
-1, /* m_size */
|
|
|
|
functions, /* m_methods */
|
|
|
|
};
|
|
|
|
|
|
|
|
m = PyModule_Create(&module_def);
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (setup_module(m) < 0) {
|
2023-03-11 16:11:48 +03:00
|
|
|
Py_DECREF(m);
|
2012-10-14 08:47:30 +04:00
|
|
|
return NULL;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2012-10-14 08:47:30 +04:00
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|