mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-06-11 00:23:21 +03:00
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
This commit is contained in:
parent
9b8c29fdc0
commit
86476a9bd2
|
@ -18,7 +18,7 @@ def test_posy_link():
|
||||||
assert im.size == (128, 128)
|
assert im.size == (128, 128)
|
||||||
assert im.getpixel((0, 0)) == (0, 0, 0, 0)
|
assert im.getpixel((0, 0)) == (0, 0, 0, 0)
|
||||||
assert im.getpixel((20, 20)) == (0, 0, 0, 255)
|
assert im.getpixel((20, 20)) == (0, 0, 0, 255)
|
||||||
assert im.getpixel((40,40)) == (255, 255, 255, 255)
|
assert im.getpixel((40, 40)) == (255, 255, 255, 255)
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_file():
|
def test_invalid_file():
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
from io import BytesIO
|
|
||||||
import struct
|
import struct
|
||||||
from PIL import Image, CurImagePlugin, ImageFile, BmpImagePlugin
|
from io import BytesIO
|
||||||
|
|
||||||
|
from PIL import BmpImagePlugin, CurImagePlugin, Image, ImageFile
|
||||||
from PIL._binary import i16le as i16
|
from PIL._binary import i16le as i16
|
||||||
from PIL._binary import i32le as i32
|
from PIL._binary import i32le as i32
|
||||||
from PIL._binary import o8
|
from PIL._binary import o8
|
||||||
from PIL._binary import o16le as o16
|
from PIL._binary import o16le as o16
|
||||||
from PIL._binary import o32le as o32
|
from PIL._binary import o32le as o32
|
||||||
|
|
||||||
|
|
||||||
def _accept(s):
|
def _accept(s):
|
||||||
return s[:4] == b'RIFF'
|
return s[:4] == b"RIFF"
|
||||||
|
|
||||||
|
|
||||||
def _save_frame(im: Image.Image, fp: BytesIO, filename: str, info: dict):
|
def _save_frame(im: Image.Image, fp: BytesIO, filename: str, info: dict):
|
||||||
|
@ -71,11 +73,12 @@ def _save_frame(im: Image.Image, fp: BytesIO, filename: str, info: dict):
|
||||||
offset = offset + bytes_len
|
offset = offset + bytes_len
|
||||||
fp.seek(current)
|
fp.seek(current)
|
||||||
|
|
||||||
|
|
||||||
def _write_single_frame(im: Image.Image, fp: BytesIO, filename: str):
|
def _write_single_frame(im: Image.Image, fp: BytesIO, filename: str):
|
||||||
fp.write(b"anih")
|
fp.write(b"anih")
|
||||||
anih = o32(36) + o32(36) + (o32(1) * 2) + (o32(0) * 4) + o32(60) + o32(1)
|
anih = o32(36) + o32(36) + (o32(1) * 2) + (o32(0) * 4) + o32(60) + o32(1)
|
||||||
fp.write(anih)
|
fp.write(anih)
|
||||||
|
|
||||||
fp.write(b"LIST" + o32(0))
|
fp.write(b"LIST" + o32(0))
|
||||||
list_offset = fp.tell()
|
list_offset = fp.tell()
|
||||||
fp.write(b"fram")
|
fp.write(b"fram")
|
||||||
|
@ -89,7 +92,7 @@ def _write_single_frame(im: Image.Image, fp: BytesIO, filename: str):
|
||||||
|
|
||||||
fp.write(icon_data)
|
fp.write(icon_data)
|
||||||
fram_end = fp.tell()
|
fram_end = fp.tell()
|
||||||
|
|
||||||
fp.seek(icon_offset - 4)
|
fp.seek(icon_offset - 4)
|
||||||
icon_size = fram_end - icon_offset
|
icon_size = fram_end - icon_offset
|
||||||
fp.write(o32(icon_size))
|
fp.write(o32(icon_size))
|
||||||
|
@ -100,7 +103,8 @@ def _write_single_frame(im: Image.Image, fp: BytesIO, filename: str):
|
||||||
|
|
||||||
fp.seek(fram_end)
|
fp.seek(fram_end)
|
||||||
|
|
||||||
def _write_multiple_frames(im: Image.Image, fp: BytesIO, filename:str):
|
|
||||||
|
def _write_multiple_frames(im: Image.Image, fp: BytesIO, filename: str):
|
||||||
anih_offset = fp.tell()
|
anih_offset = fp.tell()
|
||||||
fp.write(b"anih" + o32(36))
|
fp.write(b"anih" + o32(36))
|
||||||
fp.write(o32(0) * 9)
|
fp.write(o32(0) * 9)
|
||||||
|
@ -120,7 +124,7 @@ def _write_multiple_frames(im: Image.Image, fp: BytesIO, filename:str):
|
||||||
|
|
||||||
fp.write(icon_data)
|
fp.write(icon_data)
|
||||||
fram_end = fp.tell()
|
fram_end = fp.tell()
|
||||||
|
|
||||||
fp.seek(icon_offset - 4)
|
fp.seek(icon_offset - 4)
|
||||||
icon_size = fram_end - icon_offset
|
icon_size = fram_end - icon_offset
|
||||||
fp.write(o32(icon_size))
|
fp.write(o32(icon_size))
|
||||||
|
@ -140,9 +144,9 @@ def _write_multiple_frames(im: Image.Image, fp: BytesIO, filename:str):
|
||||||
for i in seq:
|
for i in seq:
|
||||||
if i >= len(frames):
|
if i >= len(frames):
|
||||||
raise ValueError("Sequence index out of animation frame bounds")
|
raise ValueError("Sequence index out of animation frame bounds")
|
||||||
|
|
||||||
fp.write(o32(i))
|
fp.write(o32(i))
|
||||||
|
|
||||||
fram_end = fp.tell()
|
fram_end = fp.tell()
|
||||||
fp.seek(seq_offset - 4)
|
fp.seek(seq_offset - 4)
|
||||||
seq_size = fram_end - seq_offset
|
seq_size = fram_end - seq_offset
|
||||||
|
@ -154,14 +158,14 @@ def _write_multiple_frames(im: Image.Image, fp: BytesIO, filename:str):
|
||||||
if rate:
|
if rate:
|
||||||
fp.write(b"rate" + o32(0))
|
fp.write(b"rate" + o32(0))
|
||||||
rate_offset = fp.tell()
|
rate_offset = fp.tell()
|
||||||
|
|
||||||
if seq:
|
if seq:
|
||||||
if len(rate) != len(seq):
|
if len(rate) != len(seq):
|
||||||
raise ValueError("Length of rate must match rate of sequence")
|
raise ValueError("Length of rate must match rate of sequence")
|
||||||
else:
|
else:
|
||||||
if len(rate) != len(frames):
|
if len(rate) != len(frames):
|
||||||
raise ValueError("Length of rate must match number of frames")
|
raise ValueError("Length of rate must match number of frames")
|
||||||
|
|
||||||
for r in rate:
|
for r in rate:
|
||||||
fp.write(o32(r))
|
fp.write(o32(r))
|
||||||
|
|
||||||
|
@ -171,7 +175,7 @@ def _write_multiple_frames(im: Image.Image, fp: BytesIO, filename:str):
|
||||||
fp.write(o32(rate_size))
|
fp.write(o32(rate_size))
|
||||||
|
|
||||||
fp.seek(fram_end)
|
fp.seek(fram_end)
|
||||||
|
|
||||||
bmp = im.encoderinfo.get("bitmap_format") == "bmp"
|
bmp = im.encoderinfo.get("bitmap_format") == "bmp"
|
||||||
display_rate = im.encoderinfo.get("display_rate", 2)
|
display_rate = im.encoderinfo.get("display_rate", 2)
|
||||||
n_frames = len(frames)
|
n_frames = len(frames)
|
||||||
|
@ -182,13 +186,20 @@ def _write_multiple_frames(im: Image.Image, fp: BytesIO, filename:str):
|
||||||
|
|
||||||
fp.seek(anih_offset)
|
fp.seek(anih_offset)
|
||||||
fp.write(b"anih")
|
fp.write(b"anih")
|
||||||
anih = o32(36) + o32(36) + o32(n_frames) + o32(n_steps) + (o32(0) * 4) + o32(display_rate) + o32(flag)
|
anih = (
|
||||||
|
o32(36)
|
||||||
|
+ o32(36)
|
||||||
|
+ o32(n_frames)
|
||||||
|
+ o32(n_steps)
|
||||||
|
+ (o32(0) * 4)
|
||||||
|
+ o32(display_rate)
|
||||||
|
+ o32(flag)
|
||||||
|
)
|
||||||
fp.write(anih)
|
fp.write(anih)
|
||||||
|
|
||||||
fp.seek(fram_end)
|
fp.seek(fram_end)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _write_info(im: Image.Image, fp: BytesIO, filename: str):
|
def _write_info(im: Image.Image, fp: BytesIO, filename: str):
|
||||||
fp.write(b"LIST" + o32(0))
|
fp.write(b"LIST" + o32(0))
|
||||||
list_offset = fp.tell()
|
list_offset = fp.tell()
|
||||||
|
@ -214,7 +225,7 @@ def _write_info(im: Image.Image, fp: BytesIO, filename: str):
|
||||||
inam_size = fp.tell() - inam_offset
|
inam_size = fp.tell() - inam_offset
|
||||||
|
|
||||||
fp.write(b"IART" + o32(0))
|
fp.write(b"IART" + o32(0))
|
||||||
iart_offset = fp.tell()
|
iart_offset = fp.tell()
|
||||||
|
|
||||||
fp.write(iart + b"\x00")
|
fp.write(iart + b"\x00")
|
||||||
iart_size = fp.tell() - iart_offset
|
iart_size = fp.tell() - iart_offset
|
||||||
|
@ -230,16 +241,17 @@ def _write_info(im: Image.Image, fp: BytesIO, filename: str):
|
||||||
fp.seek(list_offset - 4)
|
fp.seek(list_offset - 4)
|
||||||
list_size = info_end - list_offset
|
list_size = info_end - list_offset
|
||||||
fp.write(o32(list_size))
|
fp.write(o32(list_size))
|
||||||
|
|
||||||
fp.seek(info_end)
|
fp.seek(info_end)
|
||||||
|
|
||||||
|
|
||||||
def _save(im: Image.Image, fp: BytesIO, filename: str):
|
def _save(im: Image.Image, fp: BytesIO, filename: str):
|
||||||
fp.write(b"RIFF\x00\x00\x00\x00")
|
fp.write(b"RIFF\x00\x00\x00\x00")
|
||||||
riff_offset = fp.tell()
|
riff_offset = fp.tell()
|
||||||
|
|
||||||
fp.write(b"ACON")
|
fp.write(b"ACON")
|
||||||
_write_info(im, fp, filename)
|
_write_info(im, fp, filename)
|
||||||
|
|
||||||
frames = im.encoderinfo.get("append_images", [])
|
frames = im.encoderinfo.get("append_images", [])
|
||||||
if frames:
|
if frames:
|
||||||
_write_multiple_frames(im, fp, filename)
|
_write_multiple_frames(im, fp, filename)
|
||||||
|
@ -251,9 +263,10 @@ def _save(im: Image.Image, fp: BytesIO, filename: str):
|
||||||
fp.seek(riff_offset - 4)
|
fp.seek(riff_offset - 4)
|
||||||
riff_size = riff_end - riff_offset
|
riff_size = riff_end - riff_offset
|
||||||
fp.write(o32(riff_size))
|
fp.write(o32(riff_size))
|
||||||
|
|
||||||
fp.seek(riff_end)
|
fp.seek(riff_end)
|
||||||
|
|
||||||
|
|
||||||
class AniFile:
|
class AniFile:
|
||||||
def __init__(self, buf: BytesIO) -> None:
|
def __init__(self, buf: BytesIO) -> None:
|
||||||
self.image_data = []
|
self.image_data = []
|
||||||
|
@ -263,25 +276,22 @@ class AniFile:
|
||||||
self.seq = None
|
self.seq = None
|
||||||
self.anih = None
|
self.anih = None
|
||||||
|
|
||||||
riff, size, fformat = struct.unpack('<4sI4s', buf.read(12))
|
riff, size, fformat = struct.unpack("<4sI4s", buf.read(12))
|
||||||
if riff != b'RIFF':
|
if riff != b"RIFF":
|
||||||
SyntaxError("Not an ANI file")
|
SyntaxError("Not an ANI file")
|
||||||
|
|
||||||
self.riff = {
|
self.riff = {"size": size, "fformat": fformat}
|
||||||
"size": size,
|
|
||||||
"fformat": fformat
|
|
||||||
}
|
|
||||||
|
|
||||||
chunkOffset = buf.tell()
|
chunkOffset = buf.tell()
|
||||||
while chunkOffset < self.riff['size']:
|
while chunkOffset < self.riff["size"]:
|
||||||
buf.seek(chunkOffset)
|
buf.seek(chunkOffset)
|
||||||
chunk, size = struct.unpack('<4sI', buf.read(8))
|
chunk, size = struct.unpack("<4sI", buf.read(8))
|
||||||
chunkOffset = chunkOffset + size + 8
|
chunkOffset = chunkOffset + size + 8
|
||||||
|
|
||||||
if chunk == b'anih':
|
if chunk == b"anih":
|
||||||
s = buf.read(36)
|
s = buf.read(36)
|
||||||
self.anih = {
|
self.anih = {
|
||||||
"size": i32(s), # Data structure size (in bytes)
|
"size": i32(s), # Data structure size (in bytes)
|
||||||
"nFrames": i32(s, 4), # Number of frames
|
"nFrames": i32(s, 4), # Number of frames
|
||||||
"nSteps": i32(s, 8), # Number of frames before repeat
|
"nSteps": i32(s, 8), # Number of frames before repeat
|
||||||
"iWidth": i32(s, 12), # Width of frame (in pixels)
|
"iWidth": i32(s, 12), # Width of frame (in pixels)
|
||||||
|
@ -293,22 +303,22 @@ class AniFile:
|
||||||
"bfAttributes": i32(s, 32), # ANI attribute bit flags
|
"bfAttributes": i32(s, 32), # ANI attribute bit flags
|
||||||
}
|
}
|
||||||
|
|
||||||
if chunk == b'seq ':
|
if chunk == b"seq ":
|
||||||
s = buf.read(size)
|
s = buf.read(size)
|
||||||
self.seq = [i32(s, i*4) for i in range(size // 4)]
|
self.seq = [i32(s, i * 4) for i in range(size // 4)]
|
||||||
|
|
||||||
if chunk == b'rate':
|
if chunk == b"rate":
|
||||||
s = buf.read(size)
|
s = buf.read(size)
|
||||||
self.rate = [i32(s, i*4) for i in range(size // 4)]
|
self.rate = [i32(s, i * 4) for i in range(size // 4)]
|
||||||
|
|
||||||
if chunk == b'LIST':
|
if chunk == b"LIST":
|
||||||
listtype = struct.unpack('<4s', buf.read(4))[0]
|
listtype = struct.unpack("<4s", buf.read(4))[0]
|
||||||
if listtype != b'fram':
|
if listtype != b"fram":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
listOffset = 0
|
listOffset = 0
|
||||||
while listOffset < size - 8:
|
while listOffset < size - 8:
|
||||||
_, lSize = struct.unpack('<4sI', buf.read(8))
|
_, lSize = struct.unpack("<4sI", buf.read(8))
|
||||||
self.image_data.append({"offset": buf.tell(), "size": lSize})
|
self.image_data.append({"offset": buf.tell(), "size": lSize})
|
||||||
|
|
||||||
buf.read(lSize)
|
buf.read(lSize)
|
||||||
|
@ -333,14 +343,13 @@ class AniFile:
|
||||||
|
|
||||||
im = CurImagePlugin.CurImageFile(BytesIO(data))
|
im = CurImagePlugin.CurImageFile(BytesIO(data))
|
||||||
return im
|
return im
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AniImageFile(ImageFile.ImageFile):
|
class AniImageFile(ImageFile.ImageFile):
|
||||||
format = "ANI"
|
format = "ANI"
|
||||||
format_description = "Windows Animated Cursor"
|
format_description = "Windows Animated Cursor"
|
||||||
|
|
||||||
def _open(self):
|
def _open(self):
|
||||||
self.ani = AniFile(self.fp)
|
self.ani = AniFile(self.fp)
|
||||||
self.frame = 0
|
self.frame = 0
|
||||||
self.seek(0)
|
self.seek(0)
|
||||||
|
@ -354,14 +363,13 @@ class AniImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
@size.setter
|
@size.setter
|
||||||
def size(self, value):
|
def size(self, value):
|
||||||
if value not in self.info['sizes']:
|
if value not in self.info["sizes"]:
|
||||||
raise ValueError("This is not one of the allowed sizes of this image")
|
raise ValueError("This is not one of the allowed sizes of this image")
|
||||||
self._size = value
|
self._size = value
|
||||||
|
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
im = self.ani.frame(self.frame)
|
im = self.ani.frame(self.frame)
|
||||||
self.info['sizes'] = im.info['sizes']
|
self.info["sizes"] = im.info["sizes"]
|
||||||
self.im = im.im
|
self.im = im.im
|
||||||
self.mode = im.mode
|
self.mode = im.mode
|
||||||
|
|
||||||
|
@ -372,7 +380,7 @@ class AniImageFile(ImageFile.ImageFile):
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
|
|
||||||
Image.register_open(AniImageFile.format, AniImageFile, _accept)
|
Image.register_open(AniImageFile.format, AniImageFile, _accept)
|
||||||
Image.register_extension(AniImageFile.format, ".ani")
|
Image.register_extension(AniImageFile.format, ".ani")
|
||||||
Image.register_save(AniImageFile.format, _save)
|
Image.register_save(AniImageFile.format, _save)
|
||||||
|
|
|
@ -29,6 +29,7 @@ from ._binary import o32le as o32
|
||||||
|
|
||||||
_MAGIC = b"\0\0\2\0"
|
_MAGIC = b"\0\0\2\0"
|
||||||
|
|
||||||
|
|
||||||
def _save(im: Image.Image, fp: BytesIO, filename: str):
|
def _save(im: Image.Image, fp: BytesIO, filename: str):
|
||||||
fp.write(_MAGIC)
|
fp.write(_MAGIC)
|
||||||
bmp = im.encoderinfo.get("bitmap_format", "") == "bmp"
|
bmp = im.encoderinfo.get("bitmap_format", "") == "bmp"
|
||||||
|
@ -138,13 +139,18 @@ class CurFile(IcoImagePlugin.IcoFile):
|
||||||
|
|
||||||
# TODO: This needs further investigation. Cursor files do not really specify their bpp
|
# TODO: This needs further investigation. Cursor files do not really specify their bpp
|
||||||
# like ICO's as those bits are used for the y_hotspot. For now, bpp is calculated by
|
# like ICO's as those bits are used for the y_hotspot. For now, bpp is calculated by
|
||||||
# subtracting the AND mask (equal to number of pixels * 1bpp) and dividing by the number
|
# subtracting the AND mask (equal to number of pixels * 1bpp) and dividing by the number
|
||||||
# of pixels. This seems to work well so far.
|
# of pixels. This seems to work well so far.
|
||||||
BITMAP_INFO_HEADER_SIZE = 40
|
BITMAP_INFO_HEADER_SIZE = 40
|
||||||
bpp_without_and = ((icon_header["size"] - BITMAP_INFO_HEADER_SIZE) * 8) // icon_header["square"]
|
bpp_without_and = (
|
||||||
|
(icon_header["size"] - BITMAP_INFO_HEADER_SIZE) * 8
|
||||||
|
) // icon_header["square"]
|
||||||
|
|
||||||
if bpp_without_and != 32:
|
if bpp_without_and != 32:
|
||||||
icon_header["bpp"] = ((icon_header["size"] - BITMAP_INFO_HEADER_SIZE) * 8 - icon_header["square"]) // icon_header["square"]
|
icon_header["bpp"] = (
|
||||||
|
(icon_header["size"] - BITMAP_INFO_HEADER_SIZE) * 8
|
||||||
|
- icon_header["square"]
|
||||||
|
) // icon_header["square"]
|
||||||
else:
|
else:
|
||||||
icon_header["bpp"] = bpp_without_and
|
icon_header["bpp"] = bpp_without_and
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user