From 4876da0d1c6fa2aae28e086b9bb813f81945182e Mon Sep 17 00:00:00 2001 From: Cedric Porter Date: Sun, 29 Jul 2012 23:43:14 +0800 Subject: [PATCH] =?UTF-8?q?C=E8=AF=AD=E8=A8=80=E5=AE=9E=E7=8E=B0=E4=BA=86?= =?UTF-8?q?=E9=83=A8=E5=88=86=E5=BA=93=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EffectLab/Effect.py | 11 +++ EffectLab/ImPlatform.h | 72 +++++++++++++++ EffectLab/Makefile | 5 ++ EffectLab/core.c | 198 +++++++++++++++++++++++++++++++++++++++++ TestEffectLab.py | 18 ++-- 5 files changed, 296 insertions(+), 8 deletions(-) create mode 100644 EffectLab/ImPlatform.h create mode 100644 EffectLab/Makefile create mode 100644 EffectLab/core.c diff --git a/EffectLab/Effect.py b/EffectLab/Effect.py index 22114af..14cfe7f 100755 --- a/EffectLab/Effect.py +++ b/EffectLab/Effect.py @@ -14,6 +14,11 @@ import math, operator from math import sqrt, sin, cos, atan2 +try: + import EffectLabCore as core +except: + pass + # Effect是特效处理流程中的过滤器,输入PIL中的Image,然后输出处理好的Image # 其中,()是经过重载的,默认调用成员函数filter(img)。这样可以方便的与其他普通过滤器函数组合在一起。 # @@ -202,6 +207,12 @@ def filter(self, img): '''Effect Kernel of radius based Effect. @param formula is a function like f(x, y) => (x', y'), -1 <= x <= 1 and -1 <= y <= 1 ''' + + try: + return core.global_warp(img) + except: + pass + width, height = img.size nx, ny = width, height new_img = img.copy() diff --git a/EffectLab/ImPlatform.h b/EffectLab/ImPlatform.h new file mode 100644 index 0000000..4ffd6fd --- /dev/null +++ b/EffectLab/ImPlatform.h @@ -0,0 +1,72 @@ +/* + * The Python Imaging Library + * $Id$ + * + * platform declarations for the imaging core library + * + * Copyright (c) Fredrik Lundh 1995-2003. + */ + +#include "Python.h" + +/* Check that we have an ANSI compliant compiler */ +#ifndef HAVE_PROTOTYPES +#error Sorry, this library requires support for ANSI prototypes. +#endif +#ifndef STDC_HEADERS +#error Sorry, this library requires ANSI header files. +#endif + +#if defined(_MSC_VER) +#ifndef WIN32 +#define WIN32 +#endif +/* VC++ 4.0 is a bit annoying when it comes to precision issues (like + claiming that "float a = 0.0;" would lead to loss of precision). I + don't like to see warnings from my code, but since I still want to + keep it readable, I simply switch off a few warnings instead of adding + the tons of casts that VC++ seem to require. This code is compiled + with numerous other compilers as well, so any real errors are likely + to be catched anyway. */ +#pragma warning(disable: 4244) /* conversion from 'float' to 'int' */ +#endif + +#if defined(_MSC_VER) +#define inline __inline +#elif !defined(USE_INLINE) +#define inline +#endif + +#if SIZEOF_SHORT == 2 +#define INT16 short +#elif SIZEOF_INT == 2 +#define INT16 int +#else +#define INT16 short /* most things works just fine anyway... */ +#endif + +#if SIZEOF_SHORT == 4 +#define INT32 short +#elif SIZEOF_INT == 4 +#define INT32 int +#elif SIZEOF_LONG == 4 +#define INT32 long +#else +#error Cannot find required 32-bit integer type +#endif + +#if SIZEOF_LONG == 8 +#define INT64 long +#elif SIZEOF_LONG_LONG == 8 +#define INT64 long +#endif + +/* assume IEEE; tweak if necessary (patches are welcome) */ +#define FLOAT32 float +#define FLOAT64 double + +#define INT8 signed char +#define UINT8 unsigned char + +#define UINT16 unsigned INT16 +#define UINT32 unsigned INT32 diff --git a/EffectLab/Makefile b/EffectLab/Makefile new file mode 100644 index 0000000..918c997 --- /dev/null +++ b/EffectLab/Makefile @@ -0,0 +1,5 @@ +EffectLabCore.so: core.c + gcc -I/usr/include/python2.7 -fPIC -shared core.c -o EffectLabCore.so + +clean: + rm *.so \ No newline at end of file diff --git a/EffectLab/core.c b/EffectLab/core.c new file mode 100644 index 0000000..d6eab86 --- /dev/null +++ b/EffectLab/core.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include "ImPlatform.h" + +/* 1.9.1 pil */ + +typedef struct ImagingMemoryInstance* Imaging; +typedef struct ImagingAccessInstance* ImagingAccess; +typedef struct ImagingPaletteInstance* ImagingPalette; + +struct ImagingMemoryInstance { + + /* Format */ + char mode[6+1]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */ + int type; /* Data type (IMAGING_TYPE_*) */ + int depth; /* Depth (ignored in this version) */ + int bands; /* Number of bands (1, 2, 3, or 4) */ + int xsize; /* Image dimension. */ + int ysize; + + /* Colour palette (for "P" images only) */ + ImagingPalette palette; + + /* Data pointers */ + UINT8 **image8; /* Set for 8-bit images (pixelsize=1). */ + INT32 **image32; /* Set for 32-bit images (pixelsize=4). */ + + /* Internals */ + char **image; /* Actual raster data. */ + char *block; /* Set if data is allocated in a single block. */ + + int pixelsize; /* Size of a pixel, in bytes (1, 2 or 4) */ + int linesize; /* Size of a line, in bytes (xsize * pixelsize) */ + + /* Virtual methods */ + void (*destroy)(Imaging im); +}; + + +struct ImagingAccessInstance { + const char* mode; + void* (*line)(Imaging im, int i, int j); + void (*get_pixel)(Imaging im, int i, int j, void* pixel); + void (*put_pixel)(Imaging im, int i, int j, const void* pixel); +}; + +struct ImagingPaletteInstance { + + /* Format */ + char mode[4+1]; /* Band names */ + + /* Data */ + UINT8 palette[1024];/* Palette data (same format as image data) */ + + INT16* cache; /* Palette cache (used for predefined palettes) */ + int keep_cache; /* This palette will be reused; keep cache */ + +}; + +typedef struct { + PyObject_HEAD + Imaging image; + ImagingAccess access; +} ImagingObject; + + +static PyObject* global_warp(PyObject *self, PyObject *args) +{ + const char *text; + int result; + PyObject *image; + PyObject *newimage; + ImagingObject *core; + Imaging imIn, imOut; + int i, j, ai, aj; + int found, rsum, gsum, bsum, asum; + int antialias; + double xx, yy; + int width, height; + double i2, j2; + double xnew, ynew; + int index; + UINT8 *pixel; + + double phi,radius,radius2; + double xtmp,ytmp; + double denom; + int i3, j3; + + + if (!PyArg_ParseTuple(args, "O", &image)) + { + return NULL; + } + + if ((core = (ImagingObject *)PyObject_GetAttrString(image, "im")) == NULL) + { + return NULL; + } + imIn = core->image; + + /* copy a new image */ + newimage = PyObject_CallMethod(image, "copy", NULL); + if ((core = (ImagingObject *)PyObject_GetAttrString(newimage, "im")) == NULL) + { + return NULL; + } + imOut = core->image; + + width = imIn->xsize; + height = imIn->ysize; + + antialias = 4; + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + found = 0; + rsum = 0; + gsum = 0; + bsum = 0; + asum = 0; + + pixel = imOut->image[j]; + pixel += i * 4; + pixel[0] = 128; + pixel[1] = 128; + pixel[2] = 128; + pixel[3] = 128; + + for (ai = 0; ai < antialias; ai++) + { + xx = 2.0 * (i + ai / (double)antialias) / width - 1; + + for (aj = 0; aj < antialias; aj++) + { + yy = 2.0 * (j + aj / (double)antialias) / height - 1; + + xnew = xx; + ynew = yy; + + /* ----------- */ + radius2 = xx * xx + yy * yy; + radius = sqrt(radius2); + phi = atan2(yy, xx); + + radius = sqrt(radius); + xnew = radius * cos(phi); + ynew = radius * sin(phi); + + /* ------------------------- */ + + i2 = 0.5 * width * (xnew + 1); + j2 = 0.5 * height * (ynew + 1); + + i3 = round(i2); + j3 = round(j2); + + if (i3 < 0 || i3 >= width || j3 < 0 || j3 >= height) + { + continue; + } + + pixel = (UINT8*)imIn->image[j3]; + pixel += i3 * 4; + + rsum += pixel[0]; + gsum += pixel[1]; + bsum += pixel[2]; + asum += pixel[3]; + found++; + } + } + + + if (found > 0) + { + pixel = imOut->image[j]; + pixel += i * 4; + pixel[0] = rsum / found; + pixel[1] = gsum / found; + pixel[2] = bsum / found; + pixel[3] = asum / found; + } + } + } + + return (PyObject *)newimage; +} + +static PyMethodDef CoreMethods[] = { + {"global_warp", global_warp, METH_VARARGS, "Global warp"}, + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC initEffectLabCore() +{ + Py_InitModule("EffectLabCore", CoreMethods); +} diff --git a/TestEffectLab.py b/TestEffectLab.py index 6cdadb4..331eb3a 100755 --- a/TestEffectLab.py +++ b/TestEffectLab.py @@ -39,13 +39,13 @@ def main(): print 'Started' effects = [ - LocalWarpEffect((50, 20), (80, 40), 30), + # LocalWarpEffect((50, 20), (80, 40), 30), RadianSqrtEffect(), - LensWarpEffect(lambda x, y: (sign(x) * x ** 2, sign(y) * y ** 2)), - RadianFormulaEffect(lambda r, phi: (r ** 2, phi), 4), - GlobalWaveEffect(), - LensWarpEffect(lambda x, y: (sin(x * math.pi / 2), sin(y * math.pi / 2))), - RadianFormulaEffect(lambda r, phi: (r ** 1.5 * math.cos(r), phi)), + # LensWarpEffect(lambda x, y: (sign(x) * x ** 2, sign(y) * y ** 2)), + # RadianFormulaEffect(lambda r, phi: (r ** 2, phi), 4), + # GlobalWaveEffect(), + # LensWarpEffect(lambda x, y: (sin(x * math.pi / 2), sin(y * math.pi / 2))), + # RadianFormulaEffect(lambda r, phi: (r ** 1.5 * math.cos(r), phi)), ] # if os.path.exists('z.jpg'): @@ -78,10 +78,12 @@ def main(): offset += char_img[last].width - 1 for index, effect in enumerate(effects): - merge_origin_and_new(img, effect).save('%d.jpg' % index, quality=90) + for i in xrange(100): + merge_origin_and_new(img, effect).save('tmp/%d-%d.jpg' % (index, i), quality=90) print '.', print 'done' if __name__ == '__main__': - autoreload.main(main) + # autoreload.main(main) + main()