This commit is contained in:
Yay295 2025-01-14 16:32:08 +00:00 committed by GitHub
commit 50ebacf052
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 1044 additions and 707 deletions

View File

@ -85,7 +85,7 @@ def test_rgba_16() -> None:
with Image.open("Tests/images/rgba16.tga") as im:
assert im.mode == "RGBA"
assert im.getpixel((0, 0)) == (172, 0, 255, 255)
assert im.getpixel((0, 0)) == (173, 0, 255, 255)
assert im.getpixel((1, 0)) == (0, 255, 82, 0)

View File

@ -158,6 +158,12 @@ def test_rawmode_valueerrors(tmp_path: Path) -> None:
palette.save(f)
@pytest.mark.parametrize("rawmode", Image._DEPRECATED_RAWMODES)
def test_rawmode_deprecated(rawmode: str) -> None:
with pytest.warns(DeprecationWarning):
ImagePalette.raw(rawmode, b"")
def test_getdata() -> None:
# Arrange
data_in = list(range(256)) * 3

File diff suppressed because it is too large Load Diff

View File

@ -183,6 +183,31 @@ ExifTags.IFD.Makernote
``ExifTags.IFD.Makernote`` has been deprecated. Instead, use
``ExifTags.IFD.MakerNote``.
16-Bit RGB/BGR Rawmodes
^^^^^^^^^^^^^^^^^^^^^^^
.. deprecated:: 11.0.0
The following rawmodes have been deprecated and replaced with better-named rawmodes.
Additionally, the 5 and 6 bit conversions are slightly more accurate, so there will be
some differences in the output. The difference is only ever by 1, so you are unlikely
to notice the difference visually.
============ ==============
Deprecated Use instead
============ ==============
``RGB;15`` ``XBGR;1555``
``RGB;16`` ``BGR;565``
``BGR;5`` ``XRGB;1555``
``BGR;15`` ``XRGB;1555``
``BGR;16`` ``RGB;565``
``RGB;4B`` ``XBGR;4``
``RGBA;4B`` ``ABGR;4``
``RGBA;15`` ``ABGR;1555``
``BGRA;15`` ``ARGB;1555``
``BGRA;15Z`` ``ARGB;1555Z``
============ ==============
Removed features
----------------

View File

@ -113,6 +113,29 @@ Specific WebP Feature Checks
``True`` if the WebP module is installed, until they are removed in Pillow
12.0.0 (2025-10-15).
16-Bit RGB/BGR Rawmodes
^^^^^^^^^^^^^^^^^^^^^^^
The following rawmodes have been deprecated and replaced with better-named rawmodes.
Additionally, the 5 and 6 bit conversions are slightly more accurate, so there will be
some differences in the output. The difference is only ever by 1, so you are unlikely
to notice the difference visually.
============ ==============
Deprecated Use instead
============ ==============
``RGB;15`` ``XBGR;1555``
``RGB;16`` ``BGR;565``
``BGR;5`` ``XRGB;1555``
``BGR;15`` ``XRGB;1555``
``BGR;16`` ``RGB;565``
``RGB;4B`` ``XBGR;4``
``RGBA;4B`` ``ABGR;4``
``RGBA;15`` ``ABGR;1555``
``BGRA;15`` ``ARGB;1555``
``BGRA;15Z`` ``ARGB;1555Z``
============ ==============
API Changes
===========

View File

