mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-28 01:42:52 +03:00
Merge pull request #6879 from Yay295/eps_plugin_perf
This commit is contained in:
commit
48b0be2fb7
|
@ -29,7 +29,7 @@ def test_version(version, expected):
|
||||||
|
|
||||||
|
|
||||||
def test_unknown_version():
|
def test_unknown_version():
|
||||||
expected = r"Unknown removal version, update PIL\._deprecate\?"
|
expected = r"Unknown removal version: 12345. Update PIL\._deprecate\?"
|
||||||
with pytest.raises(ValueError, match=expected):
|
with pytest.raises(ValueError, match=expected):
|
||||||
_deprecate.deprecate("Old thing", 12345, "new thing")
|
_deprecate.deprecate("Old thing", 12345, "new thing")
|
||||||
|
|
||||||
|
|
|
@ -28,34 +28,65 @@ FILE2_COMPARE_SCALE2 = "Tests/images/non_zero_bb_scale2.png"
|
||||||
# EPS test files with binary preview
|
# EPS test files with binary preview
|
||||||
FILE3 = "Tests/images/binary_preview_map.eps"
|
FILE3 = "Tests/images/binary_preview_map.eps"
|
||||||
|
|
||||||
|
# Three unsigned 32bit little-endian values:
|
||||||
|
# 0xC6D3D0C5 magic number
|
||||||
|
# byte position of start of postscript section (12)
|
||||||
|
# byte length of postscript section (0)
|
||||||
|
# this byte length isn't valid, but we don't read it
|
||||||
|
simple_binary_header = b"\xc5\xd0\xd3\xc6\x0c\x00\x00\x00\x00\x00\x00\x00"
|
||||||
|
|
||||||
|
# taken from page 8 of the specification
|
||||||
|
# https://web.archive.org/web/20220120164601/https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/5002.EPSF_Spec.pdf
|
||||||
|
simple_eps_file = (
|
||||||
|
b"%!PS-Adobe-3.0 EPSF-3.0",
|
||||||
|
b"%%BoundingBox: 5 5 105 105",
|
||||||
|
b"10 setlinewidth",
|
||||||
|
b"10 10 moveto",
|
||||||
|
b"0 90 rlineto 90 0 rlineto 0 -90 rlineto closepath",
|
||||||
|
b"stroke",
|
||||||
|
)
|
||||||
|
simple_eps_file_with_comments = (
|
||||||
|
simple_eps_file[:1]
|
||||||
|
+ (
|
||||||
|
b"%%Comment1: Some Value",
|
||||||
|
b"%%SecondComment: Another Value",
|
||||||
|
)
|
||||||
|
+ simple_eps_file[1:]
|
||||||
|
)
|
||||||
|
simple_eps_file_without_version = simple_eps_file[1:]
|
||||||
|
simple_eps_file_without_boundingbox = simple_eps_file[:1] + simple_eps_file[2:]
|
||||||
|
simple_eps_file_with_invalid_boundingbox = (
|
||||||
|
simple_eps_file[:1] + (b"%%BoundingBox: a b c d",) + simple_eps_file[2:]
|
||||||
|
)
|
||||||
|
simple_eps_file_with_invalid_boundingbox_valid_imagedata = (
|
||||||
|
simple_eps_file_with_invalid_boundingbox + (b"%ImageData: 100 100 8 3",)
|
||||||
|
)
|
||||||
|
simple_eps_file_with_long_ascii_comment = (
|
||||||
|
simple_eps_file[:2] + (b"%%Comment: " + b"X" * 300,) + simple_eps_file[2:]
|
||||||
|
)
|
||||||
|
simple_eps_file_with_long_binary_data = (
|
||||||
|
simple_eps_file[:2]
|
||||||
|
+ (
|
||||||
|
b"%%BeginBinary: 300",
|
||||||
|
b"\0" * 300,
|
||||||
|
b"%%EndBinary",
|
||||||
|
)
|
||||||
|
+ simple_eps_file[2:]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
|
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
|
||||||
def test_sanity():
|
@pytest.mark.parametrize(
|
||||||
# Regular scale
|
("filename", "size"), ((FILE1, (460, 352)), (FILE2, (360, 252)))
|
||||||
with Image.open(FILE1) as image1:
|
)
|
||||||
image1.load()
|
@pytest.mark.parametrize("scale", (1, 2))
|
||||||
assert image1.mode == "RGB"
|
def test_sanity(filename, size, scale):
|
||||||
assert image1.size == (460, 352)
|
expected_size = tuple(s * scale for s in size)
|
||||||
assert image1.format == "EPS"
|
with Image.open(filename) as image:
|
||||||
|
image.load(scale=scale)
|
||||||
with Image.open(FILE2) as image2:
|
assert image.mode == "RGB"
|
||||||
image2.load()
|
assert image.size == expected_size
|
||||||
assert image2.mode == "RGB"
|
assert image.format == "EPS"
|
||||||
assert image2.size == (360, 252)
|
|
||||||
assert image2.format == "EPS"
|
|
||||||
|
|
||||||
# Double scale
|
|
||||||
with Image.open(FILE1) as image1_scale2:
|
|
||||||
image1_scale2.load(scale=2)
|
|
||||||
assert image1_scale2.mode == "RGB"
|
|
||||||
assert image1_scale2.size == (920, 704)
|
|
||||||
assert image1_scale2.format == "EPS"
|
|
||||||
|
|
||||||
with Image.open(FILE2) as image2_scale2:
|
|
||||||
image2_scale2.load(scale=2)
|
|
||||||
assert image2_scale2.mode == "RGB"
|
|
||||||
assert image2_scale2.size == (720, 504)
|
|
||||||
assert image2_scale2.format == "EPS"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
|
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
|
||||||
|
@ -69,11 +100,72 @@ def test_load():
|
||||||
|
|
||||||
def test_invalid_file():
|
def test_invalid_file():
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
with pytest.raises(SyntaxError):
|
with pytest.raises(SyntaxError):
|
||||||
EpsImagePlugin.EpsImageFile(invalid_file)
|
EpsImagePlugin.EpsImageFile(invalid_file)
|
||||||
|
|
||||||
|
|
||||||
|
def test_binary_header_only():
|
||||||
|
data = io.BytesIO(simple_binary_header)
|
||||||
|
with pytest.raises(SyntaxError, match='EPS header missing "%!PS-Adobe" comment'):
|
||||||
|
EpsImagePlugin.EpsImageFile(data)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||||
|
def test_missing_version_comment(prefix):
|
||||||
|
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_version))
|
||||||
|
with pytest.raises(SyntaxError):
|
||||||
|
EpsImagePlugin.EpsImageFile(data)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||||
|
def test_missing_boundingbox_comment(prefix):
|
||||||
|
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_boundingbox))
|
||||||
|
with pytest.raises(SyntaxError, match='EPS header missing "%%BoundingBox" comment'):
|
||||||
|
EpsImagePlugin.EpsImageFile(data)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||||
|
def test_invalid_boundingbox_comment(prefix):
|
||||||
|
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox))
|
||||||
|
with pytest.raises(OSError, match="cannot determine EPS bounding box"):
|
||||||
|
EpsImagePlugin.EpsImageFile(data)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||||
|
def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix):
|
||||||
|
data = io.BytesIO(
|
||||||
|
prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox_valid_imagedata)
|
||||||
|
)
|
||||||
|
with Image.open(data) as img:
|
||||||
|
assert img.mode == "RGB"
|
||||||
|
assert img.size == (100, 100)
|
||||||
|
assert img.format == "EPS"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||||
|
def test_ascii_comment_too_long(prefix):
|
||||||
|
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_ascii_comment))
|
||||||
|
with pytest.raises(SyntaxError, match="not an EPS file"):
|
||||||
|
EpsImagePlugin.EpsImageFile(data)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||||
|
def test_long_binary_data(prefix):
|
||||||
|
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data))
|
||||||
|
EpsImagePlugin.EpsImageFile(data)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
|
||||||
|
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||||
|
def test_load_long_binary_data(prefix):
|
||||||
|
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data))
|
||||||
|
with Image.open(data) as img:
|
||||||
|
img.load()
|
||||||
|
assert img.mode == "RGB"
|
||||||
|
assert img.size == (100, 100)
|
||||||
|
assert img.format == "EPS"
|
||||||
|
|
||||||
|
|
||||||
@mark_if_feature_version(
|
@mark_if_feature_version(
|
||||||
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
|
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
|
||||||
)
|
)
|
||||||
|
@ -206,7 +298,6 @@ def test_resize(filename):
|
||||||
@pytest.mark.parametrize("filename", (FILE1, FILE2))
|
@pytest.mark.parametrize("filename", (FILE1, FILE2))
|
||||||
def test_thumbnail(filename):
|
def test_thumbnail(filename):
|
||||||
# Issue #619
|
# Issue #619
|
||||||
# Arrange
|
|
||||||
with Image.open(filename) as im:
|
with Image.open(filename) as im:
|
||||||
new_size = (100, 100)
|
new_size = (100, 100)
|
||||||
im.thumbnail(new_size)
|
im.thumbnail(new_size)
|
||||||
|
@ -220,7 +311,7 @@ def test_read_binary_preview():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_readline(tmp_path):
|
def test_readline_psfile(tmp_path):
|
||||||
# check all the freaking line endings possible from the spec
|
# check all the freaking line endings possible from the spec
|
||||||
# test_string = u'something\r\nelse\n\rbaz\rbif\n'
|
# test_string = u'something\r\nelse\n\rbaz\rbif\n'
|
||||||
line_endings = ["\r\n", "\n", "\n\r", "\r"]
|
line_endings = ["\r\n", "\n", "\n\r", "\r"]
|
||||||
|
@ -237,6 +328,7 @@ def test_readline(tmp_path):
|
||||||
|
|
||||||
def _test_readline_io_psfile(test_string, ending):
|
def _test_readline_io_psfile(test_string, ending):
|
||||||
f = io.BytesIO(test_string.encode("latin-1"))
|
f = io.BytesIO(test_string.encode("latin-1"))
|
||||||
|
with pytest.warns(DeprecationWarning):
|
||||||
t = EpsImagePlugin.PSFile(f)
|
t = EpsImagePlugin.PSFile(f)
|
||||||
_test_readline(t, ending)
|
_test_readline(t, ending)
|
||||||
|
|
||||||
|
@ -246,6 +338,7 @@ def test_readline(tmp_path):
|
||||||
w.write(test_string.encode("latin-1"))
|
w.write(test_string.encode("latin-1"))
|
||||||
|
|
||||||
with open(f, "rb") as r:
|
with open(f, "rb") as r:
|
||||||
|
with pytest.warns(DeprecationWarning):
|
||||||
t = EpsImagePlugin.PSFile(r)
|
t = EpsImagePlugin.PSFile(r)
|
||||||
_test_readline(t, ending)
|
_test_readline(t, ending)
|
||||||
|
|
||||||
|
@ -255,6 +348,25 @@ def test_readline(tmp_path):
|
||||||
_test_readline_file_psfile(s, ending)
|
_test_readline_file_psfile(s, ending)
|
||||||
|
|
||||||
|
|
||||||
|
def test_psfile_deprecation():
|
||||||
|
with pytest.warns(DeprecationWarning):
|
||||||
|
EpsImagePlugin.PSFile(None)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"line_ending",
|
||||||
|
(b"\r\n", b"\n", b"\n\r", b"\r"),
|
||||||
|
)
|
||||||
|
def test_readline(prefix, line_ending):
|
||||||
|
simple_file = prefix + line_ending.join(simple_eps_file_with_comments)
|
||||||
|
data = io.BytesIO(simple_file)
|
||||||
|
test_file = EpsImagePlugin.EpsImageFile(data)
|
||||||
|
assert test_file.info["Comment1"] == "Some Value"
|
||||||
|
assert test_file.info["SecondComment"] == "Another Value"
|
||||||
|
assert test_file.size == (100, 100)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"filename",
|
"filename",
|
||||||
(
|
(
|
||||||
|
|
|
@ -207,6 +207,16 @@ Use instead::
|
||||||
left, top, right, bottom = draw.multiline_textbbox((0, 0), "Hello\nworld")
|
left, top, right, bottom = draw.multiline_textbbox((0, 0), "Hello\nworld")
|
||||||
width, height = right - left, bottom - top
|
width, height = right - left, bottom - top
|
||||||
|
|
||||||
|
PSFile
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
.. deprecated:: 9.5.0
|
||||||
|
|
||||||
|
The :py:class:`~PIL.EpsImagePlugin.PSFile` class has been deprecated and will
|
||||||
|
be removed in Pillow 11 (2024-10-15). This class was only made as a helper to
|
||||||
|
be used internally, so there is no replacement. If you need this functionality
|
||||||
|
though, it is a very short class that can easily be recreated in your own code.
|
||||||
|
|
||||||
Removed features
|
Removed features
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,13 @@ TODO
|
||||||
Deprecations
|
Deprecations
|
||||||
============
|
============
|
||||||
|
|
||||||
TODO
|
PSFile
|
||||||
^^^^
|
^^^^^^
|
||||||
|
|
||||||
TODO
|
The :py:class:`~PIL.EpsImagePlugin.PSFile` class has been deprecated and will
|
||||||
|
be removed in Pillow 11 (2024-10-15). This class was only made as a helper to
|
||||||
|
be used internally, so there is no replacement. If you need this functionality
|
||||||
|
though, it is a very short class that can easily be recreated in your own code.
|
||||||
|
|
||||||
API Changes
|
API Changes
|
||||||
===========
|
===========
|
||||||
|
|
|
@ -29,10 +29,11 @@ import tempfile
|
||||||
|
|
||||||
from . import Image, ImageFile
|
from . import Image, ImageFile
|
||||||
from ._binary import i32le as i32
|
from ._binary import i32le as i32
|
||||||
|
from ._deprecate import deprecate
|
||||||
|
|
||||||
#
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$")
|
split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$")
|
||||||
field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$")
|
field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$")
|
||||||
|
|
||||||
|
@ -162,9 +163,16 @@ def Ghostscript(tile, size, fp, scale=1, transparency=False):
|
||||||
class PSFile:
|
class PSFile:
|
||||||
"""
|
"""
|
||||||
Wrapper for bytesio object that treats either CR or LF as end of line.
|
Wrapper for bytesio object that treats either CR or LF as end of line.
|
||||||
|
This class is no longer used internally, but kept for backwards compatibility.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, fp):
|
def __init__(self, fp):
|
||||||
|
deprecate(
|
||||||
|
"PSFile",
|
||||||
|
11,
|
||||||
|
action="If you need the functionality of this class "
|
||||||
|
"you will need to implement it yourself.",
|
||||||
|
)
|
||||||
self.fp = fp
|
self.fp = fp
|
||||||
self.char = None
|
self.char = None
|
||||||
|
|
||||||
|
@ -173,13 +181,11 @@ class PSFile:
|
||||||
self.fp.seek(offset, whence)
|
self.fp.seek(offset, whence)
|
||||||
|
|
||||||
def readline(self):
|
def readline(self):
|
||||||
s = []
|
s = [self.char or b""]
|
||||||
if self.char:
|
|
||||||
s.append(self.char)
|
|
||||||
self.char = None
|
self.char = None
|
||||||
|
|
||||||
c = self.fp.read(1)
|
c = self.fp.read(1)
|
||||||
while (c not in b"\r\n") and len(c) and len(b"".join(s).strip(b"\r\n")) <= 255:
|
while (c not in b"\r\n") and len(c):
|
||||||
s.append(c)
|
s.append(c)
|
||||||
c = self.fp.read(1)
|
c = self.fp.read(1)
|
||||||
|
|
||||||
|
@ -211,29 +217,69 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
def _open(self):
|
def _open(self):
|
||||||
(length, offset) = self._find_offset(self.fp)
|
(length, offset) = self._find_offset(self.fp)
|
||||||
|
|
||||||
# Rewrap the open file pointer in something that will
|
|
||||||
# convert line endings and decode to latin-1.
|
|
||||||
fp = PSFile(self.fp)
|
|
||||||
|
|
||||||
# go to offset - start of "%!PS"
|
# go to offset - start of "%!PS"
|
||||||
fp.seek(offset)
|
self.fp.seek(offset)
|
||||||
|
|
||||||
box = None
|
|
||||||
|
|
||||||
self.mode = "RGB"
|
self.mode = "RGB"
|
||||||
self._size = 1, 1 # FIXME: huh?
|
self._size = None
|
||||||
|
|
||||||
#
|
byte_arr = bytearray(255)
|
||||||
# Load EPS header
|
bytes_mv = memoryview(byte_arr)
|
||||||
|
bytes_read = 0
|
||||||
|
reading_comments = True
|
||||||
|
|
||||||
s_raw = fp.readline()
|
def check_required_header_comments():
|
||||||
s = s_raw.strip("\r\n")
|
if "PS-Adobe" not in self.info:
|
||||||
|
msg = 'EPS header missing "%!PS-Adobe" comment'
|
||||||
|
raise SyntaxError(msg)
|
||||||
|
if "BoundingBox" not in self.info:
|
||||||
|
msg = 'EPS header missing "%%BoundingBox" comment'
|
||||||
|
raise SyntaxError(msg)
|
||||||
|
|
||||||
while s_raw:
|
while True:
|
||||||
if s:
|
byte = self.fp.read(1)
|
||||||
if len(s) > 255:
|
if byte == b"":
|
||||||
|
# if we didn't read a byte we must be at the end of the file
|
||||||
|
if bytes_read == 0:
|
||||||
|
break
|
||||||
|
elif byte in b"\r\n":
|
||||||
|
# if we read a line ending character, ignore it and parse what
|
||||||
|
# we have already read. if we haven't read any other characters,
|
||||||
|
# continue reading
|
||||||
|
if bytes_read == 0:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# ASCII/hexadecimal lines in an EPS file must not exceed
|
||||||
|
# 255 characters, not including line ending characters
|
||||||
|
if bytes_read >= 255:
|
||||||
|
# only enforce this for lines starting with a "%",
|
||||||
|
# otherwise assume it's binary data
|
||||||
|
if byte_arr[0] == ord("%"):
|
||||||
msg = "not an EPS file"
|
msg = "not an EPS file"
|
||||||
raise SyntaxError(msg)
|
raise SyntaxError(msg)
|
||||||
|
else:
|
||||||
|
if reading_comments:
|
||||||
|
check_required_header_comments()
|
||||||
|
reading_comments = False
|
||||||
|
# reset bytes_read so we can keep reading
|
||||||
|
# data until the end of the line
|
||||||
|
bytes_read = 0
|
||||||
|
byte_arr[bytes_read] = byte[0]
|
||||||
|
bytes_read += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if reading_comments:
|
||||||
|
# Load EPS header
|
||||||
|
|
||||||
|
# if this line doesn't start with a "%",
|
||||||
|
# or does start with "%%EndComments",
|
||||||
|
# then we've reached the end of the header/comments
|
||||||
|
if byte_arr[0] != ord("%") or bytes_mv[:13] == b"%%EndComments":
|
||||||
|
check_required_header_comments()
|
||||||
|
reading_comments = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
s = str(bytes_mv[:bytes_read], "latin-1")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
m = split.match(s)
|
m = split.match(s)
|
||||||
|
@ -256,16 +302,12 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
]
|
]
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
else:
|
else:
|
||||||
m = field.match(s)
|
m = field.match(s)
|
||||||
if m:
|
if m:
|
||||||
k = m.group(1)
|
k = m.group(1)
|
||||||
|
|
||||||
if k == "EndComments":
|
|
||||||
break
|
|
||||||
if k[:8] == "PS-Adobe":
|
if k[:8] == "PS-Adobe":
|
||||||
self.info[k[:8]] = k[9:]
|
self.info["PS-Adobe"] = k[9:]
|
||||||
else:
|
else:
|
||||||
self.info[k] = ""
|
self.info[k] = ""
|
||||||
elif s[0] == "%":
|
elif s[0] == "%":
|
||||||
|
@ -275,43 +317,44 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
else:
|
else:
|
||||||
msg = "bad EPS header"
|
msg = "bad EPS header"
|
||||||
raise OSError(msg)
|
raise OSError(msg)
|
||||||
|
elif bytes_mv[:11] == b"%ImageData:":
|
||||||
|
# Check for an "ImageData" descriptor
|
||||||
|
# https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577413_pgfId-1035096
|
||||||
|
|
||||||
s_raw = fp.readline()
|
# Values:
|
||||||
s = s_raw.strip("\r\n")
|
# columns
|
||||||
|
# rows
|
||||||
|
# bit depth (1 or 8)
|
||||||
|
# mode (1: L, 2: LAB, 3: RGB, 4: CMYK)
|
||||||
|
# number of padding channels
|
||||||
|
# block size (number of bytes per row per channel)
|
||||||
|
# binary/ascii (1: binary, 2: ascii)
|
||||||
|
# data start identifier (the image data follows after a single line
|
||||||
|
# consisting only of this quoted value)
|
||||||
|
image_data_values = byte_arr[11:bytes_read].split(None, 7)
|
||||||
|
columns, rows, bit_depth, mode_id = [
|
||||||
|
int(value) for value in image_data_values[:4]
|
||||||
|
]
|
||||||
|
|
||||||
if s and s[:1] != "%":
|
if bit_depth == 1:
|
||||||
break
|
|
||||||
|
|
||||||
#
|
|
||||||
# Scan for an "ImageData" descriptor
|
|
||||||
|
|
||||||
while s[:1] == "%":
|
|
||||||
if len(s) > 255:
|
|
||||||
msg = "not an EPS file"
|
|
||||||
raise SyntaxError(msg)
|
|
||||||
|
|
||||||
if s[:11] == "%ImageData:":
|
|
||||||
# Encoded bitmapped image.
|
|
||||||
x, y, bi, mo = s[11:].split(None, 7)[:4]
|
|
||||||
|
|
||||||
if int(bi) == 1:
|
|
||||||
self.mode = "1"
|
self.mode = "1"
|
||||||
elif int(bi) == 8:
|
elif bit_depth == 8:
|
||||||
try:
|
try:
|
||||||
self.mode = self.mode_map[int(mo)]
|
self.mode = self.mode_map[mode_id]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
self._size = int(x), int(y)
|
self._size = columns, rows
|
||||||
return
|
return
|
||||||
|
|
||||||
s = fp.readline().strip("\r\n")
|
bytes_read = 0
|
||||||
if not s:
|
|
||||||
break
|
|
||||||
|
|
||||||
if not box:
|
check_required_header_comments()
|
||||||
|
|
||||||
|
if not self._size:
|
||||||
|
self._size = 1, 1 # errors if this isn't set. why (1,1)?
|
||||||
msg = "cannot determine EPS bounding box"
|
msg = "cannot determine EPS bounding box"
|
||||||
raise OSError(msg)
|
raise OSError(msg)
|
||||||
|
|
||||||
|
@ -353,18 +396,15 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def _save(im, fp, filename, eps=1):
|
def _save(im, fp, filename, eps=1):
|
||||||
"""EPS Writer for the Python Imaging Library."""
|
"""EPS Writer for the Python Imaging Library."""
|
||||||
|
|
||||||
#
|
|
||||||
# make sure image data is available
|
# make sure image data is available
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
#
|
|
||||||
# determine PostScript image mode
|
# determine PostScript image mode
|
||||||
if im.mode == "L":
|
if im.mode == "L":
|
||||||
operator = (8, 1, b"image")
|
operator = (8, 1, b"image")
|
||||||
|
@ -377,7 +417,6 @@ def _save(im, fp, filename, eps=1):
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
if eps:
|
if eps:
|
||||||
#
|
|
||||||
# write EPS header
|
# write EPS header
|
||||||
fp.write(b"%!PS-Adobe-3.0 EPSF-3.0\n")
|
fp.write(b"%!PS-Adobe-3.0 EPSF-3.0\n")
|
||||||
fp.write(b"%%Creator: PIL 0.1 EpsEncode\n")
|
fp.write(b"%%Creator: PIL 0.1 EpsEncode\n")
|
||||||
|
@ -389,7 +428,6 @@ def _save(im, fp, filename, eps=1):
|
||||||
fp.write(b"%%ImageData: %d %d " % im.size)
|
fp.write(b"%%ImageData: %d %d " % im.size)
|
||||||
fp.write(b'%d %d 0 1 1 "%s"\n' % operator)
|
fp.write(b'%d %d 0 1 1 "%s"\n' % operator)
|
||||||
|
|
||||||
#
|
|
||||||
# image header
|
# image header
|
||||||
fp.write(b"gsave\n")
|
fp.write(b"gsave\n")
|
||||||
fp.write(b"10 dict begin\n")
|
fp.write(b"10 dict begin\n")
|
||||||
|
@ -410,7 +448,6 @@ def _save(im, fp, filename, eps=1):
|
||||||
fp.flush()
|
fp.flush()
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ def deprecate(
|
||||||
elif when == 11:
|
elif when == 11:
|
||||||
removed = "Pillow 11 (2024-10-15)"
|
removed = "Pillow 11 (2024-10-15)"
|
||||||
else:
|
else:
|
||||||
msg = f"Unknown removal version, update {__name__}?"
|
msg = f"Unknown removal version: {when}. Update {__name__}?"
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
if replacement and action:
|
if replacement and action:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user