mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-24 17:06:16 +03:00
Merge pull request #7123 from radarhere/apng
This commit is contained in:
commit
be4bfaac9e
|
@ -374,6 +374,20 @@ def test_apng_save(tmp_path):
|
||||||
assert im.getpixel((64, 32)) == (0, 255, 0, 255)
|
assert im.getpixel((64, 32)) == (0, 255, 0, 255)
|
||||||
|
|
||||||
|
|
||||||
|
def test_apng_save_alpha(tmp_path):
|
||||||
|
test_file = str(tmp_path / "temp.png")
|
||||||
|
|
||||||
|
im = Image.new("RGBA", (1, 1), (255, 0, 0, 255))
|
||||||
|
im2 = Image.new("RGBA", (1, 1), (255, 0, 0, 127))
|
||||||
|
im.save(test_file, save_all=True, append_images=[im2])
|
||||||
|
|
||||||
|
with Image.open(test_file) as reloaded:
|
||||||
|
assert reloaded.getpixel((0, 0)) == (255, 0, 0, 255)
|
||||||
|
|
||||||
|
reloaded.seek(1)
|
||||||
|
assert reloaded.getpixel((0, 0)) == (255, 0, 0, 127)
|
||||||
|
|
||||||
|
|
||||||
def test_apng_save_split_fdat(tmp_path):
|
def test_apng_save_split_fdat(tmp_path):
|
||||||
# test to make sure we do not generate sequence errors when writing
|
# test to make sure we do not generate sequence errors when writing
|
||||||
# frames with image data spanning multiple fdAT chunks (in this case
|
# frames with image data spanning multiple fdAT chunks (in this case
|
||||||
|
|
|
@ -1130,6 +1130,18 @@ def test_bbox(tmp_path):
|
||||||
assert reread.n_frames == 2
|
assert reread.n_frames == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_bbox_alpha(tmp_path):
|
||||||
|
out = str(tmp_path / "temp.gif")
|
||||||
|
|
||||||
|
im = Image.new("RGBA", (1, 2), (255, 0, 0, 255))
|
||||||
|
im.putpixel((0, 1), (255, 0, 0, 0))
|
||||||
|
im2 = Image.new("RGBA", (1, 2), (255, 0, 0, 0))
|
||||||
|
im.save(out, save_all=True, append_images=[im2])
|
||||||
|
|
||||||
|
with Image.open(out) as reread:
|
||||||
|
assert reread.n_frames == 2
|
||||||
|
|
||||||
|
|
||||||
def test_palette_save_L(tmp_path):
|
def test_palette_save_L(tmp_path):
|
||||||
# Generate an L mode image with a separate palette
|
# Generate an L mode image with a separate palette
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import hopper
|
from .helper import hopper
|
||||||
|
@ -38,3 +40,16 @@ def test_bbox():
|
||||||
for color in ((0, 0), (127, 0), (255, 0)):
|
for color in ((0, 0), (127, 0), (255, 0)):
|
||||||
im = Image.new(mode, (100, 100), color)
|
im = Image.new(mode, (100, 100), color)
|
||||||
check(im, (255, 255))
|
check(im, (255, 255))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("mode", ("RGBA", "RGBa", "La", "LA", "PA"))
|
||||||
|
def test_bbox_alpha_only_false(mode):
|
||||||
|
im = Image.new(mode, (100, 100))
|
||||||
|
assert im.getbbox(alpha_only=False) is None
|
||||||
|
|
||||||
|
fill_color = [1] * Image.getmodebands(mode)
|
||||||
|
fill_color[-1] = 0
|
||||||
|
im.paste(tuple(fill_color), (25, 25, 75, 75))
|
||||||
|
assert im.getbbox(alpha_only=False) == (25, 25, 75, 75)
|
||||||
|
|
||||||
|
assert im.getbbox() is None
|
||||||
|
|
|
@ -569,9 +569,9 @@ def _getbbox(base_im, im_frame):
|
||||||
delta = ImageChops.subtract_modulo(im_frame, base_im)
|
delta = ImageChops.subtract_modulo(im_frame, base_im)
|
||||||
else:
|
else:
|
||||||
delta = ImageChops.subtract_modulo(
|
delta = ImageChops.subtract_modulo(
|
||||||
im_frame.convert("RGB"), base_im.convert("RGB")
|
im_frame.convert("RGBA"), base_im.convert("RGBA")
|
||||||
)
|
)
|
||||||
return delta.getbbox()
|
return delta.getbbox(alpha_only=False)
|
||||||
|
|
||||||
|
|
||||||
def _write_multiple_frames(im, fp, palette):
|
def _write_multiple_frames(im, fp, palette):
|
||||||
|
|
|
@ -1292,11 +1292,15 @@ class Image:
|
||||||
"""
|
"""
|
||||||
return ImageMode.getmode(self.mode).bands
|
return ImageMode.getmode(self.mode).bands
|
||||||
|
|
||||||
def getbbox(self):
|
def getbbox(self, *, alpha_only=True):
|
||||||
"""
|
"""
|
||||||
Calculates the bounding box of the non-zero regions in the
|
Calculates the bounding box of the non-zero regions in the
|
||||||
image.
|
image.
|
||||||
|
|
||||||
|
:param alpha_only: Optional flag, defaulting to ``True``.
|
||||||
|
If ``True`` and the image has an alpha channel, trim transparent pixels.
|
||||||
|
Otherwise, trim pixels when all channels are zero.
|
||||||
|
Keyword-only argument.
|
||||||
:returns: The bounding box is returned as a 4-tuple defining the
|
:returns: The bounding box is returned as a 4-tuple defining the
|
||||||
left, upper, right, and lower pixel coordinate. See
|
left, upper, right, and lower pixel coordinate. See
|
||||||
:ref:`coordinate-system`. If the image is completely empty, this
|
:ref:`coordinate-system`. If the image is completely empty, this
|
||||||
|
@ -1305,7 +1309,7 @@ class Image:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.load()
|
self.load()
|
||||||
return self.im.getbbox()
|
return self.im.getbbox(alpha_only)
|
||||||
|
|
||||||
def getcolors(self, maxcolors=256):
|
def getcolors(self, maxcolors=256):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1138,9 +1138,9 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images)
|
||||||
else:
|
else:
|
||||||
base_im = previous["im"]
|
base_im = previous["im"]
|
||||||
delta = ImageChops.subtract_modulo(
|
delta = ImageChops.subtract_modulo(
|
||||||
im_frame.convert("RGB"), base_im.convert("RGB")
|
im_frame.convert("RGBA"), base_im.convert("RGBA")
|
||||||
)
|
)
|
||||||
bbox = delta.getbbox()
|
bbox = delta.getbbox(alpha_only=False)
|
||||||
if (
|
if (
|
||||||
not bbox
|
not bbox
|
||||||
and prev_disposal == encoderinfo.get("disposal")
|
and prev_disposal == encoderinfo.get("disposal")
|
||||||
|
|
|
@ -2159,9 +2159,15 @@ _isblock(ImagingObject *self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_getbbox(ImagingObject *self) {
|
_getbbox(ImagingObject *self, PyObject *args) {
|
||||||
int bbox[4];
|
int bbox[4];
|
||||||
if (!ImagingGetBBox(self->image, bbox)) {
|
|
||||||
|
int alpha_only = 1;
|
||||||
|
if (!PyArg_ParseTuple(args, "|i", &alpha_only)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ImagingGetBBox(self->image, bbox, alpha_only)) {
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
@ -3573,7 +3579,7 @@ static struct PyMethodDef methods[] = {
|
||||||
|
|
||||||
{"isblock", (PyCFunction)_isblock, METH_NOARGS},
|
{"isblock", (PyCFunction)_isblock, METH_NOARGS},
|
||||||
|
|
||||||
{"getbbox", (PyCFunction)_getbbox, METH_NOARGS},
|
{"getbbox", (PyCFunction)_getbbox, METH_VARARGS},
|
||||||
{"getcolors", (PyCFunction)_getcolors, METH_VARARGS},
|
{"getcolors", (PyCFunction)_getcolors, METH_VARARGS},
|
||||||
{"getextrema", (PyCFunction)_getextrema, METH_NOARGS},
|
{"getextrema", (PyCFunction)_getextrema, METH_NOARGS},
|
||||||
{"getprojection", (PyCFunction)_getprojection, METH_NOARGS},
|
{"getprojection", (PyCFunction)_getprojection, METH_NOARGS},
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "Imaging.h"
|
#include "Imaging.h"
|
||||||
|
|
||||||
int
|
int
|
||||||
ImagingGetBBox(Imaging im, int bbox[4]) {
|
ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) {
|
||||||
/* Get the bounding box for any non-zero data in the image.*/
|
/* Get the bounding box for any non-zero data in the image.*/
|
||||||
|
|
||||||
int x, y;
|
int x, y;
|
||||||
|
@ -58,10 +58,11 @@ ImagingGetBBox(Imaging im, int bbox[4]) {
|
||||||
INT32 mask = 0xffffffff;
|
INT32 mask = 0xffffffff;
|
||||||
if (im->bands == 3) {
|
if (im->bands == 3) {
|
||||||
((UINT8 *)&mask)[3] = 0;
|
((UINT8 *)&mask)[3] = 0;
|
||||||
} else if (
|
} else if (alpha_only && (
|
||||||
strcmp(im->mode, "RGBa") == 0 || strcmp(im->mode, "RGBA") == 0 ||
|
strcmp(im->mode, "RGBa") == 0 || strcmp(im->mode, "RGBA") == 0 ||
|
||||||
strcmp(im->mode, "La") == 0 || strcmp(im->mode, "LA") == 0 ||
|
strcmp(im->mode, "La") == 0 || strcmp(im->mode, "LA") == 0 ||
|
||||||
strcmp(im->mode, "PA") == 0) {
|
strcmp(im->mode, "PA") == 0
|
||||||
|
)) {
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
mask = 0x000000ff;
|
mask = 0x000000ff;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -317,7 +317,7 @@ ImagingMerge(const char *mode, Imaging bands[4]);
|
||||||
extern int
|
extern int
|
||||||
ImagingSplit(Imaging im, Imaging bands[4]);
|
ImagingSplit(Imaging im, Imaging bands[4]);
|
||||||
extern int
|
extern int
|
||||||
ImagingGetBBox(Imaging im, int bbox[4]);
|
ImagingGetBBox(Imaging im, int bbox[4], int alpha_only);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int x, y;
|
int x, y;
|
||||||
INT32 count;
|
INT32 count;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user