IptcImagePlugin.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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. #
  17. import os
  18. import tempfile
  19. from . import Image, ImageFile
  20. from ._binary import i8
  21. from ._binary import i16be as i16
  22. from ._binary import i32be as i32
  23. from ._binary import o8
  24. COMPRESSION = {1: "raw", 5: "jpeg"}
  25. PAD = o8(0) * 4
  26. #
  27. # Helpers
  28. def i(c):
  29. return i32((PAD + c)[-4:])
  30. def dump(c):
  31. for i in c:
  32. print("%02x" % i8(i), end=" ")
  33. print()
  34. ##
  35. # Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields
  36. # from TIFF and JPEG files, use the <b>getiptcinfo</b> function.
  37. class IptcImageFile(ImageFile.ImageFile):
  38. format = "IPTC"
  39. format_description = "IPTC/NAA"
  40. def getint(self, key):
  41. return i(self.info[key])
  42. def field(self):
  43. #
  44. # get a IPTC field header
  45. s = self.fp.read(5)
  46. if not s.strip(b"\x00"):
  47. return None, 0
  48. tag = s[1], s[2]
  49. # syntax
  50. if s[0] != 0x1C or tag[0] not in [1, 2, 3, 4, 5, 6, 7, 8, 9, 240]:
  51. msg = "invalid IPTC/NAA file"
  52. raise SyntaxError(msg)
  53. # field size
  54. size = s[3]
  55. if size > 132:
  56. msg = "illegal field length in IPTC/NAA file"
  57. raise OSError(msg)
  58. elif size == 128:
  59. size = 0
  60. elif size > 128:
  61. size = i(self.fp.read(size - 128))
  62. else:
  63. size = i16(s, 3)
  64. return tag, size
  65. def _open(self):
  66. # load descriptive fields
  67. while True:
  68. offset = self.fp.tell()
  69. tag, size = self.field()
  70. if not tag or tag == (8, 10):
  71. break
  72. if size:
  73. tagdata = self.fp.read(size)
  74. else:
  75. tagdata = None
  76. if tag in self.info:
  77. if isinstance(self.info[tag], list):
  78. self.info[tag].append(tagdata)
  79. else:
  80. self.info[tag] = [self.info[tag], tagdata]
  81. else:
  82. self.info[tag] = tagdata
  83. # mode
  84. layers = i8(self.info[(3, 60)][0])
  85. component = i8(self.info[(3, 60)][1])
  86. if (3, 65) in self.info:
  87. id = i8(self.info[(3, 65)][0]) - 1
  88. else:
  89. id = 0
  90. if layers == 1 and not component:
  91. self._mode = "L"
  92. elif layers == 3 and component:
  93. self._mode = "RGB"[id]
  94. elif layers == 4 and component:
  95. self._mode = "CMYK"[id]
  96. # size
  97. self._size = self.getint((3, 20)), self.getint((3, 30))
  98. # compression
  99. try:
  100. compression = COMPRESSION[self.getint((3, 120))]
  101. except KeyError as e:
  102. msg = "Unknown IPTC image compression"
  103. raise OSError(msg) from e
  104. # tile
  105. if tag == (8, 10):
  106. self.tile = [
  107. ("iptc", (compression, offset), (0, 0, self.size[0], self.size[1]))
  108. ]
  109. def load(self):
  110. if len(self.tile) != 1 or self.tile[0][0] != "iptc":
  111. return ImageFile.ImageFile.load(self)
  112. type, tile, box = self.tile[0]
  113. encoding, offset = tile
  114. self.fp.seek(offset)
  115. # Copy image data to temporary file
  116. o_fd, outfile = tempfile.mkstemp(text=False)
  117. o = os.fdopen(o_fd)
  118. if encoding == "raw":
  119. # To simplify access to the extracted file,
  120. # prepend a PPM header
  121. o.write("P5\n%d %d\n255\n" % self.size)
  122. while True:
  123. type, size = self.field()
  124. if type != (8, 10):
  125. break
  126. while size > 0:
  127. s = self.fp.read(min(size, 8192))
  128. if not s:
  129. break
  130. o.write(s)
  131. size -= len(s)
  132. o.close()
  133. try:
  134. with Image.open(outfile) as _im:
  135. _im.load()
  136. self.im = _im.im
  137. finally:
  138. try:
  139. os.unlink(outfile)
  140. except OSError:
  141. pass
  142. Image.register_open(IptcImageFile.format, IptcImageFile)
  143. Image.register_extension(IptcImageFile.format, ".iim")
  144. def getiptcinfo(im):
  145. """
  146. Get IPTC information from TIFF, JPEG, or IPTC file.
  147. :param im: An image containing IPTC data.
  148. :returns: A dictionary containing IPTC information, or None if
  149. no IPTC information block was found.
  150. """
  151. import io
  152. from . import JpegImagePlugin, TiffImagePlugin
  153. data = None
  154. if isinstance(im, IptcImageFile):
  155. # return info dictionary right away
  156. return im.info
  157. elif isinstance(im, JpegImagePlugin.JpegImageFile):
  158. # extract the IPTC/NAA resource
  159. photoshop = im.info.get("photoshop")
  160. if photoshop:
  161. data = photoshop.get(0x0404)
  162. elif isinstance(im, TiffImagePlugin.TiffImageFile):
  163. # get raw data from the IPTC/NAA tag (PhotoShop tags the data
  164. # as 4-byte integers, so we cannot use the get method...)
  165. try:
  166. data = im.tag.tagdata[TiffImagePlugin.IPTC_NAA_CHUNK]
  167. except (AttributeError, KeyError):
  168. pass
  169. if data is None:
  170. return None # no properties
  171. # create an IptcImagePlugin object without initializing it
  172. class FakeImage:
  173. pass
  174. im = FakeImage()
  175. im.__class__ = IptcImageFile
  176. # parse the IPTC information chunk
  177. im.info = {}
  178. im.fp = io.BytesIO(data)
  179. try:
  180. im._open()
  181. except (IndexError, KeyError):
  182. pass # expected failure
  183. return im.info