From e414c660709d233df3a2dfbe69cf0500297d6c47 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Tue, 4 Dec 2012 16:44:26 +0100 Subject: [PATCH] Add Image.alpha_composite --- PIL/Image.py | 15 ++++++ _imaging.c | 15 ++++++ libImaging/AlphaComposite.c | 94 +++++++++++++++++++++++++++++++++++++ libImaging/Imaging.h | 1 + setup.py | 4 +- 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 libImaging/AlphaComposite.c diff --git a/PIL/Image.py b/PIL/Image.py index e97623888..aa87fb472 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1980,6 +1980,21 @@ def open(fp, mode="r"): # # Image processing. +## +# Alpha composites im2 over im1. +# +# @param im1 The first image. +# @param im2 The second image. Must have the same mode and size as +# the first image. +# @return An Image object. + +def alpha_composite(im1, im2): + "Alpha composite im2 over im1." + + im1.load() + im2.load() + return im1._new(core.alpha_composite(im1.im, im2.im)) + ## # Creates a new image by interpolating between two input images, using # a constant alpha. diff --git a/_imaging.c b/_imaging.c index c21897dec..9afa08812 100644 --- a/_imaging.c +++ b/_imaging.c @@ -694,6 +694,20 @@ _open_ppm(PyObject* self, PyObject* args) return PyImagingNew(ImagingOpenPPM(filename)); } +static PyObject* +_alpha_composite(ImagingObject* self, PyObject* args) +{ + ImagingObject* imagep1; + ImagingObject* imagep2; + + if (!PyArg_ParseTuple(args, "O!O!", + &Imaging_Type, &imagep1, + &Imaging_Type, &imagep2)) + return NULL; + + return PyImagingNew(ImagingAlphaComposite(imagep1->image, imagep2->image)); +} + static PyObject* _blend(ImagingObject* self, PyObject* args) { @@ -3152,6 +3166,7 @@ extern PyObject* PyImaging_MapBuffer(PyObject* self, PyObject* args); static PyMethodDef functions[] = { /* Object factories */ + {"alpha_composite", (PyCFunction)_alpha_composite, 1}, {"blend", (PyCFunction)_blend, 1}, {"fill", (PyCFunction)_fill, 1}, {"new", (PyCFunction)_new, 1}, diff --git a/libImaging/AlphaComposite.c b/libImaging/AlphaComposite.c new file mode 100644 index 000000000..28404fd53 --- /dev/null +++ b/libImaging/AlphaComposite.c @@ -0,0 +1,94 @@ +/* + * The Python Imaging Library + * $Id$ + * + * Alpha composite imSrc over imDst. + * http://en.wikipedia.org/wiki/Alpha_compositing + * + * See the README file for details on usage and redistribution. + */ + + +#include "Imaging.h" + + +Imaging +ImagingAlphaComposite(Imaging imDst, Imaging imSrc) +{ + Imaging imOut; + int x, y; + float dstR, dstG, dstB, dstA; + float srcR, srcG, srcB, srcA; + float outR, outG, outB, outA; + + /* Check arguments */ + if (!imDst || !imSrc || + strcmp(imDst->mode, "RGBA") || + imDst->type != IMAGING_TYPE_UINT8 || + imDst->bands != 4) + return ImagingError_ModeError(); + if (strcmp(imDst->mode, imSrc->mode) || + imDst->type != imSrc->type || + imDst->bands != imSrc->bands || + imDst->xsize != imSrc->xsize || + imDst->ysize != imSrc->ysize) + return ImagingError_Mismatch(); + + imOut = ImagingNew(imDst->mode, imDst->xsize, imDst->ysize); + if (!imOut) + return NULL; + + ImagingCopyInfo(imOut, imDst); + + for (y = 0; y < imDst->ysize; y++) { + + UINT8* dst = (UINT8*) imDst->image[y]; + UINT8* src = (UINT8*) imSrc->image[y]; + UINT8* out = (UINT8*) imOut->image[y]; + + for (x = 0; x < imDst->linesize; x += 4) { + + dstR = dst[x + 0] / 255.0; + dstG = dst[x + 1] / 255.0; + dstB = dst[x + 2] / 255.0; + dstA = dst[x + 3] / 255.0; + + srcR = src[x + 0] / 255.0; + srcG = src[x + 1] / 255.0; + srcB = src[x + 2] / 255.0; + srcA = src[x + 3] / 255.0; + + if (dstA == 1.0) { + outR = srcR * srcA + dstR * (1.0 - srcA); + outG = srcG * srcA + dstG * (1.0 - srcA); + outB = srcB * srcA + dstB * (1.0 - srcA); + outA = 1.0; + } else if (srcA == 0.0) { + outR = dstR; + outG = dstG; + outB = dstB; + outA = dstA; + } else { + outA = srcA + dstA * (1.0 - srcA); + if (outA == 0.0) { + outR = 0.0; + outG = 0.0; + outB = 0.0; + } else { + outR = (srcR * srcA + dstR * dstA * (1.0 - srcA)) / outA; + outG = (srcG * srcA + dstG * dstA * (1.0 - srcA)) / outA; + outB = (srcB * srcA + dstB * dstA * (1.0 - srcA)) / outA; + } + } + + out[x + 0] = (UINT8) (255.0 * outR); + out[x + 1] = (UINT8) (255.0 * outG); + out[x + 2] = (UINT8) (255.0 * outB); + out[x + 3] = (UINT8) (255.0 * outA); + + } + + } + + return imOut; +} diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index 4609376ad..e2033022a 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -239,6 +239,7 @@ typedef int (*ImagingTransformFilter)(void* out, Imaging im, /* Image Manipulation Methods */ /* -------------------------- */ +extern Imaging ImagingAlphaComposite(Imaging imIn1, Imaging imIn2); extern Imaging ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha); extern Imaging ImagingCopy(Imaging im); extern Imaging ImagingConvert(Imaging im, const char* mode, ImagingPalette palette, int dither); diff --git a/setup.py b/setup.py index bdf6bc911..79f659146 100644 --- a/setup.py +++ b/setup.py @@ -15,8 +15,8 @@ _IMAGING = ( ) _LIB_IMAGING = ( - "Access", "Antialias", "Bands", "BitDecode", "Blend", "Chops", - "Convert", "ConvertYCbCr", "Copy", "Crc32", "Crop", "Dib", "Draw", + "Access", "AlphaComposite", "Antialias", "Bands", "BitDecode", "Blend", + "Chops", "Convert", "ConvertYCbCr", "Copy", "Crc32", "Crop", "Dib", "Draw", "Effects", "EpsEncode", "File", "Fill", "Filter", "FliDecode", "Geometry", "GetBBox", "GifDecode", "GifEncode", "HexDecode", "Histo", "JpegDecode", "JpegEncode", "LzwDecode", "Matrix",