@@ -53,24 +53,20 @@ def _open(self) -> None:
53
53
54
54
self ._size = int (m .group (1 )), int (m .group (2 ))
55
55
56
- pal = int (m .group (3 ))
56
+ palette_length = int (m .group (3 ))
57
57
bpp = int (m .group (4 ))
58
58
59
- if pal > 256 or bpp != 1 :
59
+ if palette_length > 256 or bpp != 1 :
60
60
msg = "cannot read this XPM file"
61
61
raise ValueError (msg )
62
62
63
63
#
64
64
# load palette description
65
65
66
- palette = [ b" \0 \0 \0 " ] * 256
66
+ palette = {}
67
67
68
- for _ in range (pal ):
69
- s = self .fp .readline ()
70
- if s .endswith (b"\r \n " ):
71
- s = s [:- 2 ]
72
- elif s .endswith ((b"\r " , b"\n " )):
73
- s = s [:- 1 ]
68
+ for _ in range (palette_length ):
69
+ s = self .fp .readline ().rstrip ()
74
70
75
71
c = s [1 ]
76
72
s = s [2 :- 2 ].split ()
@@ -82,7 +78,6 @@ def _open(self) -> None:
82
78
if rgb == b"None" :
83
79
self .info ["transparency" ] = c
84
80
elif rgb .startswith (b"#" ):
85
- # FIXME: handle colour names (see ImagePalette.py)
86
81
rgb = int (rgb [1 :], 16 )
87
82
palette [c ] = (
88
83
o8 ((rgb >> 16 ) & 255 ) + o8 ((rgb >> 8 ) & 255 ) + o8 (rgb & 255 )
@@ -99,9 +94,12 @@ def _open(self) -> None:
99
94
raise ValueError (msg )
100
95
101
96
self ._mode = "P"
102
- self .palette = ImagePalette .raw ("RGB" , b"" .join (palette ))
97
+ self .palette = ImagePalette .raw ("RGB" , b"" .join (palette . values () ))
103
98
104
- self .tile = [ImageFile ._Tile ("raw" , (0 , 0 ) + self .size , self .fp .tell (), "P" )]
99
+ palette_keys = tuple (palette .keys ())
100
+ self .tile = [
101
+ ImageFile ._Tile ("xpm" , (0 , 0 ) + self .size , self .fp .tell (), (palette_keys ,))
102
+ ]
105
103
106
104
def load_read (self , read_bytes : int ) -> bytes :
107
105
#
@@ -114,11 +112,31 @@ def load_read(self, read_bytes: int) -> bytes:
114
112
return b"" .join (s )
115
113
116
114
115
+ class XpmDecoder (ImageFile .PyDecoder ):
116
+ _pulls_fd = True
117
+
118
+ def decode (self , buffer : bytes | Image .SupportsArrayInterface ) -> tuple [int , int ]:
119
+ assert self .fd is not None
120
+ self .fd .readline () # Read '/* pixels */'
121
+
122
+ data = bytearray ()
123
+ palette_keys = self .args [0 ]
124
+ dest_length = self .state .xsize * self .state .ysize
125
+ while len (data ) < dest_length :
126
+ s = self .fd .readline ().rstrip ()[1 :]
127
+ s = s [: - 1 if s .endswith (b'"' ) else - 2 ]
128
+ for key in s :
129
+ data += o8 (palette_keys .index (key ))
130
+ self .set_as_raw (bytes (data ))
131
+ return - 1 , 0
132
+
133
+
117
134
#
118
135
# Registry
119
136
120
137
121
138
Image .register_open (XpmImageFile .format , XpmImageFile , _accept )
139
+ Image .register_decoder ("xpm" , XpmDecoder )
122
140
123
141
Image .register_extension (XpmImageFile .format , ".xpm" )
124
142
0 commit comments