TiffImagePlugin.py 83 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338
  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # TIFF file handling
  6. #
  7. # TIFF is a flexible, if somewhat aged, image file format originally
  8. # defined by Aldus. Although TIFF supports a wide variety of pixel
  9. # layouts and compression methods, the name doesn't really stand for
  10. # "thousands of incompatible file formats," it just feels that way.
  11. #
  12. # To read TIFF data from a stream, the stream must be seekable. For
  13. # progressive decoding, make sure to use TIFF files where the tag
  14. # directory is placed first in the file.
  15. #
  16. # History:
  17. # 1995-09-01 fl Created
  18. # 1996-05-04 fl Handle JPEGTABLES tag
  19. # 1996-05-18 fl Fixed COLORMAP support
  20. # 1997-01-05 fl Fixed PREDICTOR support
  21. # 1997-08-27 fl Added support for rational tags (from Perry Stoll)
  22. # 1998-01-10 fl Fixed seek/tell (from Jan Blom)
  23. # 1998-07-15 fl Use private names for internal variables
  24. # 1999-06-13 fl Rewritten for PIL 1.0 (1.0)
  25. # 2000-10-11 fl Additional fixes for Python 2.0 (1.1)
  26. # 2001-04-17 fl Fixed rewind support (seek to frame 0) (1.2)
  27. # 2001-05-12 fl Added write support for more tags (from Greg Couch) (1.3)
  28. # 2001-12-18 fl Added workaround for broken Matrox library
  29. # 2002-01-18 fl Don't mess up if photometric tag is missing (D. Alan Stewart)
  30. # 2003-05-19 fl Check FILLORDER tag
  31. # 2003-09-26 fl Added RGBa support
  32. # 2004-02-24 fl Added DPI support; fixed rational write support
  33. # 2005-02-07 fl Added workaround for broken Corel Draw 10 files
  34. # 2006-01-09 fl Added support for float/double tags (from Russell Nelson)
  35. #
  36. # Copyright (c) 1997-2006 by Secret Labs AB. All rights reserved.
  37. # Copyright (c) 1995-1997 by Fredrik Lundh
  38. #
  39. # See the README file for information on usage and redistribution.
  40. #
  41. from __future__ import annotations
  42. import io
  43. import itertools
  44. import logging
  45. import math
  46. import os
  47. import struct
  48. import warnings
  49. from collections.abc import Callable, MutableMapping
  50. from fractions import Fraction
  51. from numbers import Number, Rational
  52. from typing import IO, Any, cast
  53. from . import ExifTags, Image, ImageFile, ImageOps, ImagePalette, TiffTags
  54. from ._binary import i16be as i16
  55. from ._binary import i32be as i32
  56. from ._binary import o8
  57. from ._util import DeferredError, is_path
  58. from .TiffTags import TYPES
  59. TYPE_CHECKING = False
  60. if TYPE_CHECKING:
  61. from collections.abc import Iterator
  62. from typing import NoReturn
  63. from ._typing import Buffer, IntegralLike, StrOrBytesPath
  64. logger = logging.getLogger(__name__)
  65. # Set these to true to force use of libtiff for reading or writing.
  66. READ_LIBTIFF = False
  67. WRITE_LIBTIFF = False
  68. STRIP_SIZE = 65536
  69. II = b"II" # little-endian (Intel style)
  70. MM = b"MM" # big-endian (Motorola style)
  71. #
  72. # --------------------------------------------------------------------
  73. # Read TIFF files
  74. # a few tag names, just to make the code below a bit more readable
  75. OSUBFILETYPE = 255
  76. IMAGEWIDTH = 256
  77. IMAGELENGTH = 257
  78. BITSPERSAMPLE = 258
  79. COMPRESSION = 259
  80. PHOTOMETRIC_INTERPRETATION = 262
  81. FILLORDER = 266
  82. IMAGEDESCRIPTION = 270
  83. STRIPOFFSETS = 273
  84. SAMPLESPERPIXEL = 277
  85. ROWSPERSTRIP = 278
  86. STRIPBYTECOUNTS = 279
  87. X_RESOLUTION = 282
  88. Y_RESOLUTION = 283
  89. PLANAR_CONFIGURATION = 284
  90. RESOLUTION_UNIT = 296
  91. TRANSFERFUNCTION = 301
  92. SOFTWARE = 305
  93. DATE_TIME = 306
  94. ARTIST = 315
  95. PREDICTOR = 317
  96. COLORMAP = 320
  97. TILEWIDTH = 322
  98. TILELENGTH = 323
  99. TILEOFFSETS = 324
  100. TILEBYTECOUNTS = 325
  101. SUBIFD = 330
  102. EXTRASAMPLES = 338
  103. SAMPLEFORMAT = 339
  104. JPEGTABLES = 347
  105. YCBCRSUBSAMPLING = 530
  106. REFERENCEBLACKWHITE = 532
  107. COPYRIGHT = 33432
  108. IPTC_NAA_CHUNK = 33723 # newsphoto properties
  109. PHOTOSHOP_CHUNK = 34377 # photoshop properties
  110. ICCPROFILE = 34675
  111. EXIFIFD = 34665
  112. XMP = 700
  113. JPEGQUALITY = 65537 # pseudo-tag by libtiff
  114. # https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/io/TiffDecoder.java
  115. IMAGEJ_META_DATA_BYTE_COUNTS = 50838
  116. IMAGEJ_META_DATA = 50839
  117. COMPRESSION_INFO = {
  118. # Compression => pil compression name
  119. 1: "raw",
  120. 2: "tiff_ccitt",
  121. 3: "group3",
  122. 4: "group4",
  123. 5: "tiff_lzw",
  124. 6: "tiff_jpeg", # obsolete
  125. 7: "jpeg",
  126. 8: "tiff_adobe_deflate",
  127. 32771: "tiff_raw_16", # 16-bit padding
  128. 32773: "packbits",
  129. 32809: "tiff_thunderscan",
  130. 32946: "tiff_deflate",
  131. 34676: "tiff_sgilog",
  132. 34677: "tiff_sgilog24",
  133. 34925: "lzma",
  134. 50000: "zstd",
  135. 50001: "webp",
  136. }
  137. COMPRESSION_INFO_REV = {v: k for k, v in COMPRESSION_INFO.items()}
  138. OPEN_INFO = {
  139. # (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
  140. # ExtraSamples) => mode, rawmode
  141. (II, 0, (1,), 1, (1,), ()): ("1", "1;I"),
  142. (MM, 0, (1,), 1, (1,), ()): ("1", "1;I"),
  143. (II, 0, (1,), 2, (1,), ()): ("1", "1;IR"),
  144. (MM, 0, (1,), 2, (1,), ()): ("1", "1;IR"),
  145. (II, 1, (1,), 1, (1,), ()): ("1", "1"),
  146. (MM, 1, (1,), 1, (1,), ()): ("1", "1"),
  147. (II, 1, (1,), 2, (1,), ()): ("1", "1;R"),
  148. (MM, 1, (1,), 2, (1,), ()): ("1", "1;R"),
  149. (II, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
  150. (MM, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
  151. (II, 0, (1,), 2, (2,), ()): ("L", "L;2IR"),
  152. (MM, 0, (1,), 2, (2,), ()): ("L", "L;2IR"),
  153. (II, 1, (1,), 1, (2,), ()): ("L", "L;2"),
  154. (MM, 1, (1,), 1, (2,), ()): ("L", "L;2"),
  155. (II, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
  156. (MM, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
  157. (II, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
  158. (MM, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
  159. (II, 0, (1,), 2, (4,), ()): ("L", "L;4IR"),
  160. (MM, 0, (1,), 2, (4,), ()): ("L", "L;4IR"),
  161. (II, 1, (1,), 1, (4,), ()): ("L", "L;4"),
  162. (MM, 1, (1,), 1, (4,), ()): ("L", "L;4"),
  163. (II, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
  164. (MM, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
  165. (II, 0, (1,), 1, (8,), ()): ("L", "L;I"),
  166. (MM, 0, (1,), 1, (8,), ()): ("L", "L;I"),
  167. (II, 0, (1,), 2, (8,), ()): ("L", "L;IR"),
  168. (MM, 0, (1,), 2, (8,), ()): ("L", "L;IR"),
  169. (II, 1, (1,), 1, (8,), ()): ("L", "L"),
  170. (MM, 1, (1,), 1, (8,), ()): ("L", "L"),
  171. (II, 1, (2,), 1, (8,), ()): ("L", "L"),
  172. (MM, 1, (2,), 1, (8,), ()): ("L", "L"),
  173. (II, 1, (1,), 2, (8,), ()): ("L", "L;R"),
  174. (MM, 1, (1,), 2, (8,), ()): ("L", "L;R"),
  175. (II, 1, (1,), 1, (12,), ()): ("I;16", "I;12"),
  176. (II, 0, (1,), 1, (16,), ()): ("I;16", "I;16"),
  177. (II, 1, (1,), 1, (16,), ()): ("I;16", "I;16"),
  178. (MM, 1, (1,), 1, (16,), ()): ("I;16B", "I;16B"),
  179. (II, 1, (1,), 2, (16,), ()): ("I;16", "I;16R"),
  180. (II, 1, (2,), 1, (16,), ()): ("I", "I;16S"),
  181. (MM, 1, (2,), 1, (16,), ()): ("I", "I;16BS"),
  182. (II, 0, (3,), 1, (32,), ()): ("F", "F;32F"),
  183. (MM, 0, (3,), 1, (32,), ()): ("F", "F;32BF"),
  184. (II, 1, (1,), 1, (32,), ()): ("I", "I;32N"),
  185. (II, 1, (2,), 1, (32,), ()): ("I", "I;32S"),
  186. (MM, 1, (2,), 1, (32,), ()): ("I", "I;32BS"),
  187. (II, 1, (3,), 1, (32,), ()): ("F", "F;32F"),
  188. (MM, 1, (3,), 1, (32,), ()): ("F", "F;32BF"),
  189. (II, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
  190. (MM, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
  191. (II, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
  192. (MM, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
  193. (II, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
  194. (MM, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
  195. (II, 2, (1,), 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples
  196. (MM, 2, (1,), 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples
  197. (II, 2, (1,), 1, (8, 8, 8, 8), (0,)): ("RGB", "RGBX"),
  198. (MM, 2, (1,), 1, (8, 8, 8, 8), (0,)): ("RGB", "RGBX"),
  199. (II, 2, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("RGB", "RGBXX"),
  200. (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("RGB", "RGBXX"),
  201. (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGB", "RGBXXX"),
  202. (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGB", "RGBXXX"),
  203. (II, 2, (1,), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"),
  204. (MM, 2, (1,), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"),
  205. (II, 2, (1,), 1, (8, 8, 8, 8, 8), (1, 0)): ("RGBA", "RGBaX"),
  206. (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (1, 0)): ("RGBA", "RGBaX"),
  207. (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (1, 0, 0)): ("RGBA", "RGBaXX"),
  208. (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (1, 0, 0)): ("RGBA", "RGBaXX"),
  209. (II, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
  210. (MM, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
  211. (II, 2, (1,), 1, (8, 8, 8, 8, 8), (2, 0)): ("RGBA", "RGBAX"),
  212. (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (2, 0)): ("RGBA", "RGBAX"),
  213. (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (2, 0, 0)): ("RGBA", "RGBAXX"),
  214. (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (2, 0, 0)): ("RGBA", "RGBAXX"),
  215. (II, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
  216. (MM, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
  217. (II, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16L"),
  218. (MM, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16B"),
  219. (II, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16L"),
  220. (MM, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16B"),
  221. (II, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGB", "RGBX;16L"),
  222. (MM, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGB", "RGBX;16B"),
  223. (II, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16L"),
  224. (MM, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16B"),
  225. (II, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16L"),
  226. (MM, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16B"),
  227. (II, 3, (1,), 1, (1,), ()): ("P", "P;1"),
  228. (MM, 3, (1,), 1, (1,), ()): ("P", "P;1"),
  229. (II, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
  230. (MM, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
  231. (II, 3, (1,), 1, (2,), ()): ("P", "P;2"),
  232. (MM, 3, (1,), 1, (2,), ()): ("P", "P;2"),
  233. (II, 3, (1,), 2, (2,), ()): ("P", "P;2R"),
  234. (MM, 3, (1,), 2, (2,), ()): ("P", "P;2R"),
  235. (II, 3, (1,), 1, (4,), ()): ("P", "P;4"),
  236. (MM, 3, (1,), 1, (4,), ()): ("P", "P;4"),
  237. (II, 3, (1,), 2, (4,), ()): ("P", "P;4R"),
  238. (MM, 3, (1,), 2, (4,), ()): ("P", "P;4R"),
  239. (II, 3, (1,), 1, (8,), ()): ("P", "P"),
  240. (MM, 3, (1,), 1, (8,), ()): ("P", "P"),
  241. (II, 3, (1,), 1, (8, 8), (0,)): ("P", "PX"),
  242. (MM, 3, (1,), 1, (8, 8), (0,)): ("P", "PX"),
  243. (II, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"),
  244. (MM, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"),
  245. (II, 3, (1,), 2, (8,), ()): ("P", "P;R"),
  246. (MM, 3, (1,), 2, (8,), ()): ("P", "P;R"),
  247. (II, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
  248. (MM, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
  249. (II, 5, (1,), 1, (8, 8, 8, 8, 8), (0,)): ("CMYK", "CMYKX"),
  250. (MM, 5, (1,), 1, (8, 8, 8, 8, 8), (0,)): ("CMYK", "CMYKX"),
  251. (II, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"),
  252. (MM, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"),
  253. (II, 5, (1,), 1, (16, 16, 16, 16), ()): ("CMYK", "CMYK;16L"),
  254. (MM, 5, (1,), 1, (16, 16, 16, 16), ()): ("CMYK", "CMYK;16B"),
  255. (II, 6, (1,), 1, (8,), ()): ("L", "L"),
  256. (MM, 6, (1,), 1, (8,), ()): ("L", "L"),
  257. # JPEG compressed images handled by LibTiff and auto-converted to RGBX
  258. # Minimal Baseline TIFF requires YCbCr images to have 3 SamplesPerPixel
  259. (II, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGBX"),
  260. (MM, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGBX"),
  261. (II, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
  262. (MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
  263. }
  264. MAX_SAMPLESPERPIXEL = max(len(key_tp[4]) for key_tp in OPEN_INFO)
  265. PREFIXES = [
  266. b"MM\x00\x2a", # Valid TIFF header with big-endian byte order
  267. b"II\x2a\x00", # Valid TIFF header with little-endian byte order
  268. b"MM\x2a\x00", # Invalid TIFF header, assume big-endian
  269. b"II\x00\x2a", # Invalid TIFF header, assume little-endian
  270. b"MM\x00\x2b", # BigTIFF with big-endian byte order
  271. b"II\x2b\x00", # BigTIFF with little-endian byte order
  272. ]
  273. def _accept(prefix: bytes) -> bool:
  274. return prefix.startswith(tuple(PREFIXES))
  275. def _limit_rational(
  276. val: float | Fraction | IFDRational, max_val: int
  277. ) -> tuple[IntegralLike, IntegralLike]:
  278. inv = abs(val) > 1
  279. n_d = IFDRational(1 / val if inv else val).limit_rational(max_val)
  280. return n_d[::-1] if inv else n_d
  281. def _limit_signed_rational(
  282. val: IFDRational, max_val: int, min_val: int
  283. ) -> tuple[IntegralLike, IntegralLike]:
  284. frac = Fraction(val)
  285. n_d: tuple[IntegralLike, IntegralLike] = frac.numerator, frac.denominator
  286. if min(float(i) for i in n_d) < min_val:
  287. n_d = _limit_rational(val, abs(min_val))
  288. n_d_float = tuple(float(i) for i in n_d)
  289. if max(n_d_float) > max_val:
  290. n_d = _limit_rational(n_d_float[0] / n_d_float[1], max_val)
  291. return n_d
  292. ##
  293. # Wrapper for TIFF IFDs.
  294. _load_dispatch = {}
  295. _write_dispatch = {}
  296. def _delegate(op: str) -> Any:
  297. def delegate(
  298. self: IFDRational, *args: tuple[float, ...]
  299. ) -> bool | float | Fraction:
  300. return getattr(self._val, op)(*args)
  301. return delegate
  302. class IFDRational(Rational):
  303. """Implements a rational class where 0/0 is a legal value to match
  304. the in the wild use of exif rationals.
  305. e.g., DigitalZoomRatio - 0.00/0.00 indicates that no digital zoom was used
  306. """
  307. """ If the denominator is 0, store this as a float('nan'), otherwise store
  308. as a fractions.Fraction(). Delegate as appropriate
  309. """
  310. __slots__ = ("_numerator", "_denominator", "_val")
  311. def __init__(
  312. self, value: float | Fraction | IFDRational, denominator: int = 1
  313. ) -> None:
  314. """
  315. :param value: either an integer numerator, a
  316. float/rational/other number, or an IFDRational
  317. :param denominator: Optional integer denominator
  318. """
  319. self._val: Fraction | float
  320. if isinstance(value, IFDRational):
  321. self._numerator = value.numerator
  322. self._denominator = value.denominator
  323. self._val = value._val
  324. return
  325. if isinstance(value, Fraction):
  326. self._numerator = value.numerator
  327. self._denominator = value.denominator
  328. else:
  329. if TYPE_CHECKING:
  330. self._numerator = cast(IntegralLike, value)
  331. else:
  332. self._numerator = value
  333. self._denominator = denominator
  334. if denominator == 0:
  335. self._val = float("nan")
  336. elif denominator == 1:
  337. self._val = Fraction(value)
  338. elif int(value) == value:
  339. self._val = Fraction(int(value), denominator)
  340. else:
  341. self._val = Fraction(value / denominator)
  342. @property
  343. def numerator(self) -> IntegralLike:
  344. return self._numerator
  345. @property
  346. def denominator(self) -> int:
  347. return self._denominator
  348. def limit_rational(self, max_denominator: int) -> tuple[IntegralLike, int]:
  349. """
  350. :param max_denominator: Integer, the maximum denominator value
  351. :returns: Tuple of (numerator, denominator)
  352. """
  353. if self.denominator == 0:
  354. return self.numerator, self.denominator
  355. assert isinstance(self._val, Fraction)
  356. f = self._val.limit_denominator(max_denominator)
  357. return f.numerator, f.denominator
  358. def __repr__(self) -> str:
  359. return str(float(self._val))
  360. def __hash__(self) -> int: # type: ignore[override]
  361. return self._val.__hash__()
  362. def __eq__(self, other: object) -> bool:
  363. val = self._val
  364. if isinstance(other, IFDRational):
  365. other = other._val
  366. if isinstance(other, float):
  367. val = float(val)
  368. return val == other
  369. def __getstate__(self) -> list[float | Fraction | IntegralLike]:
  370. return [self._val, self._numerator, self._denominator]
  371. def __setstate__(self, state: list[float | Fraction | IntegralLike]) -> None:
  372. IFDRational.__init__(self, 0)
  373. _val, _numerator, _denominator = state
  374. assert isinstance(_val, (float, Fraction))
  375. self._val = _val
  376. if TYPE_CHECKING:
  377. self._numerator = cast(IntegralLike, _numerator)
  378. else:
  379. self._numerator = _numerator
  380. assert isinstance(_denominator, int)
  381. self._denominator = _denominator
  382. """ a = ['add','radd', 'sub', 'rsub', 'mul', 'rmul',
  383. 'truediv', 'rtruediv', 'floordiv', 'rfloordiv',
  384. 'mod','rmod', 'pow','rpow', 'pos', 'neg',
  385. 'abs', 'trunc', 'lt', 'gt', 'le', 'ge', 'bool',
  386. 'ceil', 'floor', 'round']
  387. print("\n".join("__%s__ = _delegate('__%s__')" % (s,s) for s in a))
  388. """
  389. __add__ = _delegate("__add__")
  390. __radd__ = _delegate("__radd__")
  391. __sub__ = _delegate("__sub__")
  392. __rsub__ = _delegate("__rsub__")
  393. __mul__ = _delegate("__mul__")
  394. __rmul__ = _delegate("__rmul__")
  395. __truediv__ = _delegate("__truediv__")
  396. __rtruediv__ = _delegate("__rtruediv__")
  397. __floordiv__ = _delegate("__floordiv__")
  398. __rfloordiv__ = _delegate("__rfloordiv__")
  399. __mod__ = _delegate("__mod__")
  400. __rmod__ = _delegate("__rmod__")
  401. __pow__ = _delegate("__pow__")
  402. __rpow__ = _delegate("__rpow__")
  403. __pos__ = _delegate("__pos__")
  404. __neg__ = _delegate("__neg__")
  405. __abs__ = _delegate("__abs__")
  406. __trunc__ = _delegate("__trunc__")
  407. __lt__ = _delegate("__lt__")
  408. __gt__ = _delegate("__gt__")
  409. __le__ = _delegate("__le__")
  410. __ge__ = _delegate("__ge__")
  411. __bool__ = _delegate("__bool__")
  412. __ceil__ = _delegate("__ceil__")
  413. __floor__ = _delegate("__floor__")
  414. __round__ = _delegate("__round__")
  415. # Python >= 3.11
  416. if hasattr(Fraction, "__int__"):
  417. __int__ = _delegate("__int__")
  418. _LoaderFunc = Callable[["ImageFileDirectory_v2", bytes, bool], Any]
  419. def _register_loader(idx: int, size: int) -> Callable[[_LoaderFunc], _LoaderFunc]:
  420. def decorator(func: _LoaderFunc) -> _LoaderFunc:
  421. from .TiffTags import TYPES
  422. if func.__name__.startswith("load_"):
  423. TYPES[idx] = func.__name__[5:].replace("_", " ")
  424. _load_dispatch[idx] = size, func # noqa: F821
  425. return func
  426. return decorator
  427. def _register_writer(idx: int) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
  428. def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
  429. _write_dispatch[idx] = func # noqa: F821
  430. return func
  431. return decorator
  432. def _register_basic(idx_fmt_name: tuple[int, str, str]) -> None:
  433. from .TiffTags import TYPES
  434. idx, fmt, name = idx_fmt_name
  435. TYPES[idx] = name
  436. size = struct.calcsize(f"={fmt}")
  437. def basic_handler(
  438. self: ImageFileDirectory_v2, data: bytes, legacy_api: bool = True
  439. ) -> tuple[Any, ...]:
  440. return self._unpack(f"{len(data) // size}{fmt}", data)
  441. _load_dispatch[idx] = size, basic_handler # noqa: F821
  442. _write_dispatch[idx] = lambda self, *values: ( # noqa: F821
  443. b"".join(self._pack(fmt, value) for value in values)
  444. )
  445. if TYPE_CHECKING:
  446. _IFDv2Base = MutableMapping[int, Any]
  447. else:
  448. _IFDv2Base = MutableMapping
  449. class ImageFileDirectory_v2(_IFDv2Base):
  450. """This class represents a TIFF tag directory. To speed things up, we
  451. don't decode tags unless they're asked for.
  452. Exposes a dictionary interface of the tags in the directory::
  453. ifd = ImageFileDirectory_v2()
  454. ifd[key] = 'Some Data'
  455. ifd.tagtype[key] = TiffTags.ASCII
  456. print(ifd[key])
  457. 'Some Data'
  458. Individual values are returned as the strings or numbers, sequences are
  459. returned as tuples of the values.
  460. The tiff metadata type of each item is stored in a dictionary of
  461. tag types in
  462. :attr:`~PIL.TiffImagePlugin.ImageFileDirectory_v2.tagtype`. The types
  463. are read from a tiff file, guessed from the type added, or added
  464. manually.
  465. Data Structures:
  466. * ``self.tagtype = {}``
  467. * Key: numerical TIFF tag number
  468. * Value: integer corresponding to the data type from
  469. :py:data:`.TiffTags.TYPES`
  470. .. versionadded:: 3.0.0
  471. 'Internal' data structures:
  472. * ``self._tags_v2 = {}``
  473. * Key: numerical TIFF tag number
  474. * Value: decoded data, as tuple for multiple values
  475. * ``self._tagdata = {}``
  476. * Key: numerical TIFF tag number
  477. * Value: undecoded byte string from file
  478. * ``self._tags_v1 = {}``
  479. * Key: numerical TIFF tag number
  480. * Value: decoded data in the v1 format
  481. Tags will be found in the private attributes ``self._tagdata``, and in
  482. ``self._tags_v2`` once decoded.
  483. ``self.legacy_api`` is a value for internal use, and shouldn't be changed
  484. from outside code. In cooperation with
  485. :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`, if ``legacy_api``
  486. is true, then decoded tags will be populated into both ``_tags_v1`` and
  487. ``_tags_v2``. ``_tags_v2`` will be used if this IFD is used in the TIFF
  488. save routine. Tags should be read from ``_tags_v1`` if
  489. ``legacy_api == true``.
  490. """
  491. _load_dispatch: dict[int, tuple[int, _LoaderFunc]] = {}
  492. _write_dispatch: dict[int, Callable[..., Any]] = {}
  493. def __init__(
  494. self,
  495. ifh: bytes = b"II\x2a\x00\x00\x00\x00\x00",
  496. prefix: bytes | None = None,
  497. group: int | None = None,
  498. ) -> None:
  499. """Initialize an ImageFileDirectory.
  500. To construct an ImageFileDirectory from a real file, pass the 8-byte
  501. magic header to the constructor. To only set the endianness, pass it
  502. as the 'prefix' keyword argument.
  503. :param ifh: One of the accepted magic headers (cf. PREFIXES); also sets
  504. endianness.
  505. :param prefix: Override the endianness of the file.
  506. """
  507. if not _accept(ifh):
  508. msg = f"not a TIFF file (header {repr(ifh)} not valid)"
  509. raise SyntaxError(msg)
  510. self._prefix = prefix if prefix is not None else ifh[:2]
  511. if self._prefix == MM:
  512. self._endian = ">"
  513. elif self._prefix == II:
  514. self._endian = "<"
  515. else:
  516. msg = "not a TIFF IFD"
  517. raise SyntaxError(msg)
  518. self._bigtiff = ifh[2] == 43
  519. self.group = group
  520. self.tagtype: dict[int, int] = {}
  521. """ Dictionary of tag types """
  522. self.reset()
  523. self.next = (
  524. self._unpack("Q", ifh[8:])[0]
  525. if self._bigtiff
  526. else self._unpack("L", ifh[4:])[0]
  527. )
  528. self._legacy_api = False
  529. prefix = property(lambda self: self._prefix)
  530. offset = property(lambda self: self._offset)
  531. @property
  532. def legacy_api(self) -> bool:
  533. return self._legacy_api
  534. @legacy_api.setter
  535. def legacy_api(self, value: bool) -> NoReturn:
  536. msg = "Not allowing setting of legacy api"
  537. raise Exception(msg)
  538. def reset(self) -> None:
  539. self._tags_v1: dict[int, Any] = {} # will remain empty if legacy_api is false
  540. self._tags_v2: dict[int, Any] = {} # main tag storage
  541. self._tagdata: dict[int, bytes] = {}
  542. self.tagtype = {} # added 2008-06-05 by Florian Hoech
  543. self._next = None
  544. self._offset: int | None = None
  545. def __str__(self) -> str:
  546. return str(dict(self))
  547. def named(self) -> dict[str, Any]:
  548. """
  549. :returns: dict of name|key: value
  550. Returns the complete tag dictionary, with named tags where possible.
  551. """
  552. return {
  553. TiffTags.lookup(code, self.group).name: value
  554. for code, value in self.items()
  555. }
  556. def __len__(self) -> int:
  557. return len(set(self._tagdata) | set(self._tags_v2))
  558. def __getitem__(self, tag: int) -> Any:
  559. if tag not in self._tags_v2: # unpack on the fly
  560. data = self._tagdata[tag]
  561. typ = self.tagtype[tag]
  562. size, handler = self._load_dispatch[typ]
  563. self[tag] = handler(self, data, self.legacy_api) # check type
  564. val = self._tags_v2[tag]
  565. if self.legacy_api and not isinstance(val, (tuple, bytes)):
  566. val = (val,)
  567. return val
  568. def __contains__(self, tag: object) -> bool:
  569. return tag in self._tags_v2 or tag in self._tagdata
  570. def __setitem__(self, tag: int, value: Any) -> None:
  571. self._setitem(tag, value, self.legacy_api)
  572. def _setitem(self, tag: int, value: Any, legacy_api: bool) -> None:
  573. basetypes = (Number, bytes, str)
  574. info = TiffTags.lookup(tag, self.group)
  575. values = [value] if isinstance(value, basetypes) else value
  576. if tag not in self.tagtype:
  577. if info.type:
  578. self.tagtype[tag] = info.type
  579. else:
  580. self.tagtype[tag] = TiffTags.UNDEFINED
  581. if all(isinstance(v, IFDRational) for v in values):
  582. for v in values:
  583. assert isinstance(v, IFDRational)
  584. if v < 0:
  585. self.tagtype[tag] = TiffTags.SIGNED_RATIONAL
  586. break
  587. else:
  588. self.tagtype[tag] = TiffTags.RATIONAL
  589. elif all(isinstance(v, int) for v in values):
  590. short = True
  591. signed_short = True
  592. long = True
  593. for v in values:
  594. assert isinstance(v, int)
  595. if short and not (0 <= v < 2**16):
  596. short = False
  597. if signed_short and not (-(2**15) < v < 2**15):
  598. signed_short = False
  599. if long and v < 0:
  600. long = False
  601. if short:
  602. self.tagtype[tag] = TiffTags.SHORT
  603. elif signed_short:
  604. self.tagtype[tag] = TiffTags.SIGNED_SHORT
  605. elif long:
  606. self.tagtype[tag] = TiffTags.LONG
  607. else:
  608. self.tagtype[tag] = TiffTags.SIGNED_LONG
  609. elif all(isinstance(v, float) for v in values):
  610. self.tagtype[tag] = TiffTags.DOUBLE
  611. elif all(isinstance(v, str) for v in values):
  612. self.tagtype[tag] = TiffTags.ASCII
  613. elif all(isinstance(v, bytes) for v in values):
  614. self.tagtype[tag] = TiffTags.BYTE
  615. if self.tagtype[tag] == TiffTags.UNDEFINED:
  616. values = [
  617. v.encode("ascii", "replace") if isinstance(v, str) else v
  618. for v in values
  619. ]
  620. elif self.tagtype[tag] == TiffTags.RATIONAL:
  621. values = [float(v) if isinstance(v, int) else v for v in values]
  622. is_ifd = self.tagtype[tag] == TiffTags.LONG and isinstance(values, dict)
  623. if not is_ifd:
  624. values = tuple(
  625. info.cvt_enum(value) if isinstance(value, str) else value
  626. for value in values
  627. )
  628. dest = self._tags_v1 if legacy_api else self._tags_v2
  629. # Three branches:
  630. # Spec'd length == 1, Actual length 1, store as element
  631. # Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed.
  632. # No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple.
  633. # Don't mess with the legacy api, since it's frozen.
  634. if not is_ifd and (
  635. (info.length == 1)
  636. or self.tagtype[tag] == TiffTags.BYTE
  637. or (info.length is None and len(values) == 1 and not legacy_api)
  638. ):
  639. # Don't mess with the legacy api, since it's frozen.
  640. if legacy_api and self.tagtype[tag] in [
  641. TiffTags.RATIONAL,
  642. TiffTags.SIGNED_RATIONAL,
  643. ]: # rationals
  644. values = (values,)
  645. try:
  646. (dest[tag],) = values
  647. except ValueError:
  648. # We've got a builtin tag with 1 expected entry
  649. warnings.warn(
  650. f"Metadata Warning, tag {tag} had too many entries: "
  651. f"{len(values)}, expected 1"
  652. )
  653. dest[tag] = values[0]
  654. else:
  655. # Spec'd length > 1 or undefined
  656. # Unspec'd, and length > 1
  657. dest[tag] = values
  658. def __delitem__(self, tag: int) -> None:
  659. self._tags_v2.pop(tag, None)
  660. self._tags_v1.pop(tag, None)
  661. self._tagdata.pop(tag, None)
  662. def __iter__(self) -> Iterator[int]:
  663. return iter(set(self._tagdata) | set(self._tags_v2))
  664. def _unpack(self, fmt: str, data: bytes) -> tuple[Any, ...]:
  665. return struct.unpack(self._endian + fmt, data)
  666. def _pack(self, fmt: str, *values: Any) -> bytes:
  667. return struct.pack(self._endian + fmt, *values)
  668. list(
  669. map(
  670. _register_basic,
  671. [
  672. (TiffTags.SHORT, "H", "short"),
  673. (TiffTags.LONG, "L", "long"),
  674. (TiffTags.SIGNED_BYTE, "b", "signed byte"),
  675. (TiffTags.SIGNED_SHORT, "h", "signed short"),
  676. (TiffTags.SIGNED_LONG, "l", "signed long"),
  677. (TiffTags.FLOAT, "f", "float"),
  678. (TiffTags.DOUBLE, "d", "double"),
  679. (TiffTags.IFD, "L", "long"),
  680. (TiffTags.LONG8, "Q", "long8"),
  681. ],
  682. )
  683. )
  684. @_register_loader(1, 1) # Basic type, except for the legacy API.
  685. def load_byte(self, data: bytes, legacy_api: bool = True) -> bytes:
  686. return data
  687. @_register_writer(1) # Basic type, except for the legacy API.
  688. def write_byte(self, data: bytes | int | IFDRational) -> bytes:
  689. if isinstance(data, IFDRational):
  690. data = int(data)
  691. if isinstance(data, int):
  692. data = bytes((data,))
  693. return data
  694. @_register_loader(2, 1)
  695. def load_string(self, data: bytes, legacy_api: bool = True) -> str:
  696. if data.endswith(b"\0"):
  697. data = data[:-1]
  698. return data.decode("latin-1", "replace")
  699. @_register_writer(2)
  700. def write_string(self, value: str | bytes | int) -> bytes:
  701. # remerge of https://github.com/python-pillow/Pillow/pull/1416
  702. if isinstance(value, int):
  703. value = str(value)
  704. if not isinstance(value, bytes):
  705. value = value.encode("ascii", "replace")
  706. return value + b"\0"
  707. @_register_loader(5, 8)
  708. def load_rational(
  709. self, data: bytes, legacy_api: bool = True
  710. ) -> tuple[tuple[int, int] | IFDRational, ...]:
  711. vals = self._unpack(f"{len(data) // 4}L", data)
  712. def combine(a: int, b: int) -> tuple[int, int] | IFDRational:
  713. return (a, b) if legacy_api else IFDRational(a, b)
  714. return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2]))
  715. @_register_writer(5)
  716. def write_rational(self, *values: IFDRational) -> bytes:
  717. return b"".join(
  718. self._pack("2L", *_limit_rational(frac, 2**32 - 1)) for frac in values
  719. )
  720. @_register_loader(7, 1)
  721. def load_undefined(self, data: bytes, legacy_api: bool = True) -> bytes:
  722. return data
  723. @_register_writer(7)
  724. def write_undefined(self, value: bytes | int | IFDRational) -> bytes:
  725. if isinstance(value, IFDRational):
  726. value = int(value)
  727. if isinstance(value, int):
  728. value = str(value).encode("ascii", "replace")
  729. return value
  730. @_register_loader(10, 8)
  731. def load_signed_rational(
  732. self, data: bytes, legacy_api: bool = True
  733. ) -> tuple[tuple[int, int] | IFDRational, ...]:
  734. vals = self._unpack(f"{len(data) // 4}l", data)
  735. def combine(a: int, b: int) -> tuple[int, int] | IFDRational:
  736. return (a, b) if legacy_api else IFDRational(a, b)
  737. return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2]))
  738. @_register_writer(10)
  739. def write_signed_rational(self, *values: IFDRational) -> bytes:
  740. return b"".join(
  741. self._pack("2l", *_limit_signed_rational(frac, 2**31 - 1, -(2**31)))
  742. for frac in values
  743. )
  744. def _ensure_read(self, fp: IO[bytes], size: int) -> bytes:
  745. ret = fp.read(size)
  746. if len(ret) != size:
  747. msg = (
  748. "Corrupt EXIF data. "
  749. f"Expecting to read {size} bytes but only got {len(ret)}. "
  750. )
  751. raise OSError(msg)
  752. return ret
  753. def load(self, fp: IO[bytes]) -> None:
  754. self.reset()
  755. self._offset = fp.tell()
  756. try:
  757. tag_count = (
  758. self._unpack("Q", self._ensure_read(fp, 8))
  759. if self._bigtiff
  760. else self._unpack("H", self._ensure_read(fp, 2))
  761. )[0]
  762. for i in range(tag_count):
  763. tag, typ, count, data = (
  764. self._unpack("HHQ8s", self._ensure_read(fp, 20))
  765. if self._bigtiff
  766. else self._unpack("HHL4s", self._ensure_read(fp, 12))
  767. )
  768. tagname = TiffTags.lookup(tag, self.group).name
  769. typname = TYPES.get(typ, "unknown")
  770. msg = f"tag: {tagname} ({tag}) - type: {typname} ({typ})"
  771. try:
  772. unit_size, handler = self._load_dispatch[typ]
  773. except KeyError:
  774. logger.debug("%s - unsupported type %s", msg, typ)
  775. continue # ignore unsupported type
  776. size = count * unit_size
  777. if size > (8 if self._bigtiff else 4):
  778. here = fp.tell()
  779. (offset,) = self._unpack("Q" if self._bigtiff else "L", data)
  780. msg += f" Tag Location: {here} - Data Location: {offset}"
  781. fp.seek(offset)
  782. data = ImageFile._safe_read(fp, size)
  783. fp.seek(here)
  784. else:
  785. data = data[:size]
  786. if len(data) != size:
  787. warnings.warn(
  788. "Possibly corrupt EXIF data. "
  789. f"Expecting to read {size} bytes but only got {len(data)}."
  790. f" Skipping tag {tag}"
  791. )
  792. logger.debug(msg)
  793. continue
  794. if not data:
  795. logger.debug(msg)
  796. continue
  797. self._tagdata[tag] = data
  798. self.tagtype[tag] = typ
  799. msg += " - value: "
  800. msg += f"<table: {size} bytes>" if size > 32 else repr(data)
  801. logger.debug(msg)
  802. (self.next,) = (
  803. self._unpack("Q", self._ensure_read(fp, 8))
  804. if self._bigtiff
  805. else self._unpack("L", self._ensure_read(fp, 4))
  806. )
  807. except OSError as msg:
  808. warnings.warn(str(msg))
  809. return
  810. def _get_ifh(self) -> bytes:
  811. ifh = self._prefix + self._pack("H", 43 if self._bigtiff else 42)
  812. if self._bigtiff:
  813. ifh += self._pack("HH", 8, 0)
  814. ifh += self._pack("Q", 16) if self._bigtiff else self._pack("L", 8)
  815. return ifh
  816. def tobytes(self, offset: int = 0) -> bytes:
  817. # FIXME What about tagdata?
  818. result = self._pack("Q" if self._bigtiff else "H", len(self._tags_v2))
  819. entries: list[tuple[int, int, int, bytes, bytes]] = []
  820. fmt = "Q" if self._bigtiff else "L"
  821. fmt_size = 8 if self._bigtiff else 4
  822. offset += (
  823. len(result) + len(self._tags_v2) * (20 if self._bigtiff else 12) + fmt_size
  824. )
  825. stripoffsets = None
  826. # pass 1: convert tags to binary format
  827. # always write tags in ascending order
  828. for tag, value in sorted(self._tags_v2.items()):
  829. if tag == STRIPOFFSETS:
  830. stripoffsets = len(entries)
  831. typ = self.tagtype[tag]
  832. logger.debug("Tag %s, Type: %s, Value: %s", tag, typ, repr(value))
  833. is_ifd = typ == TiffTags.LONG and isinstance(value, dict)
  834. if is_ifd:
  835. ifd = ImageFileDirectory_v2(self._get_ifh(), group=tag)
  836. values = self._tags_v2[tag]
  837. for ifd_tag, ifd_value in values.items():
  838. ifd[ifd_tag] = ifd_value
  839. data = ifd.tobytes(offset)
  840. else:
  841. values = value if isinstance(value, tuple) else (value,)
  842. data = self._write_dispatch[typ](self, *values)
  843. tagname = TiffTags.lookup(tag, self.group).name
  844. typname = "ifd" if is_ifd else TYPES.get(typ, "unknown")
  845. msg = f"save: {tagname} ({tag}) - type: {typname} ({typ}) - value: "
  846. msg += f"<table: {len(data)} bytes>" if len(data) >= 16 else str(values)
  847. logger.debug(msg)
  848. # count is sum of lengths for string and arbitrary data
  849. if is_ifd:
  850. count = 1
  851. elif typ in [TiffTags.BYTE, TiffTags.ASCII, TiffTags.UNDEFINED]:
  852. count = len(data)
  853. else:
  854. count = len(values)
  855. # figure out if data fits into the entry
  856. if len(data) <= fmt_size:
  857. entries.append((tag, typ, count, data.ljust(fmt_size, b"\0"), b""))
  858. else:
  859. entries.append((tag, typ, count, self._pack(fmt, offset), data))
  860. offset += (len(data) + 1) // 2 * 2 # pad to word
  861. # update strip offset data to point beyond auxiliary data
  862. if stripoffsets is not None:
  863. tag, typ, count, value, data = entries[stripoffsets]
  864. if data:
  865. size, handler = self._load_dispatch[typ]
  866. values = [val + offset for val in handler(self, data, self.legacy_api)]
  867. data = self._write_dispatch[typ](self, *values)
  868. else:
  869. value = self._pack(fmt, self._unpack(fmt, value)[0] + offset)
  870. entries[stripoffsets] = tag, typ, count, value, data
  871. # pass 2: write entries to file
  872. for tag, typ, count, value, data in entries:
  873. logger.debug("%s %s %s %s %s", tag, typ, count, repr(value), repr(data))
  874. result += self._pack(
  875. "HHQ8s" if self._bigtiff else "HHL4s", tag, typ, count, value
  876. )
  877. # -- overwrite here for multi-page --
  878. result += self._pack(fmt, 0) # end of entries
  879. # pass 3: write auxiliary data to file
  880. for tag, typ, count, value, data in entries:
  881. result += data
  882. if len(data) & 1:
  883. result += b"\0"
  884. return result
  885. def save(self, fp: IO[bytes]) -> int:
  886. if fp.tell() == 0: # skip TIFF header on subsequent pages
  887. fp.write(self._get_ifh())
  888. offset = fp.tell()
  889. result = self.tobytes(offset)
  890. fp.write(result)
  891. return offset + len(result)
  892. ImageFileDirectory_v2._load_dispatch = _load_dispatch
  893. ImageFileDirectory_v2._write_dispatch = _write_dispatch
  894. for idx, name in TYPES.items():
  895. name = name.replace(" ", "_")
  896. setattr(ImageFileDirectory_v2, f"load_{name}", _load_dispatch[idx][1])
  897. setattr(ImageFileDirectory_v2, f"write_{name}", _write_dispatch[idx])
  898. del _load_dispatch, _write_dispatch, idx, name
  899. # Legacy ImageFileDirectory support.
  900. class ImageFileDirectory_v1(ImageFileDirectory_v2):
  901. """This class represents the **legacy** interface to a TIFF tag directory.
  902. Exposes a dictionary interface of the tags in the directory::
  903. ifd = ImageFileDirectory_v1()
  904. ifd[key] = 'Some Data'
  905. ifd.tagtype[key] = TiffTags.ASCII
  906. print(ifd[key])
  907. ('Some Data',)
  908. Also contains a dictionary of tag types as read from the tiff image file,
  909. :attr:`~PIL.TiffImagePlugin.ImageFileDirectory_v1.tagtype`.
  910. Values are returned as a tuple.
  911. .. deprecated:: 3.0.0
  912. """
  913. def __init__(self, *args: Any, **kwargs: Any) -> None:
  914. super().__init__(*args, **kwargs)
  915. self._legacy_api = True
  916. tags = property(lambda self: self._tags_v1)
  917. tagdata = property(lambda self: self._tagdata)
  918. # defined in ImageFileDirectory_v2
  919. tagtype: dict[int, int]
  920. """Dictionary of tag types"""
  921. @classmethod
  922. def from_v2(cls, original: ImageFileDirectory_v2) -> ImageFileDirectory_v1:
  923. """Returns an
  924. :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
  925. instance with the same data as is contained in the original
  926. :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2`
  927. instance.
  928. :returns: :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
  929. """
  930. ifd = cls(prefix=original.prefix)
  931. ifd._tagdata = original._tagdata
  932. ifd.tagtype = original.tagtype
  933. ifd.next = original.next # an indicator for multipage tiffs
  934. return ifd
  935. def to_v2(self) -> ImageFileDirectory_v2:
  936. """Returns an
  937. :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2`
  938. instance with the same data as is contained in the original
  939. :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
  940. instance.
  941. :returns: :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2`
  942. """
  943. ifd = ImageFileDirectory_v2(prefix=self.prefix)
  944. ifd._tagdata = dict(self._tagdata)
  945. ifd.tagtype = dict(self.tagtype)
  946. ifd._tags_v2 = dict(self._tags_v2)
  947. return ifd
  948. def __contains__(self, tag: object) -> bool:
  949. return tag in self._tags_v1 or tag in self._tagdata
  950. def __len__(self) -> int:
  951. return len(set(self._tagdata) | set(self._tags_v1))
  952. def __iter__(self) -> Iterator[int]:
  953. return iter(set(self._tagdata) | set(self._tags_v1))
  954. def __setitem__(self, tag: int, value: Any) -> None:
  955. for legacy_api in (False, True):
  956. self._setitem(tag, value, legacy_api)
  957. def __getitem__(self, tag: int) -> Any:
  958. if tag not in self._tags_v1: # unpack on the fly
  959. data = self._tagdata[tag]
  960. typ = self.tagtype[tag]
  961. size, handler = self._load_dispatch[typ]
  962. for legacy in (False, True):
  963. self._setitem(tag, handler(self, data, legacy), legacy)
  964. val = self._tags_v1[tag]
  965. if not isinstance(val, (tuple, bytes)):
  966. val = (val,)
  967. return val
  968. # undone -- switch this pointer
  969. ImageFileDirectory = ImageFileDirectory_v1
  970. ##
  971. # Image plugin for TIFF files.
  972. class TiffImageFile(ImageFile.ImageFile):
  973. format = "TIFF"
  974. format_description = "Adobe TIFF"
  975. _close_exclusive_fp_after_loading = False
  976. def __init__(
  977. self,
  978. fp: StrOrBytesPath | IO[bytes],
  979. filename: str | bytes | None = None,
  980. ) -> None:
  981. self.tag_v2: ImageFileDirectory_v2
  982. """ Image file directory (tag dictionary) """
  983. self.tag: ImageFileDirectory_v1
  984. """ Legacy tag entries """
  985. super().__init__(fp, filename)
  986. def _open(self) -> None:
  987. """Open the first image in a TIFF file"""
  988. # Header
  989. assert self.fp is not None
  990. ifh = self.fp.read(8)
  991. if ifh[2] == 43:
  992. ifh += self.fp.read(8)
  993. self.tag_v2 = ImageFileDirectory_v2(ifh)
  994. # setup frame pointers
  995. self.__first = self.__next = self.tag_v2.next
  996. self.__frame = -1
  997. self._fp = self.fp
  998. self._frame_pos: list[int] = []
  999. self._n_frames: int | None = None
  1000. logger.debug("*** TiffImageFile._open ***")
  1001. logger.debug("- __first: %s", self.__first)
  1002. logger.debug("- ifh: %s", repr(ifh)) # Use repr to avoid str(bytes)
  1003. # and load the first frame
  1004. self._seek(0)
  1005. @property
  1006. def n_frames(self) -> int:
  1007. current_n_frames = self._n_frames
  1008. if current_n_frames is None:
  1009. current = self.tell()
  1010. self._seek(len(self._frame_pos))
  1011. while self._n_frames is None:
  1012. self._seek(self.tell() + 1)
  1013. self.seek(current)
  1014. assert self._n_frames is not None
  1015. return self._n_frames
  1016. def seek(self, frame: int) -> None:
  1017. """Select a given frame as current image"""
  1018. if not self._seek_check(frame):
  1019. return
  1020. self._seek(frame)
  1021. if self._im is not None and (
  1022. self.im.size != self._tile_size
  1023. or self.im.mode != self.mode
  1024. or self.readonly
  1025. ):
  1026. self._im = None
  1027. def _seek(self, frame: int) -> None:
  1028. if isinstance(self._fp, DeferredError):
  1029. raise self._fp.ex
  1030. self.fp = self._fp
  1031. while len(self._frame_pos) <= frame:
  1032. if not self.__next:
  1033. msg = "no more images in TIFF file"
  1034. raise EOFError(msg)
  1035. logger.debug(
  1036. "Seeking to frame %s, on frame %s, __next %s, location: %s",
  1037. frame,
  1038. self.__frame,
  1039. self.__next,
  1040. self.fp.tell(),
  1041. )
  1042. if self.__next >= 2**63:
  1043. msg = "Unable to seek to frame"
  1044. raise ValueError(msg)
  1045. self.fp.seek(self.__next)
  1046. self._frame_pos.append(self.__next)
  1047. logger.debug("Loading tags, location: %s", self.fp.tell())
  1048. self.tag_v2.load(self.fp)
  1049. if self.tag_v2.next in self._frame_pos:
  1050. # This IFD has already been processed
  1051. # Declare this to be the end of the image
  1052. self.__next = 0
  1053. else:
  1054. self.__next = self.tag_v2.next
  1055. if self.__next == 0:
  1056. self._n_frames = frame + 1
  1057. if len(self._frame_pos) == 1:
  1058. self.is_animated = self.__next != 0
  1059. self.__frame += 1
  1060. self.fp.seek(self._frame_pos[frame])
  1061. self.tag_v2.load(self.fp)
  1062. if XMP in self.tag_v2:
  1063. xmp = self.tag_v2[XMP]
  1064. if isinstance(xmp, tuple) and len(xmp) == 1:
  1065. xmp = xmp[0]
  1066. self.info["xmp"] = xmp
  1067. elif "xmp" in self.info:
  1068. del self.info["xmp"]
  1069. self._reload_exif()
  1070. # fill the legacy tag/ifd entries
  1071. self.tag = self.ifd = ImageFileDirectory_v1.from_v2(self.tag_v2)
  1072. self.__frame = frame
  1073. self._setup()
  1074. def tell(self) -> int:
  1075. """Return the current frame number"""
  1076. return self.__frame
  1077. def get_photoshop_blocks(self) -> dict[int, dict[str, bytes]]:
  1078. """
  1079. Returns a dictionary of Photoshop "Image Resource Blocks".
  1080. The keys are the image resource ID. For more information, see
  1081. https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_pgfId-1037727
  1082. :returns: Photoshop "Image Resource Blocks" in a dictionary.
  1083. """
  1084. blocks = {}
  1085. val = self.tag_v2.get(ExifTags.Base.ImageResources)
  1086. if val:
  1087. while val.startswith(b"8BIM"):
  1088. id = i16(val[4:6])
  1089. n = math.ceil((val[6] + 1) / 2) * 2
  1090. size = i32(val[6 + n : 10 + n])
  1091. data = val[10 + n : 10 + n + size]
  1092. blocks[id] = {"data": data}
  1093. val = val[math.ceil((10 + n + size) / 2) * 2 :]
  1094. return blocks
  1095. def load(self) -> Image.core.PixelAccess | None:
  1096. if self.tile and self.use_load_libtiff:
  1097. return self._load_libtiff()
  1098. return super().load()
  1099. def load_prepare(self) -> None:
  1100. if self._im is None:
  1101. Image._decompression_bomb_check(self._tile_size)
  1102. self.im = Image.core.new(self.mode, self._tile_size)
  1103. ImageFile.ImageFile.load_prepare(self)
  1104. def load_end(self) -> None:
  1105. # allow closing if we're on the first frame, there's no next
  1106. # This is the ImageFile.load path only, libtiff specific below.
  1107. if not self.is_animated:
  1108. self._close_exclusive_fp_after_loading = True
  1109. # load IFD data from fp before it is closed
  1110. exif = self.getexif()
  1111. for key in TiffTags.TAGS_V2_GROUPS:
  1112. if key not in exif:
  1113. continue
  1114. exif.get_ifd(key)
  1115. ImageOps.exif_transpose(self, in_place=True)
  1116. if ExifTags.Base.Orientation in self.tag_v2:
  1117. del self.tag_v2[ExifTags.Base.Orientation]
  1118. def _load_libtiff(self) -> Image.core.PixelAccess | None:
  1119. """Overload method triggered when we detect a compressed tiff
  1120. Calls out to libtiff"""
  1121. Image.Image.load(self)
  1122. self.load_prepare()
  1123. if not len(self.tile) == 1:
  1124. msg = "Not exactly one tile"
  1125. raise OSError(msg)
  1126. # (self._compression, (extents tuple),
  1127. # 0, (rawmode, self._compression, fp))
  1128. extents = self.tile[0][1]
  1129. args = self.tile[0][3]
  1130. # To be nice on memory footprint, if there's a
  1131. # file descriptor, use that instead of reading
  1132. # into a string in python.
  1133. assert self.fp is not None
  1134. try:
  1135. fp = hasattr(self.fp, "fileno") and self.fp.fileno()
  1136. # flush the file descriptor, prevents error on pypy 2.4+
  1137. # should also eliminate the need for fp.tell
  1138. # in _seek
  1139. if hasattr(self.fp, "flush"):
  1140. self.fp.flush()
  1141. except OSError:
  1142. # io.BytesIO have a fileno, but returns an OSError if
  1143. # it doesn't use a file descriptor.
  1144. fp = False
  1145. if fp:
  1146. assert isinstance(args, tuple)
  1147. args_list = list(args)
  1148. args_list[2] = fp
  1149. args = tuple(args_list)
  1150. decoder = Image._getdecoder(self.mode, "libtiff", args, self.decoderconfig)
  1151. try:
  1152. decoder.setimage(self.im, extents)
  1153. except ValueError as e:
  1154. msg = "Couldn't set the image"
  1155. raise OSError(msg) from e
  1156. close_self_fp = self._exclusive_fp and not self.is_animated
  1157. if hasattr(self.fp, "getvalue"):
  1158. # We've got a stringio like thing passed in. Yay for all in memory.
  1159. # The decoder needs the entire file in one shot, so there's not
  1160. # a lot we can do here other than give it the entire file.
  1161. # unless we could do something like get the address of the
  1162. # underlying string for stringio.
  1163. #
  1164. # Rearranging for supporting byteio items, since they have a fileno
  1165. # that returns an OSError if there's no underlying fp. Easier to
  1166. # deal with here by reordering.
  1167. logger.debug("have getvalue. just sending in a string from getvalue")
  1168. n, err = decoder.decode(self.fp.getvalue())
  1169. elif fp:
  1170. # we've got a actual file on disk, pass in the fp.
  1171. logger.debug("have fileno, calling fileno version of the decoder.")
  1172. if not close_self_fp:
  1173. self.fp.seek(0)
  1174. # Save and restore the file position, because libtiff will move it
  1175. # outside of the Python runtime, and that will confuse
  1176. # io.BufferedReader and possible others.
  1177. # NOTE: This must use os.lseek(), and not fp.tell()/fp.seek(),
  1178. # because the buffer read head already may not equal the actual
  1179. # file position, and fp.seek() may just adjust it's internal
  1180. # pointer and not actually seek the OS file handle.
  1181. pos = os.lseek(fp, 0, os.SEEK_CUR)
  1182. # 4 bytes, otherwise the trace might error out
  1183. n, err = decoder.decode(b"fpfp")
  1184. os.lseek(fp, pos, os.SEEK_SET)
  1185. else:
  1186. # we have something else.
  1187. logger.debug("don't have fileno or getvalue. just reading")
  1188. self.fp.seek(0)
  1189. # UNDONE -- so much for that buffer size thing.
  1190. n, err = decoder.decode(self.fp.read())
  1191. self.tile = []
  1192. self.readonly = 0
  1193. self.load_end()
  1194. if close_self_fp:
  1195. self.fp.close()
  1196. self.fp = None # might be shared
  1197. if err < 0:
  1198. msg = f"decoder error {err}"
  1199. raise OSError(msg)
  1200. return Image.Image.load(self)
  1201. def _setup(self) -> None:
  1202. """Setup this image object based on current tags"""
  1203. if 0xBC01 in self.tag_v2:
  1204. msg = "Windows Media Photo files not yet supported"
  1205. raise OSError(msg)
  1206. # extract relevant tags
  1207. self._compression = COMPRESSION_INFO[self.tag_v2.get(COMPRESSION, 1)]
  1208. self._planar_configuration = self.tag_v2.get(PLANAR_CONFIGURATION, 1)
  1209. # photometric is a required tag, but not everyone is reading
  1210. # the specification
  1211. photo = self.tag_v2.get(PHOTOMETRIC_INTERPRETATION, 0)
  1212. # old style jpeg compression images most certainly are YCbCr
  1213. if self._compression == "tiff_jpeg":
  1214. photo = 6
  1215. fillorder = self.tag_v2.get(FILLORDER, 1)
  1216. logger.debug("*** Summary ***")
  1217. logger.debug("- compression: %s", self._compression)
  1218. logger.debug("- photometric_interpretation: %s", photo)
  1219. logger.debug("- planar_configuration: %s", self._planar_configuration)
  1220. logger.debug("- fill_order: %s", fillorder)
  1221. logger.debug("- YCbCr subsampling: %s", self.tag_v2.get(YCBCRSUBSAMPLING))
  1222. # size
  1223. try:
  1224. xsize = self.tag_v2[IMAGEWIDTH]
  1225. ysize = self.tag_v2[IMAGELENGTH]
  1226. except KeyError as e:
  1227. msg = "Missing dimensions"
  1228. raise TypeError(msg) from e
  1229. if not isinstance(xsize, int) or not isinstance(ysize, int):
  1230. msg = "Invalid dimensions"
  1231. raise ValueError(msg)
  1232. self._tile_size = xsize, ysize
  1233. orientation = self.tag_v2.get(ExifTags.Base.Orientation)
  1234. if orientation in (5, 6, 7, 8):
  1235. self._size = ysize, xsize
  1236. else:
  1237. self._size = xsize, ysize
  1238. logger.debug("- size: %s", self.size)
  1239. sample_format = self.tag_v2.get(SAMPLEFORMAT, (1,))
  1240. if len(sample_format) > 1 and max(sample_format) == min(sample_format) == 1:
  1241. # SAMPLEFORMAT is properly per band, so an RGB image will
  1242. # be (1,1,1). But, we don't support per band pixel types,
  1243. # and anything more than one band is a uint8. So, just
  1244. # take the first element. Revisit this if adding support
  1245. # for more exotic images.
  1246. sample_format = (1,)
  1247. bps_tuple = self.tag_v2.get(BITSPERSAMPLE, (1,))
  1248. extra_tuple = self.tag_v2.get(EXTRASAMPLES, ())
  1249. if photo in (2, 6, 8): # RGB, YCbCr, LAB
  1250. bps_count = 3
  1251. elif photo == 5: # CMYK
  1252. bps_count = 4
  1253. else:
  1254. bps_count = 1
  1255. bps_count += len(extra_tuple)
  1256. bps_actual_count = len(bps_tuple)
  1257. samples_per_pixel = self.tag_v2.get(
  1258. SAMPLESPERPIXEL,
  1259. 3 if self._compression == "tiff_jpeg" and photo in (2, 6) else 1,
  1260. )
  1261. if samples_per_pixel > MAX_SAMPLESPERPIXEL:
  1262. # DOS check, samples_per_pixel can be a Long, and we extend the tuple below
  1263. logger.error(
  1264. "More samples per pixel than can be decoded: %s", samples_per_pixel
  1265. )
  1266. msg = "Invalid value for samples per pixel"
  1267. raise SyntaxError(msg)
  1268. if samples_per_pixel < bps_actual_count:
  1269. # If a file has more values in bps_tuple than expected,
  1270. # remove the excess.
  1271. bps_tuple = bps_tuple[:samples_per_pixel]
  1272. elif samples_per_pixel > bps_actual_count and bps_actual_count == 1:
  1273. # If a file has only one value in bps_tuple, when it should have more,
  1274. # presume it is the same number of bits for all of the samples.
  1275. bps_tuple = bps_tuple * samples_per_pixel
  1276. if len(bps_tuple) != samples_per_pixel:
  1277. msg = "unknown data organization"
  1278. raise SyntaxError(msg)
  1279. # mode: check photometric interpretation and bits per pixel
  1280. key = (
  1281. self.tag_v2.prefix,
  1282. photo,
  1283. sample_format,
  1284. fillorder,
  1285. bps_tuple,
  1286. extra_tuple,
  1287. )
  1288. logger.debug("format key: %s", key)
  1289. try:
  1290. self._mode, rawmode = OPEN_INFO[key]
  1291. except KeyError as e:
  1292. logger.debug("- unsupported format")
  1293. msg = "unknown pixel mode"
  1294. raise SyntaxError(msg) from e
  1295. logger.debug("- raw mode: %s", rawmode)
  1296. logger.debug("- pil mode: %s", self.mode)
  1297. self.info["compression"] = self._compression
  1298. xres = self.tag_v2.get(X_RESOLUTION, 1)
  1299. yres = self.tag_v2.get(Y_RESOLUTION, 1)
  1300. if xres and yres:
  1301. resunit = self.tag_v2.get(RESOLUTION_UNIT)
  1302. if resunit == 2: # dots per inch
  1303. self.info["dpi"] = (xres, yres)
  1304. elif resunit == 3: # dots per centimeter. convert to dpi
  1305. self.info["dpi"] = (xres * 2.54, yres * 2.54)
  1306. elif resunit is None: # used to default to 1, but now 2)
  1307. self.info["dpi"] = (xres, yres)
  1308. # For backward compatibility,
  1309. # we also preserve the old behavior
  1310. self.info["resolution"] = xres, yres
  1311. else: # No absolute unit of measurement
  1312. self.info["resolution"] = xres, yres
  1313. # build tile descriptors
  1314. x = y = layer = 0
  1315. self.tile = []
  1316. self.use_load_libtiff = READ_LIBTIFF or self._compression != "raw"
  1317. if self.use_load_libtiff:
  1318. # Decoder expects entire file as one tile.
  1319. # There's a buffer size limit in load (64k)
  1320. # so large g4 images will fail if we use that
  1321. # function.
  1322. #
  1323. # Setup the one tile for the whole image, then
  1324. # use the _load_libtiff function.
  1325. # libtiff handles the fillmode for us, so 1;IR should
  1326. # actually be 1;I. Including the R double reverses the
  1327. # bits, so stripes of the image are reversed. See
  1328. # https://github.com/python-pillow/Pillow/issues/279
  1329. if fillorder == 2:
  1330. # Replace fillorder with fillorder=1
  1331. key = key[:3] + (1,) + key[4:]
  1332. logger.debug("format key: %s", key)
  1333. # this should always work, since all the
  1334. # fillorder==2 modes have a corresponding
  1335. # fillorder=1 mode
  1336. self._mode, rawmode = OPEN_INFO[key]
  1337. # YCbCr images with new jpeg compression with pixels in one plane
  1338. # unpacked straight into RGB values
  1339. if (
  1340. photo == 6
  1341. and self._compression == "jpeg"
  1342. and self._planar_configuration == 1
  1343. ):
  1344. rawmode = "RGB"
  1345. # libtiff always returns the bytes in native order.
  1346. # we're expecting image byte order. So, if the rawmode
  1347. # contains I;16, we need to convert from native to image
  1348. # byte order.
  1349. elif rawmode == "I;16":
  1350. rawmode = "I;16N"
  1351. elif rawmode.endswith((";16B", ";16L")):
  1352. rawmode = rawmode[:-1] + "N"
  1353. # Offset in the tile tuple is 0, we go from 0,0 to
  1354. # w,h, and we only do this once -- eds
  1355. a = (rawmode, self._compression, False, self.tag_v2.offset)
  1356. self.tile.append(ImageFile._Tile("libtiff", (0, 0, xsize, ysize), 0, a))
  1357. elif STRIPOFFSETS in self.tag_v2 or TILEOFFSETS in self.tag_v2:
  1358. # striped image
  1359. if STRIPOFFSETS in self.tag_v2:
  1360. offsets = self.tag_v2[STRIPOFFSETS]
  1361. h = self.tag_v2.get(ROWSPERSTRIP, ysize)
  1362. w = xsize
  1363. else:
  1364. # tiled image
  1365. offsets = self.tag_v2[TILEOFFSETS]
  1366. tilewidth = self.tag_v2.get(TILEWIDTH)
  1367. h = self.tag_v2.get(TILELENGTH)
  1368. if not isinstance(tilewidth, int) or not isinstance(h, int):
  1369. msg = "Invalid tile dimensions"
  1370. raise ValueError(msg)
  1371. w = tilewidth
  1372. if w == xsize and h == ysize and self._planar_configuration != 2:
  1373. # Every tile covers the image. Only use the last offset
  1374. offsets = offsets[-1:]
  1375. for offset in offsets:
  1376. if x + w > xsize:
  1377. stride = w * sum(bps_tuple) / 8 # bytes per line
  1378. else:
  1379. stride = 0
  1380. tile_rawmode = rawmode
  1381. if self._planar_configuration == 2:
  1382. # each band on it's own layer
  1383. tile_rawmode = rawmode[layer]
  1384. # adjust stride width accordingly
  1385. stride /= bps_count
  1386. args = (tile_rawmode, int(stride), 1)
  1387. self.tile.append(
  1388. ImageFile._Tile(
  1389. self._compression,
  1390. (x, y, min(x + w, xsize), min(y + h, ysize)),
  1391. offset,
  1392. args,
  1393. )
  1394. )
  1395. x += w
  1396. if x >= xsize:
  1397. x, y = 0, y + h
  1398. if y >= ysize:
  1399. y = 0
  1400. layer += 1
  1401. else:
  1402. logger.debug("- unsupported data organization")
  1403. msg = "unknown data organization"
  1404. raise SyntaxError(msg)
  1405. # Fix up info.
  1406. if ICCPROFILE in self.tag_v2:
  1407. self.info["icc_profile"] = self.tag_v2[ICCPROFILE]
  1408. # fixup palette descriptor
  1409. if self.mode in ["P", "PA"]:
  1410. palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]]
  1411. self.palette = ImagePalette.raw("RGB;L", b"".join(palette))
  1412. #
  1413. # --------------------------------------------------------------------
  1414. # Write TIFF files
  1415. # little endian is default except for image modes with
  1416. # explicit big endian byte-order
  1417. SAVE_INFO = {
  1418. # mode => rawmode, byteorder, photometrics,
  1419. # sampleformat, bitspersample, extra
  1420. "1": ("1", II, 1, 1, (1,), None),
  1421. "L": ("L", II, 1, 1, (8,), None),
  1422. "LA": ("LA", II, 1, 1, (8, 8), 2),
  1423. "P": ("P", II, 3, 1, (8,), None),
  1424. "PA": ("PA", II, 3, 1, (8, 8), 2),
  1425. "I": ("I;32S", II, 1, 2, (32,), None),
  1426. "I;16": ("I;16", II, 1, 1, (16,), None),
  1427. "I;16L": ("I;16L", II, 1, 1, (16,), None),
  1428. "F": ("F;32F", II, 1, 3, (32,), None),
  1429. "RGB": ("RGB", II, 2, 1, (8, 8, 8), None),
  1430. "RGBX": ("RGBX", II, 2, 1, (8, 8, 8, 8), 0),
  1431. "RGBA": ("RGBA", II, 2, 1, (8, 8, 8, 8), 2),
  1432. "CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None),
  1433. "YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None),
  1434. "LAB": ("LAB", II, 8, 1, (8, 8, 8), None),
  1435. "I;16B": ("I;16B", MM, 1, 1, (16,), None),
  1436. }
  1437. def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
  1438. try:
  1439. rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
  1440. except KeyError as e:
  1441. msg = f"cannot write mode {im.mode} as TIFF"
  1442. raise OSError(msg) from e
  1443. encoderinfo = im.encoderinfo
  1444. encoderconfig = im.encoderconfig
  1445. ifd = ImageFileDirectory_v2(prefix=prefix)
  1446. if encoderinfo.get("big_tiff"):
  1447. ifd._bigtiff = True
  1448. try:
  1449. compression = encoderinfo["compression"]
  1450. except KeyError:
  1451. compression = im.info.get("compression")
  1452. if isinstance(compression, int):
  1453. # compression value may be from BMP. Ignore it
  1454. compression = None
  1455. if compression is None:
  1456. compression = "raw"
  1457. elif compression == "tiff_jpeg":
  1458. # OJPEG is obsolete, so use new-style JPEG compression instead
  1459. compression = "jpeg"
  1460. elif compression == "tiff_deflate":
  1461. compression = "tiff_adobe_deflate"
  1462. libtiff = WRITE_LIBTIFF or compression != "raw"
  1463. # required for color libtiff images
  1464. ifd[PLANAR_CONFIGURATION] = 1
  1465. ifd[IMAGEWIDTH] = im.size[0]
  1466. ifd[IMAGELENGTH] = im.size[1]
  1467. # write any arbitrary tags passed in as an ImageFileDirectory
  1468. if "tiffinfo" in encoderinfo:
  1469. info = encoderinfo["tiffinfo"]
  1470. elif "exif" in encoderinfo:
  1471. info = encoderinfo["exif"]
  1472. if isinstance(info, bytes):
  1473. exif = Image.Exif()
  1474. exif.load(info)
  1475. info = exif
  1476. else:
  1477. info = {}
  1478. logger.debug("Tiffinfo Keys: %s", list(info))
  1479. if isinstance(info, ImageFileDirectory_v1):
  1480. info = info.to_v2()
  1481. for key in info:
  1482. if isinstance(info, Image.Exif) and key in TiffTags.TAGS_V2_GROUPS:
  1483. ifd[key] = info.get_ifd(key)
  1484. else:
  1485. ifd[key] = info.get(key)
  1486. try:
  1487. ifd.tagtype[key] = info.tagtype[key]
  1488. except Exception:
  1489. pass # might not be an IFD. Might not have populated type
  1490. legacy_ifd = {}
  1491. if hasattr(im, "tag"):
  1492. legacy_ifd = im.tag.to_v2()
  1493. supplied_tags = {**legacy_ifd, **getattr(im, "tag_v2", {})}
  1494. for tag in (
  1495. # IFD offset that may not be correct in the saved image
  1496. EXIFIFD,
  1497. # Determined by the image format and should not be copied from legacy_ifd.
  1498. SAMPLEFORMAT,
  1499. ):
  1500. if tag in supplied_tags:
  1501. del supplied_tags[tag]
  1502. # additions written by Greg Couch, gregc@cgl.ucsf.edu
  1503. # inspired by image-sig posting from Kevin Cazabon, kcazabon@home.com
  1504. if hasattr(im, "tag_v2"):
  1505. # preserve tags from original TIFF image file
  1506. for key in (
  1507. RESOLUTION_UNIT,
  1508. X_RESOLUTION,
  1509. Y_RESOLUTION,
  1510. IPTC_NAA_CHUNK,
  1511. PHOTOSHOP_CHUNK,
  1512. XMP,
  1513. ):
  1514. if key in im.tag_v2:
  1515. if key == IPTC_NAA_CHUNK and im.tag_v2.tagtype[key] not in (
  1516. TiffTags.BYTE,
  1517. TiffTags.UNDEFINED,
  1518. ):
  1519. del supplied_tags[key]
  1520. else:
  1521. ifd[key] = im.tag_v2[key]
  1522. ifd.tagtype[key] = im.tag_v2.tagtype[key]
  1523. # preserve ICC profile (should also work when saving other formats
  1524. # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
  1525. icc = encoderinfo.get("icc_profile", im.info.get("icc_profile"))
  1526. if icc:
  1527. ifd[ICCPROFILE] = icc
  1528. for key, name in [
  1529. (IMAGEDESCRIPTION, "description"),
  1530. (X_RESOLUTION, "resolution"),
  1531. (Y_RESOLUTION, "resolution"),
  1532. (X_RESOLUTION, "x_resolution"),
  1533. (Y_RESOLUTION, "y_resolution"),
  1534. (RESOLUTION_UNIT, "resolution_unit"),
  1535. (SOFTWARE, "software"),
  1536. (DATE_TIME, "date_time"),
  1537. (ARTIST, "artist"),
  1538. (COPYRIGHT, "copyright"),
  1539. ]:
  1540. if name in encoderinfo:
  1541. ifd[key] = encoderinfo[name]
  1542. dpi = encoderinfo.get("dpi")
  1543. if dpi:
  1544. ifd[RESOLUTION_UNIT] = 2
  1545. ifd[X_RESOLUTION] = dpi[0]
  1546. ifd[Y_RESOLUTION] = dpi[1]
  1547. if bits != (1,):
  1548. ifd[BITSPERSAMPLE] = bits
  1549. if len(bits) != 1:
  1550. ifd[SAMPLESPERPIXEL] = len(bits)
  1551. if extra is not None:
  1552. ifd[EXTRASAMPLES] = extra
  1553. if format != 1:
  1554. ifd[SAMPLEFORMAT] = format
  1555. if PHOTOMETRIC_INTERPRETATION not in ifd:
  1556. ifd[PHOTOMETRIC_INTERPRETATION] = photo
  1557. elif im.mode in ("1", "L") and ifd[PHOTOMETRIC_INTERPRETATION] == 0:
  1558. if im.mode == "1":
  1559. inverted_im = im.copy()
  1560. px = inverted_im.load()
  1561. if px is not None:
  1562. for y in range(inverted_im.height):
  1563. for x in range(inverted_im.width):
  1564. px[x, y] = 0 if px[x, y] == 255 else 255
  1565. im = inverted_im
  1566. else:
  1567. im = ImageOps.invert(im)
  1568. if im.mode in ["P", "PA"]:
  1569. lut = im.im.getpalette("RGB", "RGB;L")
  1570. colormap = []
  1571. colors = len(lut) // 3
  1572. for i in range(3):
  1573. colormap += [v * 256 for v in lut[colors * i : colors * (i + 1)]]
  1574. colormap += [0] * (256 - colors)
  1575. ifd[COLORMAP] = colormap
  1576. # data orientation
  1577. w, h = ifd[IMAGEWIDTH], ifd[IMAGELENGTH]
  1578. stride = len(bits) * ((w * bits[0] + 7) // 8)
  1579. if ROWSPERSTRIP not in ifd:
  1580. # aim for given strip size (64 KB by default) when using libtiff writer
  1581. if libtiff:
  1582. im_strip_size = encoderinfo.get("strip_size", STRIP_SIZE)
  1583. rows_per_strip = 1 if stride == 0 else min(im_strip_size // stride, h)
  1584. # JPEG encoder expects multiple of 8 rows
  1585. if compression == "jpeg":
  1586. rows_per_strip = min(((rows_per_strip + 7) // 8) * 8, h)
  1587. else:
  1588. rows_per_strip = h
  1589. if rows_per_strip == 0:
  1590. rows_per_strip = 1
  1591. ifd[ROWSPERSTRIP] = rows_per_strip
  1592. strip_byte_counts = 1 if stride == 0 else stride * ifd[ROWSPERSTRIP]
  1593. strips_per_image = (h + ifd[ROWSPERSTRIP] - 1) // ifd[ROWSPERSTRIP]
  1594. if strip_byte_counts >= 2**16:
  1595. ifd.tagtype[STRIPBYTECOUNTS] = TiffTags.LONG
  1596. ifd[STRIPBYTECOUNTS] = (strip_byte_counts,) * (strips_per_image - 1) + (
  1597. stride * h - strip_byte_counts * (strips_per_image - 1),
  1598. )
  1599. ifd[STRIPOFFSETS] = tuple(
  1600. range(0, strip_byte_counts * strips_per_image, strip_byte_counts)
  1601. ) # this is adjusted by IFD writer
  1602. # no compression by default:
  1603. ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)
  1604. if im.mode == "YCbCr":
  1605. for tag, default_value in {
  1606. YCBCRSUBSAMPLING: (1, 1),
  1607. REFERENCEBLACKWHITE: (0, 255, 128, 255, 128, 255),
  1608. }.items():
  1609. ifd.setdefault(tag, default_value)
  1610. blocklist = [TILEWIDTH, TILELENGTH, TILEOFFSETS, TILEBYTECOUNTS]
  1611. if libtiff:
  1612. if "quality" in encoderinfo:
  1613. quality = encoderinfo["quality"]
  1614. if not isinstance(quality, int) or quality < 0 or quality > 100:
  1615. msg = "Invalid quality setting"
  1616. raise ValueError(msg)
  1617. if compression != "jpeg":
  1618. msg = "quality setting only supported for 'jpeg' compression"
  1619. raise ValueError(msg)
  1620. ifd[JPEGQUALITY] = quality
  1621. logger.debug("Saving using libtiff encoder")
  1622. logger.debug("Items: %s", sorted(ifd.items()))
  1623. _fp = 0
  1624. if hasattr(fp, "fileno"):
  1625. try:
  1626. fp.seek(0)
  1627. _fp = fp.fileno()
  1628. except io.UnsupportedOperation:
  1629. pass
  1630. # optional types for non core tags
  1631. types = {}
  1632. # STRIPOFFSETS and STRIPBYTECOUNTS are added by the library
  1633. # based on the data in the strip.
  1634. # OSUBFILETYPE is deprecated.
  1635. # The other tags expect arrays with a certain length (fixed or depending on
  1636. # BITSPERSAMPLE, etc), passing arrays with a different length will result in
  1637. # segfaults. Block these tags until we add extra validation.
  1638. # SUBIFD may also cause a segfault.
  1639. blocklist += [
  1640. OSUBFILETYPE,
  1641. REFERENCEBLACKWHITE,
  1642. STRIPBYTECOUNTS,
  1643. STRIPOFFSETS,
  1644. TRANSFERFUNCTION,
  1645. SUBIFD,
  1646. ]
  1647. # bits per sample is a single short in the tiff directory, not a list.
  1648. atts: dict[int, Any] = {BITSPERSAMPLE: bits[0]}
  1649. # Merge the ones that we have with (optional) more bits from
  1650. # the original file, e.g x,y resolution so that we can
  1651. # save(load('')) == original file.
  1652. for tag, value in itertools.chain(ifd.items(), supplied_tags.items()):
  1653. # Libtiff can only process certain core items without adding
  1654. # them to the custom dictionary.
  1655. # Custom items are supported for int, float, unicode, string and byte
  1656. # values. Other types and tuples require a tagtype.
  1657. if tag not in TiffTags.LIBTIFF_CORE:
  1658. if tag in TiffTags.TAGS_V2_GROUPS:
  1659. types[tag] = TiffTags.LONG8
  1660. elif tag in ifd.tagtype:
  1661. types[tag] = ifd.tagtype[tag]
  1662. elif isinstance(value, (int, float, str, bytes)) or (
  1663. isinstance(value, tuple)
  1664. and all(isinstance(v, (int, float, IFDRational)) for v in value)
  1665. ):
  1666. type = TiffTags.lookup(tag).type
  1667. if type:
  1668. types[tag] = type
  1669. if tag not in atts and tag not in blocklist:
  1670. if isinstance(value, str):
  1671. atts[tag] = value.encode("ascii", "replace") + b"\0"
  1672. elif isinstance(value, IFDRational):
  1673. atts[tag] = float(value)
  1674. else:
  1675. atts[tag] = value
  1676. if SAMPLEFORMAT in atts and len(atts[SAMPLEFORMAT]) == 1:
  1677. atts[SAMPLEFORMAT] = atts[SAMPLEFORMAT][0]
  1678. logger.debug("Converted items: %s", sorted(atts.items()))
  1679. # libtiff always expects the bytes in native order.
  1680. # we're storing image byte order. So, if the rawmode
  1681. # contains I;16, we need to convert from native to image
  1682. # byte order.
  1683. if im.mode in ("I;16", "I;16B", "I;16L"):
  1684. rawmode = "I;16N"
  1685. # Pass tags as sorted list so that the tags are set in a fixed order.
  1686. # This is required by libtiff for some tags. For example, the JPEGQUALITY
  1687. # pseudo tag requires that the COMPRESS tag was already set.
  1688. tags = list(atts.items())
  1689. tags.sort()
  1690. a = (rawmode, compression, _fp, filename, tags, types)
  1691. encoder = Image._getencoder(im.mode, "libtiff", a, encoderconfig)
  1692. encoder.setimage(im.im, (0, 0) + im.size)
  1693. while True:
  1694. errcode, data = encoder.encode(ImageFile.MAXBLOCK)[1:]
  1695. if not _fp:
  1696. fp.write(data)
  1697. if errcode:
  1698. break
  1699. if errcode < 0:
  1700. msg = f"encoder error {errcode} when writing image file"
  1701. raise OSError(msg)
  1702. else:
  1703. for tag in blocklist:
  1704. del ifd[tag]
  1705. offset = ifd.save(fp)
  1706. ImageFile._save(
  1707. im,
  1708. fp,
  1709. [ImageFile._Tile("raw", (0, 0) + im.size, offset, (rawmode, stride, 1))],
  1710. )
  1711. # -- helper for multi-page save --
  1712. if "_debug_multipage" in encoderinfo:
  1713. # just to access o32 and o16 (using correct byte order)
  1714. setattr(im, "_debug_multipage", ifd)
  1715. class AppendingTiffWriter(io.BytesIO):
  1716. fieldSizes = [
  1717. 0, # None
  1718. 1, # byte
  1719. 1, # ascii
  1720. 2, # short
  1721. 4, # long
  1722. 8, # rational
  1723. 1, # sbyte
  1724. 1, # undefined
  1725. 2, # sshort
  1726. 4, # slong
  1727. 8, # srational
  1728. 4, # float
  1729. 8, # double
  1730. 4, # ifd
  1731. 2, # unicode
  1732. 4, # complex
  1733. 8, # long8
  1734. ]
  1735. Tags = {
  1736. 273, # StripOffsets
  1737. 288, # FreeOffsets
  1738. 324, # TileOffsets
  1739. 519, # JPEGQTables
  1740. 520, # JPEGDCTables
  1741. 521, # JPEGACTables
  1742. }
  1743. def __init__(self, fn: StrOrBytesPath | IO[bytes], new: bool = False) -> None:
  1744. self.f: IO[bytes]
  1745. if is_path(fn):
  1746. self.name = fn
  1747. self.close_fp = True
  1748. try:
  1749. self.f = open(fn, "w+b" if new else "r+b")
  1750. except OSError:
  1751. self.f = open(fn, "w+b")
  1752. else:
  1753. self.f = cast(IO[bytes], fn)
  1754. self.close_fp = False
  1755. self.beginning = self.f.tell()
  1756. self.setup()
  1757. def setup(self) -> None:
  1758. # Reset everything.
  1759. self.f.seek(self.beginning, os.SEEK_SET)
  1760. self.whereToWriteNewIFDOffset: int | None = None
  1761. self.offsetOfNewPage = 0
  1762. self.IIMM = iimm = self.f.read(4)
  1763. self._bigtiff = b"\x2b" in iimm
  1764. if not iimm:
  1765. # empty file - first page
  1766. self.isFirst = True
  1767. return
  1768. self.isFirst = False
  1769. if iimm not in PREFIXES:
  1770. msg = "Invalid TIFF file header"
  1771. raise RuntimeError(msg)
  1772. self.setEndian("<" if iimm.startswith(II) else ">")
  1773. if self._bigtiff:
  1774. self.f.seek(4, os.SEEK_CUR)
  1775. self.skipIFDs()
  1776. self.goToEnd()
  1777. def finalize(self) -> None:
  1778. if self.isFirst:
  1779. return
  1780. # fix offsets
  1781. self.f.seek(self.offsetOfNewPage)
  1782. iimm = self.f.read(4)
  1783. if not iimm:
  1784. # Make it easy to finish a frame without committing to a new one.
  1785. return
  1786. if iimm != self.IIMM:
  1787. msg = "IIMM of new page doesn't match IIMM of first page"
  1788. raise RuntimeError(msg)
  1789. if self._bigtiff:
  1790. self.f.seek(4, os.SEEK_CUR)
  1791. ifd_offset = self._read(8 if self._bigtiff else 4)
  1792. ifd_offset += self.offsetOfNewPage
  1793. assert self.whereToWriteNewIFDOffset is not None
  1794. self.f.seek(self.whereToWriteNewIFDOffset)
  1795. self._write(ifd_offset, 8 if self._bigtiff else 4)
  1796. self.f.seek(ifd_offset)
  1797. self.fixIFD()
  1798. def newFrame(self) -> None:
  1799. # Call this to finish a frame.
  1800. self.finalize()
  1801. self.setup()
  1802. def __enter__(self) -> AppendingTiffWriter:
  1803. return self
  1804. def __exit__(self, *args: object) -> None:
  1805. if self.close_fp:
  1806. self.close()
  1807. def tell(self) -> int:
  1808. return self.f.tell() - self.offsetOfNewPage
  1809. def seek(self, offset: int, whence: int = io.SEEK_SET) -> int:
  1810. """
  1811. :param offset: Distance to seek.
  1812. :param whence: Whether the distance is relative to the start,
  1813. end or current position.
  1814. :returns: The resulting position, relative to the start.
  1815. """
  1816. if whence == os.SEEK_SET:
  1817. offset += self.offsetOfNewPage
  1818. self.f.seek(offset, whence)
  1819. return self.tell()
  1820. def goToEnd(self) -> None:
  1821. self.f.seek(0, os.SEEK_END)
  1822. pos = self.f.tell()
  1823. # pad to 16 byte boundary
  1824. pad_bytes = 16 - pos % 16
  1825. if 0 < pad_bytes < 16:
  1826. self.f.write(bytes(pad_bytes))
  1827. self.offsetOfNewPage = self.f.tell()
  1828. def setEndian(self, endian: str) -> None:
  1829. self.endian = endian
  1830. self.longFmt = f"{self.endian}L"
  1831. self.shortFmt = f"{self.endian}H"
  1832. self.tagFormat = f"{self.endian}HH" + ("Q" if self._bigtiff else "L")
  1833. def skipIFDs(self) -> None:
  1834. while True:
  1835. ifd_offset = self._read(8 if self._bigtiff else 4)
  1836. if ifd_offset == 0:
  1837. self.whereToWriteNewIFDOffset = self.f.tell() - (
  1838. 8 if self._bigtiff else 4
  1839. )
  1840. break
  1841. self.f.seek(ifd_offset)
  1842. num_tags = self._read(8 if self._bigtiff else 2)
  1843. self.f.seek(num_tags * (20 if self._bigtiff else 12), os.SEEK_CUR)
  1844. def write(self, data: Buffer, /) -> int:
  1845. return self.f.write(data)
  1846. def _fmt(self, field_size: int) -> str:
  1847. try:
  1848. return {2: "H", 4: "L", 8: "Q"}[field_size]
  1849. except KeyError:
  1850. msg = "offset is not supported"
  1851. raise RuntimeError(msg)
  1852. def _read(self, field_size: int) -> int:
  1853. (value,) = struct.unpack(
  1854. self.endian + self._fmt(field_size), self.f.read(field_size)
  1855. )
  1856. return value
  1857. def readShort(self) -> int:
  1858. return self._read(2)
  1859. def readLong(self) -> int:
  1860. return self._read(4)
  1861. @staticmethod
  1862. def _verify_bytes_written(bytes_written: int | None, expected: int) -> None:
  1863. if bytes_written is not None and bytes_written != expected:
  1864. msg = f"wrote only {bytes_written} bytes but wanted {expected}"
  1865. raise RuntimeError(msg)
  1866. def _rewriteLast(
  1867. self, value: int, field_size: int, new_field_size: int = 0
  1868. ) -> None:
  1869. self.f.seek(-field_size, os.SEEK_CUR)
  1870. if not new_field_size:
  1871. new_field_size = field_size
  1872. bytes_written = self.f.write(
  1873. struct.pack(self.endian + self._fmt(new_field_size), value)
  1874. )
  1875. self._verify_bytes_written(bytes_written, new_field_size)
  1876. def rewriteLastShortToLong(self, value: int) -> None:
  1877. self._rewriteLast(value, 2, 4)
  1878. def rewriteLastShort(self, value: int) -> None:
  1879. return self._rewriteLast(value, 2)
  1880. def rewriteLastLong(self, value: int) -> None:
  1881. return self._rewriteLast(value, 4)
  1882. def _write(self, value: int, field_size: int) -> None:
  1883. bytes_written = self.f.write(
  1884. struct.pack(self.endian + self._fmt(field_size), value)
  1885. )
  1886. self._verify_bytes_written(bytes_written, field_size)
  1887. def writeShort(self, value: int) -> None:
  1888. self._write(value, 2)
  1889. def writeLong(self, value: int) -> None:
  1890. self._write(value, 4)
  1891. def close(self) -> None:
  1892. self.finalize()
  1893. if self.close_fp:
  1894. self.f.close()
  1895. def fixIFD(self) -> None:
  1896. num_tags = self._read(8 if self._bigtiff else 2)
  1897. for i in range(num_tags):
  1898. tag, field_type, count = struct.unpack(
  1899. self.tagFormat, self.f.read(12 if self._bigtiff else 8)
  1900. )
  1901. field_size = self.fieldSizes[field_type]
  1902. total_size = field_size * count
  1903. fmt_size = 8 if self._bigtiff else 4
  1904. is_local = total_size <= fmt_size
  1905. if not is_local:
  1906. offset = self._read(fmt_size) + self.offsetOfNewPage
  1907. self._rewriteLast(offset, fmt_size)
  1908. if tag in self.Tags:
  1909. cur_pos = self.f.tell()
  1910. logger.debug(
  1911. "fixIFD: %s (%d) - type: %s (%d) - type size: %d - count: %d",
  1912. TiffTags.lookup(tag).name,
  1913. tag,
  1914. TYPES.get(field_type, "unknown"),
  1915. field_type,
  1916. field_size,
  1917. count,
  1918. )
  1919. if is_local:
  1920. self._fixOffsets(count, field_size)
  1921. self.f.seek(cur_pos + fmt_size)
  1922. else:
  1923. self.f.seek(offset)
  1924. self._fixOffsets(count, field_size)
  1925. self.f.seek(cur_pos)
  1926. elif is_local:
  1927. # skip the locally stored value that is not an offset
  1928. self.f.seek(fmt_size, os.SEEK_CUR)
  1929. def _fixOffsets(self, count: int, field_size: int) -> None:
  1930. for i in range(count):
  1931. offset = self._read(field_size)
  1932. offset += self.offsetOfNewPage
  1933. new_field_size = 0
  1934. if self._bigtiff and field_size in (2, 4) and offset >= 2**32:
  1935. # offset is now too large - we must convert long to long8
  1936. new_field_size = 8
  1937. elif field_size == 2 and offset >= 2**16:
  1938. # offset is now too large - we must convert short to long
  1939. new_field_size = 4
  1940. if new_field_size:
  1941. if count != 1:
  1942. msg = "not implemented"
  1943. raise RuntimeError(msg) # XXX TODO
  1944. # simple case - the offset is just one and therefore it is
  1945. # local (not referenced with another offset)
  1946. self._rewriteLast(offset, field_size, new_field_size)
  1947. # Move back past the new offset, past 'count', and before 'field_type'
  1948. rewind = -new_field_size - 4 - 2
  1949. self.f.seek(rewind, os.SEEK_CUR)
  1950. self.writeShort(new_field_size) # rewrite the type
  1951. self.f.seek(2 - rewind, os.SEEK_CUR)
  1952. else:
  1953. self._rewriteLast(offset, field_size)
  1954. def fixOffsets(
  1955. self, count: int, isShort: bool = False, isLong: bool = False
  1956. ) -> None:
  1957. if isShort:
  1958. field_size = 2
  1959. elif isLong:
  1960. field_size = 4
  1961. else:
  1962. field_size = 0
  1963. return self._fixOffsets(count, field_size)
  1964. def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
  1965. append_images = list(im.encoderinfo.get("append_images", []))
  1966. if not hasattr(im, "n_frames") and not append_images:
  1967. return _save(im, fp, filename)
  1968. cur_idx = im.tell()
  1969. try:
  1970. with AppendingTiffWriter(fp) as tf:
  1971. for ims in [im] + append_images:
  1972. encoderinfo = ims._attach_default_encoderinfo(im)
  1973. if not hasattr(ims, "encoderconfig"):
  1974. ims.encoderconfig = ()
  1975. nfr = getattr(ims, "n_frames", 1)
  1976. for idx in range(nfr):
  1977. ims.seek(idx)
  1978. ims.load()
  1979. _save(ims, tf, filename)
  1980. tf.newFrame()
  1981. ims.encoderinfo = encoderinfo
  1982. finally:
  1983. im.seek(cur_idx)
  1984. #
  1985. # --------------------------------------------------------------------
  1986. # Register
  1987. Image.register_open(TiffImageFile.format, TiffImageFile, _accept)
  1988. Image.register_save(TiffImageFile.format, _save)
  1989. Image.register_save_all(TiffImageFile.format, _save_all)
  1990. Image.register_extensions(TiffImageFile.format, [".tif", ".tiff"])
  1991. Image.register_mime(TiffImageFile.format, "image/tiff")