Skip to content

Commit

Permalink
Merge pull request #4370 from uploadcare/jpeg-multiple-app13
Browse files Browse the repository at this point in the history
Handle multiple and malformed JPEG APP13 markers
  • Loading branch information
homm committed Jan 27, 2020
2 parents 0bbee69 + fd03a68 commit 5965437
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 22 deletions.
Binary file added Tests/images/app13-multiple.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions Tests/test_file_jpeg.py
Expand Up @@ -676,6 +676,13 @@ def test_photoshop(self):
with Image.open("Tests/images/app13.jpg") as im:
self.assertNotIn("photoshop", im.info)

def test_photoshop_malformed_and_multiple(self):
with Image.open("Tests/images/app13-multiple.jpg") as im:
self.assertIn("photoshop", im.info)
self.assertEqual(24, len(im.info["photoshop"]))
apps_13_lengths = [len(v) for k, v in im.applist if k == "APP13"]
self.assertEqual([65504, 24], apps_13_lengths)


@unittest.skipUnless(is_win32(), "Windows only")
class TestFileCloseW32(PillowTestCase):
Expand Down
40 changes: 18 additions & 22 deletions src/PIL/JpegImagePlugin.py
Expand Up @@ -100,30 +100,25 @@ def APP(self, marker):
# reassemble the profile, rather than assuming that the APP2
# markers appear in the correct sequence.
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":
elif marker == 0xFFED and s[:14] == b"Photoshop 3.0\x00":
# parse the image resource block
offset = 14
photoshop = self.info.setdefault("photoshop", {})
while s[offset : offset + 4] == b"8BIM":
try:
offset += 4
# resource code
try:
code = i16(blocks, offset)
except struct.error:
break
code = i16(s, 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
name_len = i8(s[offset])
# name = s[offset+1:offset+1+name_len]
offset += 1 + name_len
offset += offset & 1 # align
# resource data block
size = i32(blocks, offset)
size = i32(s, offset)
offset += 4
data = blocks[offset : offset + size]
data = s[offset : offset + size]
if code == 0x03ED: # ResolutionInfo
data = {
"XResolution": i32(data[:4]) / 65536,
Expand All @@ -132,10 +127,11 @@ def APP(self, marker):
"DisplayedUnitsY": i16(data[12:]),
}
photoshop[code] = data
offset = offset + size
if offset & 1:
offset += 1
self.info["photoshop"] = photoshop
offset += size
offset += offset & 1 # align
except struct.error:
break # insufficient data

elif marker == 0xFFEE and s[:5] == b"Adobe":
self.info["adobe"] = i16(s, 5)
# extract Adobe custom properties
Expand Down

0 comments on commit 5965437

Please sign in to comment.