@@ -105,6 +105,8 @@ def _open(self):
105105
106106 maxval = None
107107 decoder_name = "raw"
108+ if magic_number in (b"P1" , b"P2" , b"P3" ):
109+ decoder_name = "ppm_plain"
108110 for ix in range (3 ):
109111 token = int (self ._read_token ())
110112 if ix == 0 : # token is the x size
@@ -126,14 +128,13 @@ def _open(self):
126128 if maxval > 255 and mode == "L" :
127129 self .mode = "I"
128130
129- # If maxval matches a bit depth, use the raw decoder directly
130- if maxval == 65535 and mode == "L" :
131- rawmode = "I;16B"
132- elif maxval != 255 :
133- decoder_name = "ppm"
131+ if decoder_name != "ppm_plain" :
132+ # If maxval matches a bit depth, use the raw decoder directly
133+ if maxval == 65535 and mode == "L" :
134+ rawmode = "I;16B"
135+ elif maxval != 255 :
136+ decoder_name = "ppm"
134137
135- if magic_number in (b"P1" , b"P2" , b"P3" ):
136- decoder_name = "ppm_plain"
137138 args = (rawmode , 0 , 1 ) if decoder_name == "raw" else (rawmode , maxval )
138139 self ._size = xsize , ysize
139140 self .tile = [(decoder_name , (0 , 0 , xsize , ysize ), self .fp .tell (), args )]
@@ -156,7 +157,7 @@ def _find_comment_end(self, block, start=0):
156157
157158 def _ignore_comments (self , block ):
158159 """
159- Deletes comments from block.
160+ Delete comments from block.
160161 If comment does not end in this block, raises a flag.
161162 """
162163 comment_spans = False
@@ -176,14 +177,14 @@ def _ignore_comments(self, block):
176177
177178 def _decode_bitonal (self ):
178179 """
179- This is a separate method because the plain PBM format all data tokens
180- are exactly one byte, and so the inter-token whitespace is optional.
180+ This is a separate method because in the plain PBM format, all data tokens are
181+ exactly one byte, so the inter-token whitespace is optional.
181182 """
182- decoded_data = bytearray ()
183+ data = bytearray ()
183184 total_bytes = self .state .xsize * self .state .ysize
184185
185186 comment_spans = False
186- while len (decoded_data ) != total_bytes :
187+ while len (data ) != total_bytes :
187188 block = self ._read_block () # read next block
188189 if not block :
189190 # eof
@@ -193,7 +194,7 @@ def _decode_bitonal(self):
193194 comment_end = self ._find_comment_end (block )
194195 if comment_end != - 1 : # comment ends in this block
195196 block = block [comment_end + 1 :] # delete tail of previous comment
196- comment_spans = False
197+ break
197198 else : # comment spans whole block
198199 block = self ._read_block ()
199200
@@ -203,19 +204,21 @@ def _decode_bitonal(self):
203204 for token in tokens :
204205 if token not in (48 , 49 ):
205206 raise ValueError (f"Invalid token for this mode: { bytes ([token ])} " )
206- decoded_data = (decoded_data + tokens )[:total_bytes ]
207+ data = (data + tokens )[:total_bytes ]
207208 invert = bytes .maketrans (b"01" , b"\xFF \x00 " )
208- return decoded_data .translate (invert )
209+ return data .translate (invert )
209210
210- def _decode_blocks (self , channels , depth , maxval ):
211- decoded_data = bytearray ()
211+ def _decode_blocks (self , maxval ):
212+ data = bytearray ()
212213 max_len = 10
213- bytes_per_sample = depth // 8
214- total_bytes = self .state .xsize * self .state .ysize * channels * bytes_per_sample
214+ out_byte_count = 4 if self .mode == "I" else 1
215+ out_max = 65535 if self .mode == "I" else 255
216+ bands = Image .getmodebands (self .mode )
217+ total_bytes = self .state .xsize * self .state .ysize * bands * out_byte_count
215218
216219 comment_spans = False
217220 half_token = False
218- while len (decoded_data ) != total_bytes :
221+ while len (data ) != total_bytes :
219222 block = self ._read_block () # read next block
220223 if not block :
221224 if half_token :
@@ -251,31 +254,24 @@ def _decode_blocks(self, channels, depth, maxval):
251254 raise ValueError (
252255 f"Token too long found in data: { token [:max_len + 1 ]} "
253256 )
254- token = int (token )
255- if token > maxval :
256- raise ValueError (f"Channel value too large for this mode: { token } " )
257- decoded_data += token .to_bytes (bytes_per_sample , "big" )
258- if len (decoded_data ) == total_bytes : # finished!
257+ value = int (token )
258+ if value > maxval :
259+ raise ValueError (f"Channel value too large for this mode: { value } " )
260+ value = round (value / maxval * out_max )
261+ data += o32 (value ) if self .mode == "I" else o8 (value )
262+ if len (data ) == total_bytes : # finished!
259263 break
260- return decoded_data
264+ return data
261265
262266 def decode (self , buffer ):
263- rawmode , maxval = self .args
264-
265267 if self .mode == "1" :
266- decoded_data = self ._decode_bitonal ()
268+ data = self ._decode_bitonal ()
267269 rawmode = "1;8"
268- elif self .mode == "L" :
269- decoded_data = self ._decode_blocks (1 , 8 , maxval )
270- elif self .mode == "I" :
271- if rawmode == "I;16B" :
272- decoded_data = self ._decode_blocks (1 , 16 , maxval )
273- elif rawmode == "I;32B" :
274- decoded_data = self ._decode_blocks (1 , 32 , maxval )
275- elif self .mode == "RGB" :
276- decoded_data = self ._decode_blocks (3 , 8 , maxval )
277-
278- self .set_as_raw (bytes (decoded_data ), rawmode )
270+ else :
271+ maxval = self .args [- 1 ]
272+ data = self ._decode_blocks (maxval )
273+ rawmode = "I;32" if self .mode == "I" else self .mode
274+ self .set_as_raw (bytes (data ), rawmode )
279275 return - 1 , 0
280276
281277
@@ -284,7 +280,7 @@ class PpmDecoder(ImageFile.PyDecoder):
284280
285281 def decode (self , buffer ):
286282 data = bytearray ()
287- maxval = min ( self .args [- 1 ], 65535 )
283+ maxval = self .args [- 1 ]
288284 in_byte_count = 1 if maxval < 256 else 2
289285 out_byte_count = 4 if self .mode == "I" else 1
290286 out_max = 65535 if self .mode == "I" else 255
@@ -301,7 +297,7 @@ def decode(self, buffer):
301297 value = min (out_max , round (value / maxval * out_max ))
302298 data += o32 (value ) if self .mode == "I" else o8 (value )
303299 rawmode = "I;32" if self .mode == "I" else self .mode
304- self .set_as_raw (bytes (data ), ( rawmode , 0 , 1 ) )
300+ self .set_as_raw (bytes (data ), rawmode )
305301 return - 1 , 0
306302
307303
@@ -337,11 +333,12 @@ def _save(im, fp, filename):
337333#
338334# --------------------------------------------------------------------
339335
340- Image . register_decoder ( "ppm_plain" , PpmPlainDecoder )
336+
341337Image .register_open (PpmImageFile .format , PpmImageFile , _accept )
342338Image .register_save (PpmImageFile .format , _save )
343339
344340Image .register_decoder ("ppm" , PpmDecoder )
341+ Image .register_decoder ("ppm_plain" , PpmPlainDecoder )
345342
346343Image .register_extensions (PpmImageFile .format , [".pbm" , ".pgm" , ".ppm" , ".pnm" ])
347344
0 commit comments