mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 17:36:18 +03:00
Merge branch 'main' into scale
This commit is contained in:
commit
5cb736d953
47
.github/workflows/wheels-dependencies.sh
vendored
47
.github/workflows/wheels-dependencies.sh
vendored
|
@ -16,7 +16,11 @@ ARCHIVE_SDIR=pillow-depends-main
|
|||
|
||||
# Package versions for fresh source builds
|
||||
FREETYPE_VERSION=2.13.2
|
||||
HARFBUZZ_VERSION=8.5.0
|
||||
if [[ "$MB_ML_VER" != 2014 ]]; then
|
||||
HARFBUZZ_VERSION=9.0.0
|
||||
else
|
||||
HARFBUZZ_VERSION=8.5.0
|
||||
fi
|
||||
LIBPNG_VERSION=1.6.43
|
||||
JPEGTURBO_VERSION=3.0.3
|
||||
OPENJPEG_VERSION=2.5.2
|
||||
|
@ -40,7 +44,7 @@ BROTLI_VERSION=1.1.0
|
|||
|
||||
if [[ -n "$IS_MACOS" ]] && [[ "$CIBW_ARCHS" == "x86_64" ]]; then
|
||||
function build_openjpeg {
|
||||
local out_dir=$(fetch_unpack https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz openjpeg-${OPENJPEG_VERSION}.tar.gz)
|
||||
local out_dir=$(fetch_unpack https://github.com/uclouvain/openjpeg/archive/v$OPENJPEG_VERSION.tar.gz openjpeg-$OPENJPEG_VERSION.tar.gz)
|
||||
(cd $out_dir \
|
||||
&& cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib . \
|
||||
&& make install)
|
||||
|
@ -50,7 +54,7 @@ fi
|
|||
|
||||
function build_brotli {
|
||||
local cmake=$(get_modern_cmake)
|
||||
local out_dir=$(fetch_unpack https://github.com/google/brotli/archive/v$BROTLI_VERSION.tar.gz brotli-1.1.0.tar.gz)
|
||||
local out_dir=$(fetch_unpack https://github.com/google/brotli/archive/v$BROTLI_VERSION.tar.gz brotli-$BROTLI_VERSION.tar.gz)
|
||||
(cd $out_dir \
|
||||
&& $cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib . \
|
||||
&& make install)
|
||||
|
@ -60,6 +64,25 @@ function build_brotli {
|
|||
fi
|
||||
}
|
||||
|
||||
function build_harfbuzz {
|
||||
if [[ "$HARFBUZZ_VERSION" == 8.5.0 ]]; then
|
||||
export FREETYPE_LIBS=-lfreetype
|
||||
export FREETYPE_CFLAGS=-I/usr/local/include/freetype2/
|
||||
build_simple harfbuzz $HARFBUZZ_VERSION https://github.com/harfbuzz/harfbuzz/releases/download/$HARFBUZZ_VERSION tar.xz --with-freetype=yes --with-glib=no
|
||||
export FREETYPE_LIBS=""
|
||||
export FREETYPE_CFLAGS=""
|
||||
else
|
||||
local out_dir=$(fetch_unpack https://github.com/harfbuzz/harfbuzz/releases/download/$HARFBUZZ_VERSION/$HARFBUZZ_VERSION.tar.xz harfbuzz-$HARFBUZZ_VERSION.tar.xz)
|
||||
(cd $out_dir \
|
||||
&& meson setup build --buildtype=release -Dfreetype=enabled -Dglib=disabled)
|
||||
(cd $out_dir/build \
|
||||
&& meson install)
|
||||
if [[ "$MB_ML_LIBC" == "manylinux" ]]; then
|
||||
cp /usr/local/lib64/libharfbuzz* /usr/local/lib
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function build {
|
||||
if [[ -n "$IS_MACOS" ]] && [[ "$CIBW_ARCHS" == "arm64" ]]; then
|
||||
sudo chown -R runner /usr/local
|
||||
|
@ -109,15 +132,7 @@ function build {
|
|||
build_freetype
|
||||
fi
|
||||
|
||||
if [ -z "$IS_MACOS" ]; then
|
||||
export FREETYPE_LIBS=-lfreetype
|
||||
export FREETYPE_CFLAGS=-I/usr/local/include/freetype2/
|
||||
fi
|
||||
build_simple harfbuzz $HARFBUZZ_VERSION https://github.com/harfbuzz/harfbuzz/releases/download/$HARFBUZZ_VERSION tar.xz --with-freetype=yes --with-glib=no
|
||||
if [ -z "$IS_MACOS" ]; then
|
||||
export FREETYPE_LIBS=""
|
||||
export FREETYPE_CFLAGS=""
|
||||
fi
|
||||
build_harfbuzz
|
||||
}
|
||||
|
||||
# Any stuff that you need to do before you start building the wheels
|
||||
|
@ -140,7 +155,13 @@ if [[ -n "$IS_MACOS" ]]; then
|
|||
brew remove --ignore-dependencies webp
|
||||
fi
|
||||
|
||||
brew install pkg-config
|
||||
brew install meson pkg-config
|
||||
elif [[ "$MB_ML_LIBC" == "manylinux" ]]; then
|
||||
if [[ "$HARFBUZZ_VERSION" != 8.5.0 ]]; then
|
||||
yum install -y meson
|
||||
fi
|
||||
else
|
||||
apk add meson
|
||||
fi
|
||||
|
||||
wrap_wheel_builder build
|
||||
|
|
|
@ -5,6 +5,9 @@ Changelog (Pillow)
|
|||
11.0.0 (unreleased)
|
||||
-------------------
|
||||
|
||||
- Support converting more modes to LAB by converting to RGBA first #8358
|
||||
[radarhere]
|
||||
|
||||
- Deprecate support for FreeType 2.9.0 #8356
|
||||
[hugovk, radarhere]
|
||||
|
||||
|
|
|
@ -1117,6 +1117,10 @@ class TestImage:
|
|||
assert len(caplog.records) == 0
|
||||
assert im.fp is None
|
||||
|
||||
def test_deprecation(self) -> None:
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert not Image.isImageType(None)
|
||||
|
||||
|
||||
class TestImageBytes:
|
||||
@pytest.mark.parametrize("mode", Image.MODES + ["BGR;15", "BGR;16", "BGR;24"])
|
||||
|
|
|
@ -696,6 +696,12 @@ def test_rgb_lab(mode: str) -> None:
|
|||
assert value[:3] == (0, 255, 255)
|
||||
|
||||
|
||||
def test_cmyk_lab() -> None:
|
||||
im = Image.new("CMYK", (1, 1))
|
||||
converted_im = im.convert("LAB")
|
||||
assert converted_im.getpixel((0, 0)) == (255, 128, 128)
|
||||
|
||||
|
||||
def test_deprecation() -> None:
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert ImageCms.DESCRIPTION.strip().startswith("pyCMS")
|
||||
|
|
|
@ -130,6 +130,14 @@ ICNS (width, height, scale) sizes
|
|||
Setting an ICNS image size to ``(width, height, scale)`` before loading has been
|
||||
deprecated. Instead, ``load(scale)`` can be used.
|
||||
|
||||
Image isImageType()
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. deprecated:: 11.0.0
|
||||
|
||||
``Image.isImageType(im)`` has been deprecated. Use ``isinstance(im, Image.Image)``
|
||||
instead.
|
||||
|
||||
ImageMath.lambda_eval and ImageMath.unsafe_eval options parameter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -69,6 +69,14 @@ ICNS (width, height, scale) sizes
|
|||
Setting an ICNS image size to ``(width, height, scale)`` before loading has been
|
||||
deprecated. Instead, ``load(scale)`` can be used.
|
||||
|
||||
Image isImageType()
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. deprecated:: 11.0.0
|
||||
|
||||
``Image.isImageType(im)`` has been deprecated. Use ``isinstance(im, Image.Image)``
|
||||
instead.
|
||||
|
||||
ImageMath.lambda_eval and ImageMath.unsafe_eval options parameter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -133,6 +133,7 @@ def isImageType(t: Any) -> TypeGuard[Image]:
|
|||
:param t: object to check if it's an image
|
||||
:returns: True if the object is an image
|
||||
"""
|
||||
deprecate("Image.isImageType(im)", 12, "isinstance(im, Image.Image)")
|
||||
return hasattr(t, "im")
|
||||
|
||||
|
||||
|
@ -1130,17 +1131,23 @@ class Image:
|
|||
return new_im
|
||||
|
||||
if "LAB" in (self.mode, mode):
|
||||
other_mode = mode if self.mode == "LAB" else self.mode
|
||||
im = self
|
||||
if mode == "LAB":
|
||||
if im.mode not in ("RGB", "RGBA", "RGBX"):
|
||||
im = im.convert("RGBA")
|
||||
other_mode = im.mode
|
||||
else:
|
||||
other_mode = mode
|
||||
if other_mode in ("RGB", "RGBA", "RGBX"):
|
||||
from . import ImageCms
|
||||
|
||||
srgb = ImageCms.createProfile("sRGB")
|
||||
lab = ImageCms.createProfile("LAB")
|
||||
profiles = [lab, srgb] if self.mode == "LAB" else [srgb, lab]
|
||||
profiles = [lab, srgb] if im.mode == "LAB" else [srgb, lab]
|
||||
transform = ImageCms.buildTransform(
|
||||
profiles[0], profiles[1], self.mode, mode
|
||||
profiles[0], profiles[1], im.mode, mode
|
||||
)
|
||||
return transform.apply(self)
|
||||
return transform.apply(im)
|
||||
|
||||
# colorspace conversion
|
||||
if dither is None:
|
||||
|
@ -1817,23 +1824,22 @@ class Image:
|
|||
:param mask: An optional mask image.
|
||||
"""
|
||||
|
||||
if isImageType(box):
|
||||
if isinstance(box, Image):
|
||||
if mask is not None:
|
||||
msg = "If using second argument as mask, third argument must be None"
|
||||
raise ValueError(msg)
|
||||
# abbreviated paste(im, mask) syntax
|
||||
mask = box
|
||||
box = None
|
||||
assert not isinstance(box, Image)
|
||||
|
||||
if box is None:
|
||||
box = (0, 0)
|
||||
|
||||
if len(box) == 2:
|
||||
# upper left corner given; get size from image or mask
|
||||
if isImageType(im):
|
||||
if isinstance(im, Image):
|
||||
size = im.size
|
||||
elif isImageType(mask):
|
||||
elif isinstance(mask, Image):
|
||||
size = mask.size
|
||||
else:
|
||||
# FIXME: use self.size here?
|
||||
|
@ -1846,17 +1852,15 @@ class Image:
|
|||
from . import ImageColor
|
||||
|
||||
source = ImageColor.getcolor(im, self.mode)
|
||||
elif isImageType(im):
|
||||
elif isinstance(im, Image):
|
||||
im.load()
|
||||
if self.mode != im.mode:
|
||||
if self.mode != "RGB" or im.mode not in ("LA", "RGBA", "RGBa"):
|
||||
# should use an adapter for this!
|
||||
im = im.convert(self.mode)
|
||||
source = im.im
|
||||
elif isinstance(im, tuple):
|
||||
source = im
|
||||
else:
|
||||
source = cast(float, im)
|
||||
source = im
|
||||
|
||||
self._ensure_mutable()
|
||||
|
||||
|
@ -2017,7 +2021,7 @@ class Image:
|
|||
else:
|
||||
band = 3
|
||||
|
||||
if isImageType(alpha):
|
||||
if isinstance(alpha, Image):
|
||||
# alpha layer
|
||||
if alpha.mode not in ("1", "L"):
|
||||
msg = "illegal image mode"
|
||||
|
@ -2027,7 +2031,6 @@ class Image:
|
|||
alpha = alpha.convert("L")
|
||||
else:
|
||||
# constant alpha
|
||||
alpha = cast(int, alpha) # see python/typing#1013
|
||||
try:
|
||||
self.im.fillband(band, alpha)
|
||||
except (AttributeError, ValueError):
|
||||
|
|
|
@ -268,7 +268,7 @@ def lambda_eval(
|
|||
args.update(options)
|
||||
args.update(kw)
|
||||
for k, v in args.items():
|
||||
if hasattr(v, "im"):
|
||||
if isinstance(v, Image.Image):
|
||||
args[k] = _Operand(v)
|
||||
|
||||
out = expression(args)
|
||||
|
@ -319,7 +319,7 @@ def unsafe_eval(
|
|||
args.update(options)
|
||||
args.update(kw)
|
||||
for k, v in args.items():
|
||||
if hasattr(v, "im"):
|
||||
if isinstance(v, Image.Image):
|
||||
args[k] = _Operand(v)
|
||||
|
||||
compiled_code = compile(expression, "<string>", "eval")
|
||||
|
|
|
@ -31,7 +31,27 @@ ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) {
|
|||
bbox[2] = bbox[3] = 0;
|
||||
|
||||
#define GETBBOX(image, mask) \
|
||||
/* first stage: looking for any pixels from top */ \
|
||||
for (y = 0; y < im->ysize; y++) { \
|
||||
has_data = 0; \
|
||||
for (x = 0; x < im->xsize; x++) { \
|
||||
if (im->image[y][x] & mask) { \
|
||||
has_data = 1; \
|
||||
bbox[0] = x; \
|
||||
bbox[1] = y; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
if (has_data) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
/* Check that we have a box */ \
|
||||
if (bbox[1] < 0) { \
|
||||
return 0; /* no data */ \
|
||||
} \
|
||||
/* second stage: looking for any pixels from bottom */ \
|
||||
for (y = im->ysize - 1; y >= bbox[1]; y--) { \
|
||||
has_data = 0; \
|
||||
for (x = 0; x < im->xsize; x++) { \
|
||||
if (im->image[y][x] & mask) { \
|
||||
|
@ -39,16 +59,27 @@ ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) {
|
|||
if (x < bbox[0]) { \
|
||||
bbox[0] = x; \
|
||||
} \
|
||||
if (x >= bbox[2]) { \
|
||||
bbox[2] = x + 1; \
|
||||
} \
|
||||
bbox[3] = y + 1; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
if (has_data) { \
|
||||
if (bbox[1] < 0) { \
|
||||
bbox[1] = y; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
/* third stage: looking for left and right boundaries */ \
|
||||
for (y = bbox[1]; y < bbox[3]; y++) { \
|
||||
for (x = 0; x < bbox[0]; x++) { \
|
||||
if (im->image[y][x] & mask) { \
|
||||
bbox[0] = x; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
for (x = im->xsize - 1; x >= bbox[2]; x--) { \
|
||||
if (im->image[y][x] & mask) { \
|
||||
bbox[2] = x + 1; \
|
||||
break; \
|
||||
} \
|
||||
bbox[3] = y + 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
@ -71,11 +102,6 @@ ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) {
|
|||
GETBBOX(image32, mask);
|
||||
}
|
||||
|
||||
/* Check that we got a box */
|
||||
if (bbox[1] < 0) {
|
||||
return 0; /* no data */
|
||||
}
|
||||
|
||||
return 1; /* ok */
|
||||
}
|
||||
|
||||
|
@ -144,6 +170,9 @@ ImagingGetExtrema(Imaging im, void *extrema) {
|
|||
imax = in[x];
|
||||
}
|
||||
}
|
||||
if (imin == 0 && imax == 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
((UINT8 *)extrema)[0] = (UINT8)imin;
|
||||
((UINT8 *)extrema)[1] = (UINT8)imax;
|
||||
|
|
Loading…
Reference in New Issue
Block a user