Read Photoshop resolution data

This commit is contained in:
Andrew Murray 2019-03-06 10:28:45 +11:00
parent 975fccafc7
commit 636ad68f5e
3 changed files with 46 additions and 30 deletions

View File

@ -590,6 +590,15 @@ class TestFileJpeg(PillowTestCase):
# Act / Assert # Act / Assert
self.assertEqual(im._getexif()[306], '2017:03:13 23:03:09') self.assertEqual(im._getexif()[306], '2017:03:13 23:03:09')
def test_photoshop(self):
im = Image.open("Tests/images/photoshop-200dpi.jpg")
self.assertEqual(im.info["photoshop"][0x03ed], {
'XResolution': 200.0,
'DisplayedUnitsX': 1,
'YResolution': 200.0,
'DisplayedUnitsY': 1,
})
@unittest.skipUnless(sys.platform.startswith('win32'), "Windows only") @unittest.skipUnless(sys.platform.startswith('win32'), "Windows only")
class TestFileCloseW32(PillowTestCase): class TestFileCloseW32(PillowTestCase):

View File

@ -198,35 +198,9 @@ def getiptcinfo(im):
elif isinstance(im, JpegImagePlugin.JpegImageFile): elif isinstance(im, JpegImagePlugin.JpegImageFile):
# extract the IPTC/NAA resource # extract the IPTC/NAA resource
try: photoshop = im.info.get("photoshop")
app = im.app["APP13"] if photoshop:
if app[:14] == b"Photoshop 3.0\x00": data = photoshop.get(0x0404)
app = app[14:]
# parse the image resource block
offset = 0
while app[offset:offset+4] == b"8BIM":
offset += 4
# resource code
code = i16(app, offset)
offset += 2
# resource name (usually empty)
name_len = i8(app[offset])
# name = app[offset+1:offset+1+name_len]
offset = 1 + offset + name_len
if offset & 1:
offset += 1
# resource data block
size = i32(app, offset)
offset += 4
if code == 0x0404:
# 0x0404 contains IPTC/NAA data
data = app[offset:offset+size]
break
offset = offset + size
if offset & 1:
offset += 1
except (AttributeError, KeyError):
pass
elif isinstance(im, TiffImagePlugin.TiffImageFile): elif isinstance(im, TiffImagePlugin.TiffImageFile):
# get raw data from the IPTC/NAA tag (PhotoShop tags the data # get raw data from the IPTC/NAA tag (PhotoShop tags the data

View File

@ -39,7 +39,7 @@ import struct
import io import io
import warnings import warnings
from . import Image, ImageFile, TiffImagePlugin from . import Image, ImageFile, TiffImagePlugin
from ._binary import i8, o8, i16be as i16 from ._binary import i8, o8, i16be as i16, i32be as i32
from .JpegPresets import presets from .JpegPresets import presets
from ._util import isStringType from ._util import isStringType
@ -104,6 +104,39 @@ def APP(self, marker):
# reassemble the profile, rather than assuming that the APP2 # reassemble the profile, rather than assuming that the APP2
# markers appear in the correct sequence. # markers appear in the correct sequence.
self.icclist.append(s) self.icclist.append(s)
elif marker == 0xFFED:
if s[:14] == b"Photoshop 3.0\x00":
blocks = s[14:]
# parse the image resource block
offset = 0
photoshop = {}
while blocks[offset:offset+4] == b"8BIM":
offset += 4
# resource code
code = i16(blocks, offset)
offset += 2
# resource name (usually empty)
name_len = i8(blocks[offset])
# name = blocks[offset+1:offset+1+name_len]
offset = 1 + offset + name_len
if offset & 1:
offset += 1
# resource data block
size = i32(blocks, offset)
offset += 4
data = blocks[offset:offset+size]
if code == 0x03ED: # ResolutionInfo
data = {
'XResolution': i32(data[:4]) / 65536,
'DisplayedUnitsX': i16(data[4:8]),
'YResolution': i32(data[8:12]) / 65536,
'DisplayedUnitsY': i16(data[12:]),
}
photoshop[code] = data
offset = offset + size
if offset & 1:
offset += 1
self.info["photoshop"] = photoshop
elif marker == 0xFFEE and s[:5] == b"Adobe": elif marker == 0xFFEE and s[:5] == b"Adobe":
self.info["adobe"] = i16(s, 5) self.info["adobe"] = i16(s, 5)
# extract Adobe custom properties # extract Adobe custom properties