Skip to content

Commit

Permalink
Provide way to load big palettes;
Browse files Browse the repository at this point in the history
  • Loading branch information
jsbueno committed Oct 6, 2022
1 parent 1ed6039 commit a12389b
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Tests/images/custom_gimp_palette.gpl
@@ -1,7 +1,7 @@
GIMP Palette
Name: custompalette
Columns: 4
#
# Original written by David Wetz in https://stackoverflow.com/questions/815836/im-creating-a-program-that-generates-a-palette-from-a-true-color-image-need-hel/815855#815855
0 0 0 Index 0
65 38 30 Index 1
103 62 49 Index 2
Expand Down
25 changes: 25 additions & 0 deletions Tests/test_file_gimppalette.py
Expand Up @@ -20,6 +20,21 @@ def test_sanity():
GimpPaletteFile(fp)


def test_large_file_is_truncated():
import warnings
from unittest.mock import patch
try:
original_value = GimpPaletteFile._max_file_size
GimpPaletteFile._max_file_size = 100
with warnings.catch_warnings():
warnings.simplefilter("error")
with pytest.raises(UserWarning):
with open("Tests/images/custom_gimp_palette.gpl", "rb") as fp:
palette_file = GimpPaletteFile(fp)

finally:
GimpPaletteFile._max_file_size = original_value

def test_get_palette():
# Arrange
with open("Tests/images/custom_gimp_palette.gpl", "rb") as fp:
Expand All @@ -43,3 +58,13 @@ def test_get_palette():
expected_palette += bytes(color)
assert palette == expected_palette
assert mode == "RGB"


def test_n_colors():
# Arrange
with open("Tests/images/custom_gimp_palette.gpl", "rb") as fp:
palette_file = GimpPaletteFile(fp)

palette, _ = palette_file.getpalette()
assert len(palette) == 24
assert palette_file.n_colors == 8
27 changes: 23 additions & 4 deletions src/PIL/GimpPaletteFile.py
Expand Up @@ -15,6 +15,7 @@
#

import re
import warnings

from ._binary import o8

Expand All @@ -24,25 +25,39 @@ class GimpPaletteFile:

rawmode = "RGB"

#: override if reading larger palettes is needed
max_colors = 256
_max_line_size = 100
_max_file_size = 2 ** 20

def __init__(self, fp):

if fp.readline()[:12] != b"GIMP Palette":
raise SyntaxError("not a GIMP palette file")

read = 0

self.palette = b""
while len(self.palette) < 768:
while len(self.palette) < 3 * self.max_colors:

s = fp.readline()
s = fp.readline(self._max_file_size)
if not s:
break

read += len(s)
if read >= self._max_file_size:
warnings.warn(
f"Palette file truncated at {self._max_file_size - len(s)} bytes")
break

# skip fields and comment lines
if re.match(rb"\w+:|#", s):
continue
if len(s) > 100:
if len(s) > self._max_line_size:
raise SyntaxError("bad palette file")

v = s.split()
# 4th column is color name and may contain spaces.
v = s.split(None, 4)
if len(v) < 3:
raise ValueError("bad palette entry")
for i in range(3):
Expand All @@ -51,3 +66,7 @@ def __init__(self, fp):
def getpalette(self):

return self.palette, self.rawmode

@property
def n_colors(self):
return len(self.palette) / 3

0 comments on commit a12389b

Please sign in to comment.