mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-10 19:56:47 +03:00
Merge pull request #4230 from dwastberg/new_chops
Added three new channel operations
This commit is contained in:
commit
c6115c1ceb
|
@ -38,6 +38,10 @@ def test_sanity():
|
|||
ImageChops.blend(im, im, 0.5)
|
||||
ImageChops.composite(im, im, im)
|
||||
|
||||
ImageChops.soft_light(im, im)
|
||||
ImageChops.hard_light(im, im)
|
||||
ImageChops.overlay(im, im)
|
||||
|
||||
ImageChops.offset(im, 10)
|
||||
ImageChops.offset(im, 10, 20)
|
||||
|
||||
|
@ -209,8 +213,8 @@ def test_lighter_image():
|
|||
# Act
|
||||
new = ImageChops.lighter(im1, im2)
|
||||
|
||||
# Assert
|
||||
assert_image_equal(new, im1)
|
||||
# Assert
|
||||
assert_image_equal(new, im1)
|
||||
|
||||
|
||||
def test_lighter_pixel():
|
||||
|
@ -275,13 +279,13 @@ def test_offset():
|
|||
# Act
|
||||
new = ImageChops.offset(im, xoffset, yoffset)
|
||||
|
||||
# Assert
|
||||
assert new.getbbox() == (0, 45, 100, 96)
|
||||
assert new.getpixel((50, 50)) == BLACK
|
||||
assert new.getpixel((50 + xoffset, 50 + yoffset)) == DARK_GREEN
|
||||
# Assert
|
||||
assert new.getbbox() == (0, 45, 100, 96)
|
||||
assert new.getpixel((50, 50)) == BLACK
|
||||
assert new.getpixel((50 + xoffset, 50 + yoffset)) == DARK_GREEN
|
||||
|
||||
# Test no yoffset
|
||||
assert ImageChops.offset(im, xoffset) == ImageChops.offset(im, xoffset, xoffset)
|
||||
# Test no yoffset
|
||||
assert ImageChops.offset(im, xoffset) == ImageChops.offset(im, xoffset, xoffset)
|
||||
|
||||
|
||||
def test_screen():
|
||||
|
@ -362,6 +366,45 @@ def test_subtract_modulo_no_clip():
|
|||
assert new.getpixel((50, 50)) == (241, 167, 127)
|
||||
|
||||
|
||||
def test_soft_light():
|
||||
# Arrange
|
||||
im1 = Image.open("Tests/images/hopper.png")
|
||||
im2 = Image.open("Tests/images/hopper-XYZ.png")
|
||||
|
||||
# Act
|
||||
new = ImageChops.soft_light(im1, im2)
|
||||
|
||||
# Assert
|
||||
assert new.getpixel((64, 64)) == (163, 54, 32)
|
||||
assert new.getpixel((15, 100)) == (1, 1, 3)
|
||||
|
||||
|
||||
def test_hard_light():
|
||||
# Arrange
|
||||
im1 = Image.open("Tests/images/hopper.png")
|
||||
im2 = Image.open("Tests/images/hopper-XYZ.png")
|
||||
|
||||
# Act
|
||||
new = ImageChops.hard_light(im1, im2)
|
||||
|
||||
# Assert
|
||||
assert new.getpixel((64, 64)) == (144, 50, 27)
|
||||
assert new.getpixel((15, 100)) == (1, 1, 2)
|
||||
|
||||
|
||||
def test_overlay():
|
||||
# Arrange
|
||||
im1 = Image.open("Tests/images/hopper.png")
|
||||
im2 = Image.open("Tests/images/hopper-XYZ.png")
|
||||
|
||||
# Act
|
||||
new = ImageChops.overlay(im1, im2)
|
||||
|
||||
# Assert
|
||||
assert new.getpixel((64, 64)) == (159, 50, 27)
|
||||
assert new.getpixel((15, 100)) == (1, 1, 2)
|
||||
|
||||
|
||||
def test_logical():
|
||||
def table(op, a, b):
|
||||
out = []
|
||||
|
|
|
@ -36,6 +36,9 @@ operations in this module).
|
|||
.. autofunction:: PIL.ImageChops.logical_or
|
||||
.. autofunction:: PIL.ImageChops.logical_xor
|
||||
.. autofunction:: PIL.ImageChops.multiply
|
||||
.. autofunction:: PIL.ImageChops.soft_light
|
||||
.. autofunction:: PIL.ImageChops.hard_light
|
||||
.. autofunction:: PIL.ImageChops.overlay
|
||||
.. py:method:: PIL.ImageChops.offset(image, xoffset, yoffset=None)
|
||||
|
||||
Returns a copy of the image where data has been offset by the given
|
||||
|
|
|
@ -139,6 +139,42 @@ def screen(image1, image2):
|
|||
return image1._new(image1.im.chop_screen(image2.im))
|
||||
|
||||
|
||||
def soft_light(image1, image2):
|
||||
"""
|
||||
Superimposes two images on top of each other using the Soft Light algorithm
|
||||
|
||||
:rtype: :py:class:`~PIL.Image.Image`
|
||||
"""
|
||||
|
||||
image1.load()
|
||||
image2.load()
|
||||
return image1._new(image1.im.chop_soft_light(image2.im))
|
||||
|
||||
|
||||
def hard_light(image1, image2):
|
||||
"""
|
||||
Superimposes two images on top of each other using the Hard Light algorithm
|
||||
|
||||
:rtype: :py:class:`~PIL.Image.Image`
|
||||
"""
|
||||
|
||||
image1.load()
|
||||
image2.load()
|
||||
return image1._new(image1.im.chop_hard_light(image2.im))
|
||||
|
||||
|
||||
def overlay(image1, image2):
|
||||
"""
|
||||
Superimposes two images on top of each other using the Overlay algorithm
|
||||
|
||||
:rtype: :py:class:`~PIL.Image.Image`
|
||||
"""
|
||||
|
||||
image1.load()
|
||||
image2.load()
|
||||
return image1._new(image1.im.chop_overlay(image2.im))
|
||||
|
||||
|
||||
def add(image1, image2, scale=1.0, offset=0):
|
||||
"""
|
||||
Adds two images, dividing the result by scale and adding the
|
||||
|
|
|
@ -2406,6 +2406,38 @@ _chop_subtract_modulo(ImagingObject* self, PyObject* args)
|
|||
return PyImagingNew(ImagingChopSubtractModulo(self->image, imagep->image));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
_chop_soft_light(ImagingObject* self, PyObject* args)
|
||||
{
|
||||
ImagingObject* imagep;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
|
||||
return NULL;
|
||||
|
||||
return PyImagingNew(ImagingChopSoftLight(self->image, imagep->image));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
_chop_hard_light(ImagingObject* self, PyObject* args)
|
||||
{
|
||||
ImagingObject* imagep;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
|
||||
return NULL;
|
||||
|
||||
return PyImagingNew(ImagingChopHardLight(self->image, imagep->image));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
_chop_overlay(ImagingObject* self, PyObject* args)
|
||||
{
|
||||
ImagingObject* imagep;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
|
||||
return NULL;
|
||||
|
||||
return PyImagingNew(ImagingOverlay(self->image, imagep->image));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -3325,6 +3357,10 @@ static struct PyMethodDef methods[] = {
|
|||
{"chop_and", (PyCFunction)_chop_and, 1},
|
||||
{"chop_or", (PyCFunction)_chop_or, 1},
|
||||
{"chop_xor", (PyCFunction)_chop_xor, 1},
|
||||
{"chop_soft_light", (PyCFunction)_chop_soft_light, 1},
|
||||
{"chop_hard_light", (PyCFunction)_chop_hard_light, 1},
|
||||
{"chop_overlay", (PyCFunction)_chop_overlay, 1},
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WITH_UNSHARPMASK
|
||||
|
|
|
@ -146,3 +146,27 @@ ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2)
|
|||
{
|
||||
CHOP2(in1[x] - in2[x], NULL);
|
||||
}
|
||||
|
||||
Imaging
|
||||
ImagingChopSoftLight(Imaging imIn1, Imaging imIn2)
|
||||
{
|
||||
CHOP2( (((255-in1[x]) * (in1[x]*in2[x]) ) / 65536) +
|
||||
(in1[x] * ( 255 - ( (255 - in1[x]) * (255 - in2[x] ) / 255) )) / 255
|
||||
, NULL );
|
||||
}
|
||||
|
||||
Imaging
|
||||
ImagingChopHardLight(Imaging imIn1, Imaging imIn2)
|
||||
{
|
||||
CHOP2( (in2[x]<128) ? ( (in1[x]*in2[x])/127)
|
||||
: 255 - ( ((255-in2[x]) * (255-in1[x])) / 127)
|
||||
, NULL);
|
||||
}
|
||||
|
||||
Imaging
|
||||
ImagingOverlay(Imaging imIn1, Imaging imIn2)
|
||||
{
|
||||
CHOP2( (in1[x]<128) ? ( (in1[x]*in2[x])/127)
|
||||
: 255 - ( ((255-in1[x]) * (255-in2[x])) / 127)
|
||||
, NULL);
|
||||
}
|
||||
|
|
|
@ -339,6 +339,9 @@ extern Imaging ImagingChopSubtract(
|
|||
Imaging imIn1, Imaging imIn2, float scale, int offset);
|
||||
extern Imaging ImagingChopAddModulo(Imaging imIn1, Imaging imIn2);
|
||||
extern Imaging ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2);
|
||||
extern Imaging ImagingChopSoftLight(Imaging imIn1, Imaging imIn2);
|
||||
extern Imaging ImagingChopHardLight(Imaging imIn1, Imaging imIn2);
|
||||
extern Imaging ImagingOverlay(Imaging imIn1, Imaging imIn2);
|
||||
|
||||
/* "1" images only */
|
||||
extern Imaging ImagingChopAnd(Imaging imIn1, Imaging imIn2);
|
||||
|
|
Loading…
Reference in New Issue
Block a user