mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 09:26:16 +03:00
Consistent DPI rounding
This commit is contained in:
parent
2adfea9b4e
commit
c96cdb5e77
BIN
Tests/images/drawing_roundDown.emf
Normal file
BIN
Tests/images/drawing_roundDown.emf
Normal file
Binary file not shown.
BIN
Tests/images/hopper_roundDown.bmp
Normal file
BIN
Tests/images/hopper_roundDown.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
BIN
Tests/images/hopper_roundDown_2.tif
Normal file
BIN
Tests/images/hopper_roundDown_2.tif
Normal file
Binary file not shown.
BIN
Tests/images/hopper_roundDown_3.tif
Normal file
BIN
Tests/images/hopper_roundDown_3.tif
Normal file
Binary file not shown.
BIN
Tests/images/hopper_roundDown_None.tif
Normal file
BIN
Tests/images/hopper_roundDown_None.tif
Normal file
Binary file not shown.
BIN
Tests/images/hopper_roundUp_2.tif
Normal file
BIN
Tests/images/hopper_roundUp_2.tif
Normal file
Binary file not shown.
BIN
Tests/images/hopper_roundUp_3.tif
Normal file
BIN
Tests/images/hopper_roundUp_3.tif
Normal file
Binary file not shown.
BIN
Tests/images/hopper_roundUp_None.tif
Normal file
BIN
Tests/images/hopper_roundUp_None.tif
Normal file
Binary file not shown.
BIN
Tests/images/iptc_roundDown.jpg
Normal file
BIN
Tests/images/iptc_roundDown.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
Tests/images/iptc_roundUp.jpg
Normal file
BIN
Tests/images/iptc_roundUp.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -71,6 +71,27 @@ class TestFileBmp(PillowTestCase):
|
|||
self.assertEqual(im.size, reloaded.size)
|
||||
self.assertEqual(reloaded.format, "JPEG")
|
||||
|
||||
def test_load_dpi_rounding(self):
|
||||
# Round up
|
||||
im = Image.open('Tests/images/hopper.bmp')
|
||||
self.assertEqual(im.info["dpi"], (96, 96))
|
||||
|
||||
# Round down
|
||||
im = Image.open('Tests/images/hopper_roundDown.bmp')
|
||||
self.assertEqual(im.info["dpi"], (72, 72))
|
||||
|
||||
def test_save_dpi_rounding(self):
|
||||
outfile = self.tempfile("temp.bmp")
|
||||
im = Image.open('Tests/images/hopper.bmp')
|
||||
|
||||
im.save(outfile, dpi=(72.2, 72.2))
|
||||
reloaded = Image.open(outfile)
|
||||
self.assertEqual(reloaded.info["dpi"], (72, 72))
|
||||
|
||||
im.save(outfile, dpi=(72.8, 72.8))
|
||||
reloaded = Image.open(outfile)
|
||||
self.assertEqual(reloaded.info["dpi"], (73, 73))
|
||||
|
||||
def test_load_dib(self):
|
||||
# test for #1293, Imagegrab returning Unsupported Bitfields Format
|
||||
im = Image.open('Tests/images/clipboard.dib')
|
||||
|
|
|
@ -524,6 +524,27 @@ class TestFileJpeg(PillowTestCase):
|
|||
reloaded.load()
|
||||
self.assertEqual(im.info['dpi'], reloaded.info['dpi'])
|
||||
|
||||
def test_load_dpi_rounding(self):
|
||||
# Round up
|
||||
im = Image.open('Tests/images/iptc_roundUp.jpg')
|
||||
self.assertEqual(im.info["dpi"], (44, 44))
|
||||
|
||||
# Round down
|
||||
im = Image.open('Tests/images/iptc_roundDown.jpg')
|
||||
self.assertEqual(im.info["dpi"], (2, 2))
|
||||
|
||||
def test_save_dpi_rounding(self):
|
||||
outfile = self.tempfile("temp.jpg")
|
||||
im = Image.open('Tests/images/hopper.jpg')
|
||||
|
||||
im.save(outfile, dpi=(72.2, 72.2))
|
||||
reloaded = Image.open(outfile)
|
||||
self.assertEqual(reloaded.info["dpi"], (72, 72))
|
||||
|
||||
im.save(outfile, dpi=(72.8, 72.8))
|
||||
reloaded = Image.open(outfile)
|
||||
self.assertEqual(reloaded.info["dpi"], (73, 73))
|
||||
|
||||
def test_dpi_tuple_from_exif(self):
|
||||
# Arrange
|
||||
# This Photoshop CC 2017 image has DPI in EXIF not metadata
|
||||
|
|
|
@ -389,6 +389,24 @@ class TestFilePng(PillowTestCase):
|
|||
im = roundtrip(im, dpi=(100, 100))
|
||||
self.assertEqual(im.info["dpi"], (100, 100))
|
||||
|
||||
def test_load_dpi_rounding(self):
|
||||
# Round up
|
||||
im = Image.open(TEST_PNG_FILE)
|
||||
self.assertEqual(im.info["dpi"], (96, 96))
|
||||
|
||||
# Round down
|
||||
im = Image.open("Tests/images/icc_profile_none.png")
|
||||
self.assertEqual(im.info["dpi"], (72, 72))
|
||||
|
||||
def test_save_dpi_rounding(self):
|
||||
im = Image.open(TEST_PNG_FILE)
|
||||
|
||||
im = roundtrip(im, dpi=(72.2, 72.2))
|
||||
self.assertEqual(im.info["dpi"], (72, 72))
|
||||
|
||||
im = roundtrip(im, dpi=(72.8, 72.8))
|
||||
self.assertEqual(im.info["dpi"], (73, 73))
|
||||
|
||||
def test_roundtrip_text(self):
|
||||
# Check text roundtripping
|
||||
|
||||
|
|
|
@ -126,6 +126,30 @@ class TestFileTiff(PillowTestCase):
|
|||
im._setup()
|
||||
self.assertEqual(im.info['dpi'], (71., 71.))
|
||||
|
||||
def test_load_dpi_rounding(self):
|
||||
for resolutionUnit, dpi in ((None, (72, 73)),
|
||||
(2, (72, 73)),
|
||||
(3, (183, 185))):
|
||||
im = Image.open(
|
||||
"Tests/images/hopper_roundDown_"+str(resolutionUnit)+".tif")
|
||||
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
|
||||
self.assertEqual(im.info['dpi'], (dpi[0], dpi[0]))
|
||||
|
||||
im = Image.open("Tests/images/hopper_roundUp_"+str(resolutionUnit)+".tif")
|
||||
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
|
||||
self.assertEqual(im.info['dpi'], (dpi[1], dpi[1]))
|
||||
|
||||
def test_save_dpi_rounding(self):
|
||||
outfile = self.tempfile("temp.tif")
|
||||
im = Image.open("Tests/images/hopper.tif")
|
||||
|
||||
for dpi in (72.2, 72.8):
|
||||
im.save(outfile, dpi=(dpi, dpi))
|
||||
|
||||
reloaded = Image.open(outfile)
|
||||
reloaded.load()
|
||||
self.assertEqual((round(dpi), round(dpi)), reloaded.info['dpi'])
|
||||
|
||||
def test_save_setting_missing_resolution(self):
|
||||
b = BytesIO()
|
||||
Image.open("Tests/images/10ct_32bit_128.tiff").save(
|
||||
|
|
|
@ -45,6 +45,15 @@ class TestFileWmf(PillowTestCase):
|
|||
# Restore the state before this test
|
||||
WmfImagePlugin.register_handler(None)
|
||||
|
||||
def test_load_dpi_rounding(self):
|
||||
# Round up
|
||||
im = Image.open('Tests/images/drawing.emf')
|
||||
self.assertEqual(im.info["dpi"], 1424)
|
||||
|
||||
# Round down
|
||||
im = Image.open('Tests/images/drawing_roundDown.emf')
|
||||
self.assertEqual(im.info["dpi"], 1426)
|
||||
|
||||
def test_save(self):
|
||||
im = hopper()
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import i8, i16le as i16, i32le as i32, \
|
||||
o8, o16le as o16, o32le as o32
|
||||
import math
|
||||
|
||||
# __version__ is deprecated and will be removed in a future version. Use
|
||||
# PIL.__version__ instead.
|
||||
|
@ -121,8 +120,7 @@ class BmpImageFile(ImageFile.ImageFile):
|
|||
file_info['colors'] = i32(header_data[28:32])
|
||||
file_info['palette_padding'] = 4
|
||||
self.info["dpi"] = tuple(
|
||||
map(lambda x: int(math.ceil(x / 39.3701)),
|
||||
file_info['pixels_per_meter']))
|
||||
int(x / 39.3701 + 0.5) for x in file_info['pixels_per_meter'])
|
||||
if file_info['compression'] == self.BITFIELDS:
|
||||
if len(header_data) >= 52:
|
||||
for idx, mask in enumerate(['r_mask',
|
||||
|
@ -311,7 +309,7 @@ def _save(im, fp, filename, bitmap_header=True):
|
|||
dpi = info.get("dpi", (96, 96))
|
||||
|
||||
# 1 meter == 39.3701 inches
|
||||
ppm = tuple(map(lambda x: int(x * 39.3701), dpi))
|
||||
ppm = tuple(map(lambda x: int(x * 39.3701 + 0.5), dpi))
|
||||
|
||||
stride = ((im.size[0]*bits+7)//8+3) & (~3)
|
||||
header = 40 # or 64 for OS/2 version 2
|
||||
|
|
|
@ -160,13 +160,13 @@ def APP(self, marker):
|
|||
resolution_unit = exif[0x0128]
|
||||
x_resolution = exif[0x011A]
|
||||
try:
|
||||
dpi = x_resolution[0] / x_resolution[1]
|
||||
dpi = float(x_resolution[0]) / x_resolution[1]
|
||||
except TypeError:
|
||||
dpi = x_resolution
|
||||
if resolution_unit == 3: # cm
|
||||
# 1 dpcm = 2.54 dpi
|
||||
dpi *= 2.54
|
||||
self.info["dpi"] = dpi, dpi
|
||||
self.info["dpi"] = int(dpi + 0.5), int(dpi + 0.5)
|
||||
except (KeyError, SyntaxError, ZeroDivisionError):
|
||||
# SyntaxError for invalid/unreadable exif
|
||||
# KeyError for dpi not included
|
||||
|
|
|
@ -1260,11 +1260,11 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
if xres and yres:
|
||||
resunit = self.tag_v2.get(RESOLUTION_UNIT)
|
||||
if resunit == 2: # dots per inch
|
||||
self.info["dpi"] = xres, yres
|
||||
self.info["dpi"] = int(xres + 0.5), int(yres + 0.5)
|
||||
elif resunit == 3: # dots per centimeter. convert to dpi
|
||||
self.info["dpi"] = xres * 2.54, yres * 2.54
|
||||
self.info["dpi"] = int(xres * 2.54 + 0.5), int(yres * 2.54 + 0.5)
|
||||
elif resunit is None: # used to default to 1, but now 2)
|
||||
self.info["dpi"] = xres, yres
|
||||
self.info["dpi"] = int(xres + 0.5), int(yres + 0.5)
|
||||
# For backward compatibility,
|
||||
# we also preserve the old behavior
|
||||
self.info["resolution"] = xres, yres
|
||||
|
@ -1475,8 +1475,8 @@ def _save(im, fp, filename):
|
|||
dpi = im.encoderinfo.get("dpi")
|
||||
if dpi:
|
||||
ifd[RESOLUTION_UNIT] = 2
|
||||
ifd[X_RESOLUTION] = dpi[0]
|
||||
ifd[Y_RESOLUTION] = dpi[1]
|
||||
ifd[X_RESOLUTION] = int(dpi[0] + 0.5)
|
||||
ifd[Y_RESOLUTION] = int(dpi[1] + 0.5)
|
||||
|
||||
if bits != (1,):
|
||||
ifd[BITSPERSAMPLE] = bits
|
||||
|
|
|
@ -131,8 +131,8 @@ class WmfStubImageFile(ImageFile.StubImageFile):
|
|||
size = x1 - x0, y1 - y0
|
||||
|
||||
# calculate dots per inch from bbox and frame
|
||||
xdpi = 2540 * (x1 - y0) // (frame[2] - frame[0])
|
||||
ydpi = 2540 * (y1 - y0) // (frame[3] - frame[1])
|
||||
xdpi = int(2540.0 * (x1 - y0) / (frame[2] - frame[0]) + 0.5)
|
||||
ydpi = int(2540.0 * (y1 - y0) / (frame[3] - frame[1]) + 0.5)
|
||||
|
||||
self.info["wmf_bbox"] = x0, y0, x1, y1
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user