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
18 changes: 18 additions & 0 deletions Tests/test_file_png.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,24 @@ def test_roundtrip_itxt(self) -> None:
assert im.text["eggs"].lang == "en"
assert im.text["eggs"].tkey == "Eggs"

def test_text_key(self) -> None:
info = PngImagePlugin.PngInfo()

for length in (0, 80):
with pytest.raises(
ValueError, match="Text key must be 1 to 79 characters long"
):
info.add_itxt("k" * length, "value")
with pytest.raises(ValueError, match="Text key cannot contain null characters"):
info.add_text("a\0b", "value")
assert info.chunks == []

info.add_itxt("i" * 79, "value")
info.add_text("t" * 79, "value")

im = roundtrip(Image.new("RGB", (1, 1)), pnginfo=info)
assert im.text == {"i" * 79: "value", "t" * 79: "value"}

def test_nonunicode_text(self) -> None:
# Check so that non-Unicode text is saved as a tEXt rather than iTXt

Expand Down
16 changes: 14 additions & 2 deletions src/PIL/PngImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,16 @@ def add(self, cid: bytes, data: bytes, after_idat: bool = False) -> None:

self.chunks.append((cid, data, after_idat))

def _check_text_key(self, key: bytes) -> None:
if not 1 <= len(key) <= 79:
msg = "Text key must be 1 to 79 characters long"
raise ValueError(msg)

if b"\0" in key:
# The NULL character is the separator after the key
msg = "Text key cannot contain null characters"
raise ValueError(msg)

def add_itxt(
self,
key: str | bytes,
Expand All @@ -320,7 +330,7 @@ def add_itxt(
) -> None:
"""Appends an iTXt chunk.

:param key: latin-1 encodable text key name
:param key: latin-1 encodable text key name. 1 to 79 characters long
:param value: value for this key
:param lang: language code
:param tkey: UTF-8 version of the key name
Expand All @@ -330,6 +340,7 @@ def add_itxt(

if not isinstance(key, bytes):
key = key.encode("latin-1", "strict")
self._check_text_key(key)
if not isinstance(value, bytes):
value = value.encode("utf-8", "strict")
if not isinstance(lang, bytes):
Expand All @@ -350,7 +361,7 @@ def add_text(
) -> None:
"""Appends a text chunk.

:param key: latin-1 encodable text key name
:param key: latin-1 encodable text key name. 1 to 79 characters long
:param value: value for this key, text or an
:py:class:`PIL.PngImagePlugin.iTXt` instance
:param zip: compression flag
Expand All @@ -374,6 +385,7 @@ def add_text(

if not isinstance(key, bytes):
key = key.encode("latin-1", "strict")
self._check_text_key(key)

if zip:
self.add(b"zTXt", key + b"\0\0" + zlib.compress(value))
Expand Down
Loading