mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-27 09:44:31 +03:00
Added ICO saving in BMP format
This commit is contained in:
parent
22e1fff754
commit
2c9a9b3529
|
@ -56,6 +56,35 @@ def test_save_to_bytes():
|
||||||
assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS))
|
assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("mode", ("1", "L", "P", "RGB", "RGBA"))
|
||||||
|
def test_save_to_bytes_bmp(mode):
|
||||||
|
output = io.BytesIO()
|
||||||
|
im = hopper(mode)
|
||||||
|
im.save(output, "ico", bitmap_format="bmp", sizes=[(32, 32), (64, 64)])
|
||||||
|
|
||||||
|
# The default image
|
||||||
|
output.seek(0)
|
||||||
|
with Image.open(output) as reloaded:
|
||||||
|
assert reloaded.info["sizes"] == {(32, 32), (64, 64)}
|
||||||
|
|
||||||
|
assert "RGBA" == reloaded.mode
|
||||||
|
assert (64, 64) == reloaded.size
|
||||||
|
assert reloaded.format == "ICO"
|
||||||
|
im = hopper(mode).resize((64, 64), Image.LANCZOS).convert("RGBA")
|
||||||
|
assert_image_equal(reloaded, im)
|
||||||
|
|
||||||
|
# The other one
|
||||||
|
output.seek(0)
|
||||||
|
with Image.open(output) as reloaded:
|
||||||
|
reloaded.size = (32, 32)
|
||||||
|
|
||||||
|
assert "RGBA" == reloaded.mode
|
||||||
|
assert (32, 32) == reloaded.size
|
||||||
|
assert reloaded.format == "ICO"
|
||||||
|
im = hopper(mode).resize((32, 32), Image.LANCZOS).convert("RGBA")
|
||||||
|
assert_image_equal(reloaded, im)
|
||||||
|
|
||||||
|
|
||||||
def test_incorrect_size():
|
def test_incorrect_size():
|
||||||
with Image.open(TEST_ICO_FILE) as im:
|
with Image.open(TEST_ICO_FILE) as im:
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
|
|
|
@ -247,6 +247,12 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum
|
||||||
|
|
||||||
.. versionadded:: 8.1.0
|
.. versionadded:: 8.1.0
|
||||||
|
|
||||||
|
**bitmap_format**
|
||||||
|
By default, the image data will be saved in PNG format. With a bitmap format of
|
||||||
|
"bmp", image data will be saved in BMP format instead.
|
||||||
|
|
||||||
|
.. versionadded:: 8.3.0
|
||||||
|
|
||||||
IM
|
IM
|
||||||
^^
|
^^
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ from math import ceil, log
|
||||||
from . import BmpImagePlugin, Image, ImageFile, PngImagePlugin
|
from . import BmpImagePlugin, Image, ImageFile, PngImagePlugin
|
||||||
from ._binary import i16le as i16
|
from ._binary import i16le as i16
|
||||||
from ._binary import i32le as i32
|
from ._binary import i32le as i32
|
||||||
|
from ._binary import o32le as o32
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
@ -53,6 +54,7 @@ def _save(im, fp, filename):
|
||||||
sizes = list(sizes)
|
sizes = list(sizes)
|
||||||
fp.write(struct.pack("<H", len(sizes))) # idCount(2)
|
fp.write(struct.pack("<H", len(sizes))) # idCount(2)
|
||||||
offset = fp.tell() + len(sizes) * 16
|
offset = fp.tell() + len(sizes) * 16
|
||||||
|
bmp = im.encoderinfo.get("bitmap_format") == "bmp"
|
||||||
provided_images = {im.size: im for im in im.encoderinfo.get("append_images", [])}
|
provided_images = {im.size: im for im in im.encoderinfo.get("append_images", [])}
|
||||||
for size in sizes:
|
for size in sizes:
|
||||||
width, height = size
|
width, height = size
|
||||||
|
@ -62,17 +64,30 @@ def _save(im, fp, filename):
|
||||||
fp.write(b"\0") # bColorCount(1)
|
fp.write(b"\0") # bColorCount(1)
|
||||||
fp.write(b"\0") # bReserved(1)
|
fp.write(b"\0") # bReserved(1)
|
||||||
fp.write(b"\0\0") # wPlanes(2)
|
fp.write(b"\0\0") # wPlanes(2)
|
||||||
fp.write(struct.pack("<H", 32)) # wBitCount(2)
|
|
||||||
|
|
||||||
image_io = BytesIO()
|
|
||||||
tmp = provided_images.get(size)
|
tmp = provided_images.get(size)
|
||||||
if not tmp:
|
if not tmp:
|
||||||
# TODO: invent a more convenient method for proportional scalings
|
# TODO: invent a more convenient method for proportional scalings
|
||||||
tmp = im.copy()
|
tmp = im.copy()
|
||||||
tmp.thumbnail(size, Image.LANCZOS, reducing_gap=None)
|
tmp.thumbnail(size, Image.LANCZOS, reducing_gap=None)
|
||||||
tmp.save(image_io, "png")
|
bits = BmpImagePlugin.SAVE[tmp.mode][1] if bmp else 32
|
||||||
|
fp.write(struct.pack("<H", bits)) # wBitCount(2)
|
||||||
|
|
||||||
|
image_io = BytesIO()
|
||||||
|
if bmp:
|
||||||
|
tmp.save(image_io, "dib")
|
||||||
|
|
||||||
|
if bits != 32:
|
||||||
|
and_mask = Image.new("1", tmp.size)
|
||||||
|
ImageFile._save(
|
||||||
|
and_mask, image_io, [("raw", (0, 0) + tmp.size, 0, ("1", 0, -1))]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
tmp.save(image_io, "png")
|
||||||
image_io.seek(0)
|
image_io.seek(0)
|
||||||
image_bytes = image_io.read()
|
image_bytes = image_io.read()
|
||||||
|
if bmp:
|
||||||
|
image_bytes = image_bytes[:8] + o32(height * 2) + image_bytes[12:]
|
||||||
bytes_len = len(image_bytes)
|
bytes_len = len(image_bytes)
|
||||||
fp.write(struct.pack("<I", bytes_len)) # dwBytesInRes(4)
|
fp.write(struct.pack("<I", bytes_len)) # dwBytesInRes(4)
|
||||||
fp.write(struct.pack("<I", offset)) # dwImageOffset(4)
|
fp.write(struct.pack("<I", offset)) # dwImageOffset(4)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user