Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Tests/test_image_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def test_sanity():
assert m.bands == ("1",)
assert m.basemode == "L"
assert m.basetype == "L"
assert m.typestr == "|b1"

for mode in (
"I;16",
Expand All @@ -45,6 +46,7 @@ def test_sanity():
assert m.bands == ("R", "G", "B")
assert m.basemode == "RGB"
assert m.basetype == "L"
assert m.typestr == "|u1"


def test_properties():
Expand Down
46 changes: 7 additions & 39 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,48 +203,16 @@ def isImageType(t):
# --------------------------------------------------------------------
# Modes

if sys.byteorder == "little":
_ENDIAN = "<"
else:
_ENDIAN = ">"

_MODE_CONV = {
# official modes
"1": ("|b1", None), # Bits need to be extended to bytes
"L": ("|u1", None),
"LA": ("|u1", 2),
"I": (_ENDIAN + "i4", None),
"F": (_ENDIAN + "f4", None),
"P": ("|u1", None),
"RGB": ("|u1", 3),
"RGBX": ("|u1", 4),
"RGBA": ("|u1", 4),
"CMYK": ("|u1", 4),
"YCbCr": ("|u1", 3),
"LAB": ("|u1", 3), # UNDONE - unsigned |u1i1i1
"HSV": ("|u1", 3),
# I;16 == I;16L, and I;32 == I;32L
"I;16": ("<u2", None),
"I;16B": (">u2", None),
"I;16L": ("<u2", None),
"I;16S": ("<i2", None),
"I;16BS": (">i2", None),
"I;16LS": ("<i2", None),
"I;32": ("<u4", None),
"I;32B": (">u4", None),
"I;32L": ("<u4", None),
"I;32S": ("<i4", None),
"I;32BS": (">i4", None),
"I;32LS": ("<i4", None),
}
_ENDIAN = "<" if sys.byteorder == "little" else ">"


def _conv_type_shape(im):
typ, extra = _MODE_CONV[im.mode]
if extra is None:
return (im.size[1], im.size[0]), typ
else:
return (im.size[1], im.size[0], extra), typ
m = ImageMode.getmode(im.mode)
shape = (im.height, im.width)
extra = len(m.bands)
if extra != 1:
shape += (extra,)
return shape, m.typestr


MODES = ["1", "CMYK", "F", "HSV", "I", "L", "LAB", "P", "RGB", "RGBA", "RGBX", "YCbCr"]
Expand Down
81 changes: 47 additions & 34 deletions src/PIL/ImageMode.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@
# See the README file for information on usage and redistribution.
#

import sys

# mode descriptor cache
_modes = None


class ModeDescriptor:
"""Wrapper for mode strings."""

def __init__(self, mode, bands, basemode, basetype):
def __init__(self, mode, bands, basemode, basetype, typestr):
self.mode = mode
self.bands = bands
self.basemode = basemode
self.basetype = basetype
self.typestr = typestr

def __str__(self):
return self.mode
Expand All @@ -36,43 +39,53 @@ def getmode(mode):
if not _modes:
# initialize mode cache
modes = {}
for m, (basemode, basetype, bands) in {
endian = "<" if sys.byteorder == "little" else ">"
for m, (basemode, basetype, bands, typestr) in {
# core modes
"1": ("L", "L", ("1",)),
"L": ("L", "L", ("L",)),
"I": ("L", "I", ("I",)),
"F": ("L", "F", ("F",)),
"P": ("P", "L", ("P",)),
"RGB": ("RGB", "L", ("R", "G", "B")),
"RGBX": ("RGB", "L", ("R", "G", "B", "X")),
"RGBA": ("RGB", "L", ("R", "G", "B", "A")),
"CMYK": ("RGB", "L", ("C", "M", "Y", "K")),
"YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")),
"LAB": ("RGB", "L", ("L", "A", "B")),
"HSV": ("RGB", "L", ("H", "S", "V")),
# Bits need to be extended to bytes
"1": ("L", "L", ("1",), "|b1"),
"L": ("L", "L", ("L",), "|u1"),
"I": ("L", "I", ("I",), endian + "i4"),
"F": ("L", "F", ("F",), endian + "f4"),
"P": ("P", "L", ("P",), "|u1"),
"RGB": ("RGB", "L", ("R", "G", "B"), "|u1"),
"RGBX": ("RGB", "L", ("R", "G", "B", "X"), "|u1"),
"RGBA": ("RGB", "L", ("R", "G", "B", "A"), "|u1"),
"CMYK": ("RGB", "L", ("C", "M", "Y", "K"), "|u1"),
"YCbCr": ("RGB", "L", ("Y", "Cb", "Cr"), "|u1"),
# UNDONE - unsigned |u1i1i1
"LAB": ("RGB", "L", ("L", "A", "B"), "|u1"),
"HSV": ("RGB", "L", ("H", "S", "V"), "|u1"),
# extra experimental modes
"RGBa": ("RGB", "L", ("R", "G", "B", "a")),
"BGR;15": ("RGB", "L", ("B", "G", "R")),
"BGR;16": ("RGB", "L", ("B", "G", "R")),
"BGR;24": ("RGB", "L", ("B", "G", "R")),
"BGR;32": ("RGB", "L", ("B", "G", "R")),
"LA": ("L", "L", ("L", "A")),
"La": ("L", "L", ("L", "a")),
"PA": ("RGB", "L", ("P", "A")),
"RGBa": ("RGB", "L", ("R", "G", "B", "a"), "|u1"),
"BGR;15": ("RGB", "L", ("B", "G", "R"), endian + "u2"),
"BGR;16": ("RGB", "L", ("B", "G", "R"), endian + "u2"),
"BGR;24": ("RGB", "L", ("B", "G", "R"), endian + "u3"),
"BGR;32": ("RGB", "L", ("B", "G", "R"), endian + "u4"),
"LA": ("L", "L", ("L", "A"), "|u1"),
"La": ("L", "L", ("L", "a"), "|u1"),
"PA": ("RGB", "L", ("P", "A"), "|u1"),
}.items():
modes[m] = ModeDescriptor(m, bands, basemode, basetype)
modes[m] = ModeDescriptor(m, bands, basemode, basetype, typestr)
# mapping modes
for i16mode in (
"I;16",
"I;16S",
"I;16L",
"I;16LS",
"I;16B",
"I;16BS",
"I;16N",
"I;16NS",
):
modes[i16mode] = ModeDescriptor(i16mode, ("I",), "L", "L")
for i16mode, typestr in {
# I;16 == I;16L, and I;32 == I;32L
"I;16": "<u2",
"I;16S": "<i2",
"I;16L": "<u2",
"I;16LS": "<i2",
"I;16B": ">u2",
"I;16BS": ">i2",
"I;16N": endian + "u2",
"I;16NS": endian + "i2",
"I;32": "<u4",
"I;32B": ">u4",
"I;32L": "<u4",
"I;32S": "<i4",
"I;32BS": ">i4",
"I;32LS": "<i4",
}.items():
modes[i16mode] = ModeDescriptor(i16mode, ("I",), "L", "L", typestr)
# set global mode cache atomically
_modes = modes
return _modes[mode]