Merge pull request #745 from gcq/master

Handle resolution in BMP files
This commit is contained in:
wiredfool 2014-06-29 13:32:02 -07:00
commit 118a2d5ff0
2 changed files with 38 additions and 15 deletions

View File

@ -28,6 +28,7 @@ __version__ = "0.7"
from PIL import Image, ImageFile, ImagePalette, _binary
import math
i8 = _binary.i8
i16 = _binary.i16le
@ -88,6 +89,7 @@ class BmpImageFile(ImageFile.ImageFile):
bits = i16(s[14:])
self.size = i32(s[4:]), i32(s[8:])
compression = i32(s[16:])
pxperm = (i32(s[24:]), i32(s[28:])) # Pixels per meter
lutsize = 4
colors = i32(s[32:])
direction = -1
@ -95,6 +97,8 @@ class BmpImageFile(ImageFile.ImageFile):
# upside-down storage
self.size = self.size[0], 2**32 - self.size[1]
direction = 0
self.info["dpi"] = tuple(map(lambda x: math.ceil(x / 39.3701), pxperm))
else:
raise IOError("Unsupported BMP header type (%d)" % len(s))
@ -203,30 +207,37 @@ def _save(im, fp, filename, check=0):
if check:
return check
info = im.encoderinfo
dpi = info.get("dpi", (96, 96))
# 1 meter == 39.3701 inches
ppm = tuple(map(lambda x: int(x * 39.3701), dpi))
stride = ((im.size[0]*bits+7)//8+3)&(~3)
header = 40 # or 64 for OS/2 version 2
offset = 14 + header + colors * 4
image = stride * im.size[1]
# bitmap header
fp.write(b"BM" + # file type (magic)
o32(offset+image) + # file size
o32(0) + # reserved
o32(offset)) # image data offset
fp.write(b"BM" + # file type (magic)
o32(offset+image) + # file size
o32(0) + # reserved
o32(offset)) # image data offset
# bitmap info header
fp.write(o32(header) + # info header size
o32(im.size[0]) + # width
o32(im.size[1]) + # height
o16(1) + # planes
o16(bits) + # depth
o32(0) + # compression (0=uncompressed)
o32(image) + # size of bitmap
o32(1) + o32(1) + # resolution
o32(colors) + # colors used
o32(colors)) # colors important
fp.write(o32(header) + # info header size
o32(im.size[0]) + # width
o32(im.size[1]) + # height
o16(1) + # planes
o16(bits) + # depth
o32(0) + # compression (0=uncompressed)
o32(image) + # size of bitmap
o32(ppm[0]) + o32(ppm[1]) + # resolution
o32(colors) + # colors used
o32(colors)) # colors important
fp.write(b"\0" * (header - 40)) # padding (for OS/2 format)
fp.write(b"\0" * (header - 40)) # padding (for OS/2 format)
if im.mode == "1":
for i in (0, 255):

View File

@ -37,6 +37,18 @@ class TestFileBmp(PillowTestCase):
self.assertEqual(im.size, reloaded.size)
self.assertEqual(reloaded.format, "BMP")
def test_dpi(self):
dpi = (72, 72)
output = io.BytesIO()
im = lena()
im.save(output, "BMP", dpi=dpi)
output.seek(0)
reloaded = Image.open(output)
self.assertEqual(reloaded.info["dpi"], dpi)
if __name__ == '__main__':
unittest.main()