@ -43,7 +43,7 @@ BIT2MODE = {
1: ("P", "P;1"),
4: ("P", "P;4"),
8: ("P", "P"),
16: ("RGB", "BGR;15"),
16: ("RGB", "XRGB;1555"),
24: ("RGB", "BGR"),
32: ("RGB", "BGRX"),
}
@ -218,8 +218,8 @@ class BmpImageFile(ImageFile.ImageFile):
(32, (0xFF000000, 0xFF00, 0xFF, 0xFF0000)): "BGAR",
(32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
(24, (0xFF0000, 0xFF00, 0xFF)): "BGR",
(16, (0xF800, 0x7E0, 0x1F)): "BGR;16",
(16, (0x7C00, 0x3E0, 0x1F)): "BGR;15",
(16, (0xF800, 0x7E0, 0x1F)): "RGB;565",
(16, (0x7C00, 0x3E0, 0x1F)): "XRGB;1555",
}
if file_info["bits"] in SUPPORTED:
if (

View File

@ -283,6 +283,20 @@ MODES = [
# may have to modify the stride calculation in map.c too!
_MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16L", "I;16B")
# map of old deprecated rawmode to new replacement rawmode
_DEPRECATED_RAWMODES = {
"RGB;15": "XBGR;1555",
"RGB;16": "BGR;565",
"BGR;5": "XRGB;1555",
"BGR;15": "XRGB;1555",
"BGR;16": "RGB;565",
"RGB;4B": "XBGR;4",
"RGBA;4B": "ABGR;4",
"RGBA;15": "ABGR;1555",
"BGRA;15": "ARGB;1555",
"BGRA;15Z": "ARGB;1555Z",
}
def getmodebase(mode: str) -> str:
"""
@ -426,6 +440,15 @@ def _getdecoder(
elif not isinstance(args, tuple):
args = (args,)
if decoder_name == "raw":
rawmode = args[0]
if mode != rawmode and rawmode in _DEPRECATED_RAWMODES:
deprecate(
f"rawmode {rawmode}",
12,
replacement=f"rawmode {_DEPRECATED_RAWMODES[rawmode]}",
)
try:
decoder = DECODERS[decoder_name]
except KeyError:
@ -1627,6 +1650,12 @@ class Image:
mode = self.im.getpalettemode()
except ValueError:
return None # no palette
if rawmode in _DEPRECATED_RAWMODES:
deprecate(
f"rawmode {rawmode}",
12,
replacement=f"rawmode {_DEPRECATED_RAWMODES[rawmode]}",
)
if rawmode is None:
rawmode = mode
return list(self.im.getpalette(mode, rawmode))

View File

@ -209,6 +209,16 @@ class ImagePalette:
def raw(rawmode: str, data: Sequence[int] | bytes | bytearray) -> ImagePalette:
from . import Image
from ._deprecate import deprecate
if rawmode in Image._DEPRECATED_RAWMODES:
deprecate(
f"rawmode {rawmode}",
12,
replacement=f"rawmode {Image._DEPRECATED_RAWMODES[rawmode]}",
)
palette = ImagePalette()
palette.rawmode = rawmode
palette.palette = data

View File

@ -36,7 +36,7 @@ MODES = {
(3, 1): "1",
(3, 8): "L",
(3, 16): "LA",
(2, 16): "BGRA;15Z",
(2, 16): "ARGB;1555Z",
(2, 24): "BGR",
(2, 32): "BGRA",
}
@ -116,7 +116,7 @@ class TgaImageFile(ImageFile.ImageFile):
start, size, mapdepth = i16(s, 3), i16(s, 5), s[7]
if mapdepth == 16:
self.palette = ImagePalette.raw(
"BGRA;15Z", bytes(2 * start) + self.fp.read(2 * size)
"ARGB;1555Z", bytes(2 * start) + self.fp.read(2 * size)
)
self.palette.mode = "RGBA"
elif mapdepth == 24:

View File

@ -254,6 +254,30 @@ packLAL(UINT8 *out, const UINT8 *in, int pixels) {
}
}
static void
ImagingPackXRGB1555(UINT8 *out, const UINT8 *in, int pixels) {
for (int i = 0; i < pixels; out += 2, in += 4, i++) {
/* XRGB, 1/5/5/5 bits per pixel, little-endian */
const UINT8 r = in[0] >> 3;
const UINT8 g = in[1] >> 3;
const UINT8 b = in[2] >> 3;
out[1] = 0x80 | (r << 2) | (g >> 3);
out[0] = (g << 5) | b;
}
}
static void
ImagingPackRGB565(UINT8 *out, const UINT8 *in, int pixels) {
for (int i = 0; i < pixels; out += 2, in += 4, i++) {
/* RGB, 5/6/5 bits per pixel, little-endian */
const UINT8 r = in[0] >> 3;
const UINT8 g = in[1] >> 2;
const UINT8 b = in[2] >> 3;
out[1] = (r << 3) | (g >> 3);
out[0] = (g << 5) | b;
}
}
void
ImagingPackRGB(UINT8 *out, const UINT8 *in, int pixels) {
int i = 0;
@ -284,6 +308,30 @@ ImagingPackXRGB(UINT8 *out, const UINT8 *in, int pixels) {
}
}
static void
ImagingPackXBGR1555(UINT8 *out, const UINT8 *in, int pixels) {
for (int i = 0; i < pixels; out += 2, in += 4, i++) {
/* XBGR, 1/5/5/5 bits per pixel, little-endian */
const UINT8 r = in[0] >> 3;
const UINT8 g = in[1] >> 3;
const UINT8 b = in[2] >> 3;
out[1] = 0x80 | (b << 2) | (g >> 3);
out[0] = (g << 5) | r;
}
}
static void
ImagingPackBGR565(UINT8 *out, const UINT8 *in, int pixels) {
for (int i = 0; i < pixels; out += 2, in += 4, i++) {
/* BGR, 5/6/5 bits per pixel, little-endian */
const UINT8 r = in[0] >> 3;
const UINT8 g = in[1] >> 2;
const UINT8 b = in[2] >> 3;
out[1] = (b << 3) | (g >> 3);
out[0] = (g << 5) | r;
}
}
void
ImagingPackBGR(UINT8 *out, const UINT8 *in, int pixels) {
int i;
@ -561,10 +609,14 @@ static struct {
{"PA", "PA;L", 16, packLAL},
/* true colour */
{"RGB", "XRGB;1555", 16, ImagingPackXRGB1555},
{"RGB", "RGB;565", 16, ImagingPackRGB565},
{"RGB", "RGB", 24, ImagingPackRGB},
{"RGB", "RGBX", 32, copy4},
{"RGB", "RGBA", 32, copy4},
{"RGB", "XRGB", 32, ImagingPackXRGB},
{"RGB", "XBGR;1555", 16, ImagingPackXBGR1555},
{"RGB", "BGR;565", 16, ImagingPackBGR565},
{"RGB", "BGR", 24, ImagingPackBGR},
{"RGB", "BGRX", 32, ImagingPackBGRX},
{"RGB", "XBGR", 32, ImagingPackXBGR},

View File

@ -764,31 +764,153 @@ ImagingUnpackBGR16(UINT8 *out, const UINT8 *in, int pixels) {
}
}
void
ImagingUnpackRGB4B(UINT8 *out, const UINT8 *in, int pixels) {
int i, pixel;
/* RGB, 4 bits per pixel */
for (i = 0; i < pixels; i++) {
pixel = in[0] + (in[1] << 8);
out[R] = (pixel & 15) * 17;
out[G] = ((pixel >> 4) & 15) * 17;
out[B] = ((pixel >> 8) & 15) * 17;
static void
ImagingUnpackXRGB1555(UINT8 *out, const UINT8 *in, const int pixels) {
/* XRGB, 1/5/5/5 bits per pixel, little-endian */
for (int i = 0; i < pixels; i++) {
const UINT16 pixel = ((UINT16)in[1] << 8) | in[0];
const UINT8 r = (pixel >> 10) & 31;
const UINT8 g = (pixel >> 5) & 31;
const UINT8 b = pixel & 31;
out[R] = (r << 3) | (r >> 2);
out[G] = (g << 3) | (g >> 2);
out[B] = (b << 3) | (b >> 2);
out[A] = 255;
out += 4;
in += 2;
}
}
void
ImagingUnpackRGBA4B(UINT8 *out, const UINT8 *in, int pixels) {
int i, pixel;
/* RGBA, 4 bits per pixel */
for (i = 0; i < pixels; i++) {
pixel = in[0] + (in[1] << 8);
out[R] = (pixel & 15) * 17;
out[G] = ((pixel >> 4) & 15) * 17;
out[B] = ((pixel >> 8) & 15) * 17;
out[A] = ((pixel >> 12) & 15) * 17;
static void
ImagingUnpackARGB1555(UINT8 *out, const UINT8 *in, const int pixels) {
/* ARGB, 1/5/5/5 bits per pixel, little-endian */
for (int i = 0; i < pixels; i++) {
const UINT16 pixel = ((UINT16)in[1] << 8) | in[0];
const UINT8 r = (pixel >> 10) & 31;
const UINT8 g = (pixel >> 5) & 31;
const UINT8 b = pixel & 31;
out[R] = (r << 3) | (r >> 2);
out[G] = (g << 3) | (g >> 2);
out[B] = (b << 3) | (b >> 2);
out[A] = (pixel >> 15) * 255;
out += 4;
in += 2;
}
}
static void
ImagingUnpackARGB1555Z(UINT8 *out, const UINT8 *in, const int pixels) {
/* ARGB, 1/5/5/5 bits per pixel, little-endian, inverted alpha */
for (int i = 0; i < pixels; i++) {
const UINT16 pixel = ((UINT16)in[1] << 8) | in[0];
const UINT8 r = (pixel >> 10) & 31;
const UINT8 g = (pixel >> 5) & 31;
const UINT8 b = pixel & 31;
out[R] = (r << 3) | (r >> 2);
out[G] = (g << 3) | (g >> 2);
out[B] = (b << 3) | (b >> 2);
out[A] = ~((pixel >> 15) * 255);
out += 4;
in += 2;
}
}
static void
ImagingUnpackXBGR1555(UINT8 *out, const UINT8 *in, const int pixels) {
/* XBGR, 1/5/5/5 bits per pixel, little-endian */
for (int i = 0; i < pixels; i++) {
const UINT16 pixel = ((UINT16)in[1] << 8) | in[0];
const UINT8 b = (pixel >> 10) & 31;
const UINT8 g = (pixel >> 5) & 31;
const UINT8 r = pixel & 31;
out[R] = (r << 3) | (r >> 2);
out[G] = (g << 3) | (g >> 2);
out[B] = (b << 3) | (b >> 2);
out[A] = 255;
out += 4;
in += 2;
}
}
static void
ImagingUnpackABGR1555(UINT8 *out, const UINT8 *in, const int pixels) {
/* ABGR, 1/5/5/5 bits per pixel, little-endian */
for (int i = 0; i < pixels; i++) {
const UINT16 pixel = ((UINT16)in[1] << 8) | in[0];
const UINT8 b = (pixel >> 10) & 31;
const UINT8 g = (pixel >> 5) & 31;
const UINT8 r = pixel & 31;
out[R] = (r << 3) | (r >> 2);
out[G] = (g << 3) | (g >> 2);
out[B] = (b << 3) | (b >> 2);
out[A] = (pixel >> 15) * 255;
out += 4;
in += 2;
}
}
static void
ImagingUnpackRGB565(UINT8 *out, const UINT8 *in, const int pixels) {
/* RGB, 5/6/5 bits per pixel, little-endian */
for (int i = 0; i < pixels; i++) {
const UINT16 pixel = ((UINT16)in[1] << 8) | in[0];
const UINT8 r = (pixel >> 11) & 31;
const UINT8 g = (pixel >> 5) & 63;
const UINT8 b = pixel & 31;
out[R] = (r << 3) | (r >> 2);
out[G] = (g << 2) | (g >> 4);
out[B] = (b << 3) | (b >> 2);
out[A] = 255;
out += 4;
in += 2;
}
}
static void
ImagingUnpackBGR565(UINT8 *out, const UINT8 *in, const int pixels) {
/* BGR, 5/6/5 bits per pixel, little-endian */
for (int i = 0; i < pixels; i++) {
const UINT16 pixel = ((UINT16)in[1] << 8) | in[0];
const UINT8 b = (pixel >> 11) & 31;
const UINT8 g = (pixel >> 5) & 63;
const UINT8 r = pixel & 31;
out[R] = (r << 3) | (r >> 2);
out[G] = (g << 2) | (g >> 4);
out[B] = (b << 3) | (b >> 2);
out[A] = 255;
out += 4;
in += 2;
}
}
static void
ImagingUnpackXBGR4(UINT8 *out, const UINT8 *in, const int pixels) {
/* XBGR, 4 bits per pixel, little-endian */
for (int i = 0; i < pixels; i++) {
const UINT8 b = in[1] & 0x0F;
const UINT8 g = in[0] & 0xF0;
const UINT8 r = in[0] & 0x0F;
out[R] = (r << 4) | r;
out[G] = g | (g >> 4);
out[B] = (b << 4) | b;
out[A] = 255;
out += 4;
in += 2;
}
}
static void
ImagingUnpackABGR4(UINT8 *out, const UINT8 *in, const int pixels) {
/* ABGR, 4 bits per pixel, little-endian */
for (int i = 0; i < pixels; i++) {
const UINT8 a = in[1] & 0xF0;
const UINT8 b = in[1] & 0x0F;
const UINT8 g = in[0] & 0xF0;
const UINT8 r = in[0] & 0x0F;
out[R] = (r << 4) | r;
out[G] = g | (g >> 4);
out[B] = (b << 4) | b;
out[A] = a | (a >> 4);
out += 4;
in += 2;
}
@ -1554,16 +1676,25 @@ static struct {
ImagingShuffler unpack;
} unpackers[] = {
/* raw mode syntax is "<mode>;<bits><flags>" where "bits" defaults
depending on mode (1 for "1", 8 for "P" and "L", etc), and
"flags" should be given in alphabetical order. if both bits
and flags have their default values, the ; should be left out */
// The rawmode syntax is "<mode>;<bits><flags>".
// "bits" defaults depending on mode (1 for "1", 8 for "P" and "L", etc.).
// "flags" should be given in alphabetical order.
// If both bits and flags have their default values, the ; should be left out.
/* flags: "I" inverted data; "R" reversed bit order; "B" big
endian byte order (default is little endian); "L" line
interleave, "S" signed, "F" floating point, "Z" inverted alpha */
// Flags:
// "B" big endian byte order (default is little endian)
// "F" floating point
// "I" inverted data
// "L" line interleaved
// "N" native endian byte order
// "R" reversed bit order
// "S" signed
// "Z" inverted alpha
/* exception: rawmodes "I" and "F" are always native endian byte order */
// Exceptions:
// Some RGB/BGR rawmodes have different sized bands,
// so the size of each band is listed consecutively.
// Rawmodes "I" and "F" default to native endian byte order.
/* bilevel */
{"1", "1", 1, unpack1},
@ -1620,13 +1751,22 @@ static struct {
{"RGB", "RGB;16B", 48, unpackRGB16B},
{"RGB", "BGR", 24, ImagingUnpackBGR},
{"RGB", "RGB;15", 16, ImagingUnpackRGB15},
{"RGB", "XRGB;1555", 16, ImagingUnpackXRGB1555},
{"RGB", "ARGB;1555", 16, ImagingUnpackARGB1555},
{"RGB", "ARGB;1555Z", 16, ImagingUnpackARGB1555Z},
{"RGB", "BGR;15", 16, ImagingUnpackBGR15},
{"RGB", "XBGR;1555", 16, ImagingUnpackXBGR1555},
{"RGB", "ABGR;1555", 16, ImagingUnpackABGR1555},
{"RGB", "RGB;16", 16, ImagingUnpackRGB16},
{"RGB", "RGB;565", 16, ImagingUnpackRGB565},
{"RGB", "BGR;16", 16, ImagingUnpackBGR16},
{"RGB", "BGR;565", 16, ImagingUnpackBGR565},
{"RGB", "RGB;4B", 16, ImagingUnpackXBGR4},
{"RGB", "XBGR;4", 16, ImagingUnpackXBGR4},
{"RGB", "ABGR;4", 16, ImagingUnpackABGR4},
{"RGB", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */
{"RGB", "RGBX;16L", 64, unpackRGBA16L},
{"RGB", "RGBX;16B", 64, unpackRGBA16B},
{"RGB", "RGB;4B", 16, ImagingUnpackRGB4B},
{"RGB", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */
{"RGB", "RGBX", 32, copy4},
{"RGB", "RGBX;L", 32, unpackRGBAL},
{"RGB", "RGBXX", 40, copy4skip1},
@ -1656,6 +1796,9 @@ static struct {
/* true colour w. alpha */
{"RGBA", "LA", 16, unpackRGBALA},
{"RGBA", "LA;16B", 32, unpackRGBALA16B},
{"RGBA", "ARGB;1555", 16, ImagingUnpackARGB1555},
{"RGBA", "ARGB;1555Z", 16, ImagingUnpackARGB1555Z},
{"RGBA", "ABGR;1555", 16, ImagingUnpackABGR1555},
{"RGBA", "RGBA", 32, copy4},
{"RGBA", "RGBAX", 40, copy4skip1},
{"RGBA", "RGBAXX", 48, copy4skip2},
@ -1671,7 +1814,8 @@ static struct {
{"RGBA", "RGBA;15", 16, ImagingUnpackRGBA15},
{"RGBA", "BGRA;15", 16, ImagingUnpackBGRA15},
{"RGBA", "BGRA;15Z", 16, ImagingUnpackBGRA15Z},
{"RGBA", "RGBA;4B", 16, ImagingUnpackRGBA4B},
{"RGBA", "RGBA;4B", 16, ImagingUnpackABGR4},
{"RGBA", "ABGR;4", 16, ImagingUnpackABGR4},
{"RGBA", "RGBA;16L", 64, unpackRGBA16L},
{"RGBA", "RGBA;16B", 64, unpackRGBA16B},
{"RGBA", "BGRA", 32, unpackBGRA},
@ -1736,8 +1880,13 @@ static struct {
{"RGBX", "RGB;16B", 48, unpackRGB16B},
{"RGBX", "BGR", 24, ImagingUnpackBGR},
{"RGBX", "RGB;15", 16, ImagingUnpackRGB15},
{"RGBX", "XRGB;1555", 16, ImagingUnpackXRGB1555},
{"RGBX", "RGB;565", 16, ImagingUnpackRGB565},
{"RGBX", "BGR;15", 16, ImagingUnpackBGR15},
{"RGBX", "RGB;4B", 16, ImagingUnpackRGB4B},
{"RGBX", "XBGR;1555", 16, ImagingUnpackXBGR1555},
{"RGBX", "BGR;565", 16, ImagingUnpackBGR565},
{"RGBX", "RGB;4B", 16, ImagingUnpackXBGR4},
{"RGBX", "XBGR;4", 16, ImagingUnpackXBGR4},
{"RGBX", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */
{"RGBX", "RGBX", 32, copy4},
{"RGBX", "RGBXX", 40, copy4skip1},