Skip to content

Commit a12389b

Browse files
committed
Provide way to load big palettes;
1 parent 1ed6039 commit a12389b

3 files changed

Lines changed: 49 additions & 5 deletions

File tree

Tests/images/custom_gimp_palette.gpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
GIMP Palette
22
Name: custompalette
33
Columns: 4
4-
#
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
55
0 0 0 Index 0
66
65 38 30 Index 1
77
103 62 49 Index 2

Tests/test_file_gimppalette.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,21 @@ def test_sanity():
2020
GimpPaletteFile(fp)
2121

2222

23+
def test_large_file_is_truncated():
24+
import warnings
25+
from unittest.mock import patch
26+
try:
27+
original_value = GimpPaletteFile._max_file_size
28+
GimpPaletteFile._max_file_size = 100
29+
with warnings.catch_warnings():
30+
warnings.simplefilter("error")
31+
with pytest.raises(UserWarning):
32+
with open("Tests/images/custom_gimp_palette.gpl", "rb") as fp:
33+
palette_file = GimpPaletteFile(fp)
34+
35+
finally:
36+
GimpPaletteFile._max_file_size = original_value
37+
2338
def test_get_palette():
2439
# Arrange
2540
with open("Tests/images/custom_gimp_palette.gpl", "rb") as fp:
@@ -43,3 +58,13 @@ def test_get_palette():
4358
expected_palette += bytes(color)
4459
assert palette == expected_palette
4560
assert mode == "RGB"
61+
62+
63+
def test_n_colors():
64+
# Arrange
65+
with open("Tests/images/custom_gimp_palette.gpl", "rb") as fp:
66+
palette_file = GimpPaletteFile(fp)
67+
68+
palette, _ = palette_file.getpalette()
69+
assert len(palette) == 24
70+
assert palette_file.n_colors == 8

src/PIL/GimpPaletteFile.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#
1616

1717
import re
18+
import warnings
1819

1920
from ._binary import o8
2021

@@ -24,25 +25,39 @@ class GimpPaletteFile:
2425

2526
rawmode = "RGB"
2627

28+
#: override if reading larger palettes is needed
29+
max_colors = 256
30+
_max_line_size = 100
31+
_max_file_size = 2 ** 20
32+
2733
def __init__(self, fp):
2834

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

38+
read = 0
39+
3240
self.palette = b""
33-
while len(self.palette) < 768:
41+
while len(self.palette) < 3 * self.max_colors:
3442

35-
s = fp.readline()
43+
s = fp.readline(self._max_file_size)
3644
if not s:
3745
break
3846

47+
read += len(s)
48+
if read >= self._max_file_size:
49+
warnings.warn(
50+
f"Palette file truncated at {self._max_file_size - len(s)} bytes")
51+
break
52+
3953
# skip fields and comment lines
4054
if re.match(rb"\w+:|#", s):
4155
continue
42-
if len(s) > 100:
56+
if len(s) > self._max_line_size:
4357
raise SyntaxError("bad palette file")
4458

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

5368
return self.palette, self.rawmode
69+
70+
@property
71+
def n_colors(self):
72+
return len(self.palette) / 3

0 commit comments

Comments
 (0)