Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/PIL/IptcImagePlugin.py: 13%
125 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1#
2# The Python Imaging Library.
3# $Id$
4#
5# IPTC/NAA file handling
6#
7# history:
8# 1995-10-01 fl Created
9# 1998-03-09 fl Cleaned up and added to PIL
10# 2002-06-18 fl Added getiptcinfo helper
11#
12# Copyright (c) Secret Labs AB 1997-2002.
13# Copyright (c) Fredrik Lundh 1995.
14#
15# See the README file for information on usage and redistribution.
16#
17import os
18import tempfile
20from . import Image, ImageFile
21from ._binary import i8
22from ._binary import i16be as i16
23from ._binary import i32be as i32
24from ._binary import o8
26COMPRESSION = {1: "raw", 5: "jpeg"}
28PAD = o8(0) * 4
31#
32# Helpers
35def i(c):
36 return i32((PAD + c)[-4:])
39def dump(c):
40 for i in c:
41 print("%02x" % i8(i), end=" ")
42 print()
45##
46# Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields
47# from TIFF and JPEG files, use the <b>getiptcinfo</b> function.
50class IptcImageFile(ImageFile.ImageFile):
52 format = "IPTC"
53 format_description = "IPTC/NAA"
55 def getint(self, key):
56 return i(self.info[key])
58 def field(self):
59 #
60 # get a IPTC field header
61 s = self.fp.read(5)
62 if not len(s):
63 return None, 0
65 tag = s[1], s[2]
67 # syntax
68 if s[0] != 0x1C or tag[0] < 1 or tag[0] > 9:
69 raise SyntaxError("invalid IPTC/NAA file")
71 # field size
72 size = s[3]
73 if size > 132:
74 raise OSError("illegal field length in IPTC/NAA file")
75 elif size == 128:
76 size = 0
77 elif size > 128:
78 size = i(self.fp.read(size - 128))
79 else:
80 size = i16(s, 3)
82 return tag, size
84 def _open(self):
86 # load descriptive fields
87 while True:
88 offset = self.fp.tell()
89 tag, size = self.field()
90 if not tag or tag == (8, 10):
91 break
92 if size:
93 tagdata = self.fp.read(size)
94 else:
95 tagdata = None
96 if tag in self.info:
97 if isinstance(self.info[tag], list):
98 self.info[tag].append(tagdata)
99 else:
100 self.info[tag] = [self.info[tag], tagdata]
101 else:
102 self.info[tag] = tagdata
104 # mode
105 layers = i8(self.info[(3, 60)][0])
106 component = i8(self.info[(3, 60)][1])
107 if (3, 65) in self.info:
108 id = i8(self.info[(3, 65)][0]) - 1
109 else:
110 id = 0
111 if layers == 1 and not component:
112 self.mode = "L"
113 elif layers == 3 and component:
114 self.mode = "RGB"[id]
115 elif layers == 4 and component:
116 self.mode = "CMYK"[id]
118 # size
119 self._size = self.getint((3, 20)), self.getint((3, 30))
121 # compression
122 try:
123 compression = COMPRESSION[self.getint((3, 120))]
124 except KeyError as e:
125 raise OSError("Unknown IPTC image compression") from e
127 # tile
128 if tag == (8, 10):
129 self.tile = [
130 ("iptc", (compression, offset), (0, 0, self.size[0], self.size[1]))
131 ]
133 def load(self):
135 if len(self.tile) != 1 or self.tile[0][0] != "iptc":
136 return ImageFile.ImageFile.load(self)
138 type, tile, box = self.tile[0]
140 encoding, offset = tile
142 self.fp.seek(offset)
144 # Copy image data to temporary file
145 o_fd, outfile = tempfile.mkstemp(text=False)
146 o = os.fdopen(o_fd)
147 if encoding == "raw":
148 # To simplify access to the extracted file,
149 # prepend a PPM header
150 o.write("P5\n%d %d\n255\n" % self.size)
151 while True:
152 type, size = self.field()
153 if type != (8, 10):
154 break
155 while size > 0:
156 s = self.fp.read(min(size, 8192))
157 if not s:
158 break
159 o.write(s)
160 size -= len(s)
161 o.close()
163 try:
164 with Image.open(outfile) as _im:
165 _im.load()
166 self.im = _im.im
167 finally:
168 try:
169 os.unlink(outfile)
170 except OSError:
171 pass
174Image.register_open(IptcImageFile.format, IptcImageFile)
176Image.register_extension(IptcImageFile.format, ".iim")
179def getiptcinfo(im):
180 """
181 Get IPTC information from TIFF, JPEG, or IPTC file.
183 :param im: An image containing IPTC data.
184 :returns: A dictionary containing IPTC information, or None if
185 no IPTC information block was found.
186 """
187 import io
189 from . import JpegImagePlugin, TiffImagePlugin
191 data = None
193 if isinstance(im, IptcImageFile):
194 # return info dictionary right away
195 return im.info
197 elif isinstance(im, JpegImagePlugin.JpegImageFile):
198 # extract the IPTC/NAA resource
199 photoshop = im.info.get("photoshop")
200 if photoshop:
201 data = photoshop.get(0x0404)
203 elif isinstance(im, TiffImagePlugin.TiffImageFile):
204 # get raw data from the IPTC/NAA tag (PhotoShop tags the data
205 # as 4-byte integers, so we cannot use the get method...)
206 try:
207 data = im.tag.tagdata[TiffImagePlugin.IPTC_NAA_CHUNK]
208 except (AttributeError, KeyError):
209 pass
211 if data is None:
212 return None # no properties
214 # create an IptcImagePlugin object without initializing it
215 class FakeImage:
216 pass
218 im = FakeImage()
219 im.__class__ = IptcImageFile
221 # parse the IPTC information chunk
222 im.info = {}
223 im.fp = io.BytesIO(data)
225 try:
226 im._open()
227 except (IndexError, KeyError):
228 pass # expected failure
230 return im.info