diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 5801e1766..21033cc5d 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -685,6 +685,32 @@ class TestFileTiff: assert description[0]["format"] == "image/tiff" assert description[3]["BitsPerSample"]["Seq"]["li"] == ["8", "8", "8"] + def test_get_photoshop_blocks(self): + with Image.open("Tests/images/lab.tif") as im: + assert list(im.get_photoshop_blocks().keys()) == [ + 1061, + 1002, + 1005, + 1062, + 1037, + 1049, + 1011, + 1034, + 10000, + 1013, + 1016, + 1032, + 1054, + 1050, + 1064, + 1041, + 1044, + 1036, + 1057, + 4000, + 4001, + ] + def test_close_on_load_exclusive(self, tmp_path): # similar to test_fd_leak, but runs on unixlike os tmpfile = str(tmp_path / "temp.tif") diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index a3922d699..764739e90 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -41,6 +41,7 @@ import io import itertools import logging +import math import os import struct import warnings @@ -49,6 +50,8 @@ from fractions import Fraction from numbers import Number, Rational from . import Image, ImageFile, ImageOps, ImagePalette, TiffTags +from ._binary import i16be as i16 +from ._binary import i32be as i32 from ._binary import o8 from .TiffTags import TYPES @@ -1129,6 +1132,27 @@ class TiffImageFile(ImageFile.ImageFile): """ return self._getxmp(self.tag_v2[700]) if 700 in self.tag_v2 else {} + def get_photoshop_blocks(self): + """ + Returns a dictionary of Photoshop "Image Resource Blocks". + The keys are the image resource ID. For more information, see + https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_pgfId-1037727 + + :returns: Photoshop "Image Resource Blocks" in a dictionary. + """ + blocks = {} + val = self.tag_v2.get(0x8649) + if val: + while val[:4] == b"8BIM": + id = i16(val[4:6]) + n = math.ceil((val[6] + 1) / 2) * 2 + size = i32(val[6 + n : 10 + n]) + data = val[10 + n : 10 + n + size] + blocks[id] = {"data": data} + + val = val[math.ceil((10 + n + size) / 2) * 2 :] + return blocks + def load(self): if self.tile and self.use_load_libtiff: return self._load_libtiff()