Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Tests/images/drawing_roundDown.emf
Binary file not shown.
Binary file added Tests/images/hopper_roundDown.bmp
Binary file not shown.
Binary file added Tests/images/hopper_roundDown_2.tif
Binary file not shown.
Binary file added Tests/images/hopper_roundDown_3.tif
Binary file not shown.
Binary file added Tests/images/hopper_roundDown_None.tif
Binary file not shown.
Binary file added Tests/images/hopper_roundUp_2.tif
Binary file not shown.
Binary file added Tests/images/hopper_roundUp_3.tif
Binary file not shown.
Binary file added Tests/images/hopper_roundUp_None.tif
Binary file not shown.
Binary file added Tests/images/iptc_roundDown.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/iptc_roundUp.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions Tests/test_file_bmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,27 @@ def test_save_bmp_with_dpi(self):
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')
Expand Down
21 changes: 21 additions & 0 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,27 @@ def test_save_tiff_with_dpi(self):
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
Expand Down
18 changes: 18 additions & 0 deletions Tests/test_file_png.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,24 @@ def test_roundtrip_dpi(self):
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

Expand Down
24 changes: 24 additions & 0 deletions Tests/test_file_tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,30 @@ def test_int_resolution(self):
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(
Expand Down
9 changes: 9 additions & 0 deletions Tests/test_file_wmf.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ def save(self, im, fp, filename):
# 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()

Expand Down
6 changes: 2 additions & 4 deletions src/PIL/BmpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -121,8 +120,7 @@ def _bitmap(self, header=0, offset=0):
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',
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/JpegImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions src/PIL/TiffImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1260,11 +1260,11 @@ def _setup(self):
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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/WmfImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ def _open(self):
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

Expand Down