Guest User

Untitled

a guest
Jul 20th, 2018
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.11 KB | None | 0 0
  1. """
  2. \description TIFF file format dump
  3. \author paryan
  4. """
  5. from __future__ import print_function
  6. import argparse
  7. from struct import *
  8. import os
  9. import os.path as path
  10.  
  11. #
  12. # field (data) type
  13. # code -> (byte size, python struct module unpack code)
  14. #
  15. vtypes = {
  16. 12:(8,'d'), # DOUBLE double (IEEE 8-byte)
  17. 11:(4,'f'), # FLOAT float (IEEE 4-byte)
  18. 10:(8,'ii'), # SRATIONAL (int32, int32)
  19. 9:(4,'i'), # SLONG int32
  20. 8:(2,'h'), # SSHORT int16
  21. 7:(1,'c'), # UNDEFINED
  22. 6:(1,'b'), # SBYTE int8
  23. 5:(8,'II'), # RATIONAL (uint32, uint32)
  24. 4:(4,'I'), # LONG uint32
  25. 3:(2,'H'), # SHORT uint16
  26. 2:(-1,'c'), # ASCII uint8 (7-bit)
  27. 1:(1,'c') # BYTE uint8
  28. }
  29. fieldtype_label = {
  30. 0: "UNDEFINED",
  31. 1: "BYTE",
  32. 2: "ASCII",
  33. 3: "SHORT",
  34. 4: "LONG",
  35. 5: "RATIONAL",
  36. 6: "SBYTE",
  37. 7: "UNDEFINED",
  38. 8: "SSHORT",
  39. 9: "SLONG",
  40. 10: "SRATIONAL",
  41. 11: "FLOAT",
  42. 12: "DOUBLE",
  43. }
  44.  
  45. #
  46. # TIFF Tag dictionary
  47. # Ideally, int maps to tuple of name, and handler/reader or expected data type
  48. #
  49. tagdict = {
  50. 254: ("SubfileType"),# 0=Full, 1=Reduced resolution, 2=one page of many, 4=transparency mask
  51. 255: ("OldSubfileType"),# 1=full resolution image, 2=reduced image, 3=one page of many
  52. 256: ("ImageWidth"),
  53. 257: ("ImageLength"),
  54. 258: ("BitsPerSample"),
  55. 259: ("Compression"),
  56. # 1=None
  57. # 2=CCITT modified Huffman RLE
  58. # 3=CCITT Group 3 fax encoding (T.4)
  59. # 4=CCITT Group 4 fax encoding (T.6)
  60. # 5=LZW
  61. # 6=JPEG
  62. # 7=JPEG DCT
  63. # 9=TIFF/FX T.85 JBIG
  64. # 10=TIFF/FX T.43 Colour by layered JBIG
  65. # 32766=NeXT 2-bit RLE
  66. # 32771=#1 w/ word alignment (CCITRLEW)
  67. # 32773=Macintosh RLE (packbits)
  68. # 32809=Thunderscan RLE
  69. # 32946=Deflate
  70. # 8=Adobe Deflate
  71. # 34712=JPEG2000
  72. # 34925=LZMA2
  73. 262: ("PhotometricInterpretation"),
  74. # 0=min value is white
  75. # 1=min value is black
  76. # 2=RGB
  77. # 3=color map indexed (palette)
  78. # 4=mask
  79. # 5=color separation
  80. # 6=YCbCr (CCIR 601)
  81. # 8=CIE L*a*b*
  82. # 9=ICC L*a*b*
  83. 263: ("Thresholding"),
  84. # 1=bilevel
  85. # 2=halftone/dithered scan
  86. # 3=floyd-steinberg (error diffuse)
  87. 269: ("DocumentName"),
  88. 270: ("ImageDescription"),
  89. 271: ("Make"),
  90. 272: ("Model"),
  91. 273: ("StripOffsets"),
  92. 274: ("Orientation"),
  93. # 1=top left (normal)
  94. # 2=top right (mirror horizontal)
  95. # 3=bottom right (rotate 180)
  96. # 4=bottom left (mirror vertical)
  97. # 5=left top (row 0 lhs, col 0 top) mirror h rotate 270 CW
  98. # 6=right top (rotate90 cw)
  99. # 7=right bottom mirror h rotate 90 cw
  100. # 8=left bottom rotate 270 cw
  101. 277: ("SamplesPerPixel"),
  102. 278: ("RowsPerStrip"),
  103. 279: ("StripByteCounts"),
  104. 280: ("MinSampleValue"),
  105. 281: ("MaxSampleValue"),
  106. 282: ("XResolution"),
  107. 283: ("YResolution"),
  108. 284: ("PlanarConfiguration"), # 1=contiguous 2=separate planes
  109. 285: ("PageName"),
  110. 286: ("XPosition"),
  111. 287: ("YPosition"),
  112. 288: ("FreeOffsets"),
  113. 289: ("FreeByteCounts"),
  114. 290: ("GrayResponseUnit"),
  115. 291: ("GrayResponseCurve"),
  116. 296: ("ResolutionUnit"),
  117. # 1=None
  118. # 2=Inch
  119. # 3=cm (metric)
  120. 300: ("ColorResponseUnit"),
  121. 301: ("TransferFunction"),
  122. 305: ("Software"),
  123. 306: ("DateTime"),
  124. 315: ("Artist"),
  125. 316: ("HostComputer"),
  126. 317: ("Predictor"),# 1=None, 2=Horizontal, 3=Floating-point horizontal
  127. 318: ("WhitePoint"),
  128. 319: ("PrimaryChromaticities"),
  129. 320: ("ColorMap"),
  130. 322: ("TileWidth"), # tile width in pixels (cols)
  131. 323: ("TileLength"),# tile height in pixels (rows)
  132. 324: ("TileOffsets"),
  133. 325: ("TileByteCounts"),
  134. 330: ("SubIFD"),
  135. 332: ("InkSet"), # 1=CMYK 2=MultiInk (hi-fi)
  136. 333: ("InkNames"),
  137. 334: ("NumberOfInks"),
  138. 336: ("DotRange"),
  139. 337: ("TargetPrinter"),
  140. 338: ("ExtraSamples"), #0=Unspecified, 1=Associated alpha, 2=unassociated alpha
  141. 339: ("SampleFormat"),
  142. # 1=unsigned int
  143. # 2=signed int
  144. # 3=IEEE FP
  145. # 4=untyped (void)
  146. # 5=complex signed int
  147. # 6=complex IEEE FP
  148. 340: ("MinSampleValue"),
  149. 341: ("MaxSampleValue"),
  150. 346: ("Indexed"), # 0=not indexed, 1=indexed
  151. 351: ("OPIProxy"), # 0=no hi-res, 1=hi-res exists
  152.  
  153. 404: ("VersionYear"), #
  154. 405: ("ModeNumber"), #
  155.  
  156. 512: ("JPEGProcessingAlg"), # 1=Baseline, 14=Lossless
  157. 513: ("JPEGInterchangeFormat"),
  158. 514: ("JPEGInterchangeFormatLength"),
  159. 529: ("YCbCrCoefficients"),
  160. 530: ("YCbCrSubSampling"),
  161. 531: ("YCbCrPositioning"),
  162. 532: ("ReferenceBlackWhite"),
  163.  
  164. 700: ("XMP"),
  165.  
  166. 28672: ("SonyRawFileType"), #Sony ARW
  167. 28673: ("SonyUndocumented"), #Sony ARW
  168. 28688: ("SonyCurve"), #Sony ARW
  169.  
  170. 32997: ("ImageDepth"),
  171. 32998: ("TileDepth"),
  172. 33421: ("CFARepeatPatternDim"),
  173. 33422: ("CFAPattern"),
  174. 33432: ("Copyright"),
  175. 33434: ("ExposureTime"),
  176. 33437: ("FNumber"),
  177.  
  178. 33550: ("ModelPixelScaleTag"), #GeoTIFF
  179.  
  180. 33723: ("IPTC"),
  181.  
  182. 33920: ("IntegraphMatrixTag"), #IrasB
  183. 33922: ("ModelTiePointTag"), #GeoTIFF
  184.  
  185. 34019: ("RasterPadding"), # 0=Byte,1=Word,2=Long,9=Sector,10=Long Sector
  186. 34264: ("ModelTransformationTag"), #GeoTIFF
  187.  
  188. 34665: ("Exif"), # Exif IFD
  189. 34675: ("ICCProfile"),
  190.  
  191. 34732: ("ImageLayer"),
  192. 34735: ("GeoKeyDirectoryTag"), #GeoTIFF
  193. 34736: ("GeoDoubleParamsTag"), #GeoTIFF
  194. 34737: ("GeoAsciiParamsTag"), #GeoTIFF
  195.  
  196. 34850: ("ExposureProgram"),
  197. # 0=Undefined
  198. # 1=Manual
  199. # 2=Program AE
  200. # 3=Aperture-priority AE
  201. # 4=Shutter speed priority AE
  202. # 5=Creative(slow speed)
  203. # 6=Action(High speed)
  204. # 7=Portrait
  205. # 8=Landscape
  206. # 9=Bulb
  207. 34852: ("SpectralSensitivity"),
  208. 34853: ("GPSInfo"),# Sub IFD
  209.  
  210. 34855: ("ISOSpeedRatings"),
  211. 34856: ("OptoElectricConversionFactor"),
  212. 34857: ("Interlace"),
  213. 34858: ("TimeZoneOffset"),
  214. 34859: ("SelfTimeMode"),
  215.  
  216. 34864: ("SensitivityType"),
  217. 34865: ("StandardOutputSensitivity"),
  218. 34866: ("RecommendedExposureIndex"),
  219. 34867: ("ISOSpeed"),
  220. 34868: ("ISOSpeedLatitudeyyy"),
  221. 34869: ("ISOSpeedLatitudezzz"),
  222.  
  223. 36864: ("ExifVersion"),
  224. 36867: ("DateTimeOriginal"),
  225. 36868: ("DateTimeDigitized"),
  226.  
  227. 37121: ("ComponentsConfiguration"),
  228. 37122: ("CompressedBitsPerPixel"),
  229.  
  230. 37377: ("ShutterSpeedValue"),
  231. 37378: ("ApertureValue"),
  232. 37379: ("BrightnessValue"),
  233. 37380: ("ExposureBiasValue"),
  234. 37381: ("MaxApertureValue"),
  235. 37382: ("SubjectDistance"),
  236. 37383: ("MeteringMode"),
  237. 37384: ("LightSource"),
  238. #
  239. 37385: ("Flash"),
  240. 37386: ("FocalLength"),
  241. 37396: ("SubjectArea"),
  242. 37398: ("TIFF/EPStandardID"),
  243. 37399: ("SensingMethod"),
  244. 37500: ("MakerNote"),
  245. 37510: ("UserComment"),
  246. 37520: ("SubsecTime"),
  247. 37521: ("SubsecTimeOriginal"),
  248. 37522: ("SubsecTimeDigitized"),
  249.  
  250. 40960: ("FlashPixVersion"),
  251. 40961: ("ColorSpace"),
  252. 40962: ("PixelXDimension"),
  253. 40963: ("PixelYDimension"),
  254. 40964: ("RelatedSoundFile"),
  255. 40965: ("InteropOffset"),
  256.  
  257. 41483: ("FlashEnergy"),
  258. 41484: ("SpatialFreqResponse"),
  259. 41486: ("FocalPlaneXResolution"),
  260. 41487: ("FocalPlaneYResolution"),
  261. 41488: ("FocalPlaneResolutionUnit"),
  262.  
  263. 41492: ("SubjectLocation"),
  264. 41493: ("ExposureIndex"),
  265. 41495: ("SensingMethod"),
  266.  
  267. 41728: ("FileSource"),
  268. 41729: ("SceneType"),
  269. 41730: ("CFAPattern"),
  270.  
  271. 41985: ("CustomRendered"),
  272. 41986: ("ExposureMode"),
  273. 41987: ("WhiteBalance"),
  274. 41988: ("DigitalZoomRatio"),
  275. 41989: ("FocalLengthIn35mmFilm"),
  276. 41990: ("SceneCaptureType"),
  277. 41991: ("GainControl"),
  278. 41992: ("Contrast"),
  279. 41993: ("Saturation"),
  280. 41994: ("Sharpness"),
  281. 41995: ("DeviceSettingDescription"),
  282. 41996: ("SubjectDistanceRange"),
  283.  
  284. 42016: ("ImageUniqueID"),
  285. 42034: ("LensSpecification"), # minfocal, maxfocal, minFnumMinFocal, minFnumMaxFocal
  286. 42035: ("LensMake"),
  287. 42036: ("LensModel"),
  288. 42037: ("LensSerialNumber"),
  289.  
  290. 42112: ("GDAL_METADATA"),
  291. 42113: ("GDAL_NODATA"),
  292.  
  293. 42240: ("Gamma"),
  294.  
  295. 50706: ("DNGVersion"),
  296. 50708: ("UniqueCameraModel"),
  297. 50709: ("LocalizedCameraModel"),
  298. 50710: ("CFAPlaneColor"),
  299. 50711: ("CFALayout"),
  300.  
  301. 50341: ("PrintImageMatching"),
  302. 50740: ("DNGPrivateData"),
  303. 50828: ("OriginalRawFileData"),
  304. 50829: ("ActiveArea"),
  305.  
  306. 50936: ("ProfileName"),
  307. 50937: ("ProfileHueSatMapDims"),
  308. 50938: ("ProfileHueSatMapData1"),
  309. 50939: ("ProfileHueSatMapData2"),
  310. 50940: ("ProfileToneCurve"),
  311. 50941: ("ProfileEmbedPolicy"),
  312. 50942: ("ProfileCopyright"),
  313.  
  314. 50964: ("ForwardMatrix1"),
  315. 50965: ("ForwardMatrix2"),
  316. 50966: ("PreviewApplicationName"),
  317. 50967: ("PreviewApplicationVersion"),
  318. 50968: ("PreviewSettingsName"),
  319. 50969: ("PreviewSettingsDigest"),
  320. 50970: ("PreviewColorSpace"),
  321. 50971: ("PreviewDateTime"),
  322. 50972: ("RawImageDigest"),
  323. }
  324.  
  325. #
  326. # GPS specific tags on GPSInfo SubIFD
  327. #
  328. gps_tagdict = {
  329. 0: ("GPSVersionID"),
  330. 1: ("GPSLatitudeRef"),
  331. 2: ("GPSLatitude"),
  332. 3: ("GPSLongitudeRef"),
  333. 4: ("GPSLongitude"),
  334. 5: ("GPSAltitudeRef"),
  335. 6: ("GPSAltitude"),
  336. 7: ("GPSTimeStamp"),
  337. 8: ("GPSSatellites"),
  338. 9: ("GPSStatus"), # A=Active, V=Void
  339. 10: ("GPSMeasureMode"), # 2=2d, 3=3d
  340. 11: ("GPSDOP"),
  341. 12: ("GPSSpeedRef"), # K=kph, M=mph, N=knots
  342. 13: ("GPSSpeed"),
  343. 14: ("GPSTrackRef"), # M=Mag North, T=True North
  344. 15: ("GPSTrack"),
  345. 16: ("GPSImgDirectionRef"), # M=Mag North, T=True North
  346. 17: ("GPSImgDirection"),
  347. 18: ("GPSMapDatum"),
  348. 19: ("GPSDestLatitudeRef"), # N, S
  349. 20: ("GPSDestLatitude"),
  350. 21: ("GPSDestLongitudeRef"), # E,W
  351. 22: ("GPSDestLongitude"),
  352. 23: ("GPSDestBearingRef"), #M, T
  353. 24: ("GPSDestBearing"),
  354. 25: ("GPSDestDistanceRef"), # K,M, N
  355. 26: ("GPSDestDistance"),
  356. 27: ("GPSProcessingMethod"), # GPS, CELLID, WLAN, MANUAL
  357. 28: ("GPSAreaInformation"),
  358. 29: ("GPSDateStamp"), #YYYY:mm:dd
  359. 30: ("GPSDifferential"), # 1=Differential corrected
  360. 31: ("GPSHPositioningError"),
  361. }
  362.  
  363. makernote_nikon_tagdict = {
  364. 1: ("MakerNoteVersion"),# 0210=D60
  365. 2: ("ISO"),
  366. 3: ("ColorMode"),
  367. 4: ("Quality"),
  368. 5: ("WhiteBalance"),
  369. 6: ("Sharpness"),
  370. 7: ("FocusMode"),
  371. 8: ("FlashSetting"),
  372. 9: ("FlashType"),
  373. 11: ("WhiteBalanceFineTune"),
  374. 12: ("WB_RBLevels"),
  375. 13: ("ProgramShift"),
  376. 14: ("ExposureDifference"),
  377. 15: ("ISOSelection"),
  378. 16: ("DataDump"),
  379. 17: ("PreviewIFD"),
  380. 18: ("FlashExposureComp"),
  381. 19: ("ISOSetting"),
  382. 20: ("ColorBalanceA"),
  383. 22: ("ImageBoundary"),
  384. 23: ("ExternalFlashExposureComp"),
  385. 24: ("FlashExposureBracketValue"),
  386. 25: ("ExposureBracketValue"),
  387. 26: ("ImageProcessing"),
  388. 27: ("CropHighSpeed"),
  389. 28: ("ExposureTiming"),
  390. 29: ("SerialNumber"),
  391. 30: ("ColorSpace"),
  392. 31: ("VRInfo"),
  393. 32: ("ImageAuthentication"),
  394. 33: ("FaceDetect"),
  395. 34: ("Active D-Lighting"),
  396. 35: ("PictureControlData"),
  397. 36: ("WorldTime"),
  398. 37: ("ISOInfo"),
  399. 43: ("DistortInfo"),
  400. 131: ("LensType"),
  401. 132: ("Lens"),
  402. 133: ("ManualFocusDistance"),
  403. 134: ("DigitalZoom"),
  404. 135: ("FlashMode"),
  405. 136: ("AFInfo"),
  406. 137: ("ShootingMode"), # bitpos
  407. # :0 = continuous
  408. # :1 = delay
  409. # :2 = PC Control
  410. # :3 = Self-timer
  411. # :4 = Exposure Bracketing
  412. # :5 = Auto ISO
  413. # :6 = WB Bracketing
  414. # :7 = IR Control
  415. # :8 = D-Lighting Bracketing
  416. 149: ("NoiseReduction"),
  417. 153: ("RawImageCenter"),
  418. 154: ("SensorPixelSize"),
  419. 156: ("SceneAssist"),
  420. 158: ("RetouchHistory"),
  421. 160: ("SerialNumber"),
  422. 162: ("ImageDataSize"),
  423. 165: ("ImageCount"),
  424. 166: ("DeletedImageCount"),
  425. 167: ("ShutterCount"),
  426. 185: ("AFTune"),
  427. 187: ("RetouchInfo"),
  428. }
  429.  
  430. sony_tagdict = {
  431. 16: ("CameraInfo"),
  432. 32: ("FocusInfo"),
  433. 258: ("Quality"),
  434.  
  435. 8206: ("PictureEffect"), #0 single
  436. 8207: ("SoftSkinEffect"), #0 single
  437. 8241: ("SerialNumber"), #0 single
  438. 36875: ("FaceDetectSetting"), #0 single
  439. 45056: ("FileFormat"), #0 single
  440. 45057: ("SonyModelID"), #0 single
  441. 45088: ("CreativeStyle"), #0 single
  442. 45089: ("ColorTemperature"), #0 single
  443. 45090: ("ColorCompensationFilter"), # neg green, pos magenta
  444. 45091: ("SceneMode"), #0 single
  445. 45092: ("ZoneMatching"), #0 single
  446. 45093: ("DynamicRangeOptimizer"), #0 single
  447. 45094: ("ImageStabilization"), #0 single
  448. 45095: ("LensType"), #0 single
  449. 45097: ("ColorMode"), #0 single
  450. 45098: ("LensSpec"), #0 single
  451. 45099: ("FullImageSize"), #0 single
  452. 45100: ("PreviewImageSize"), #0 single
  453. 45129: ("ReleaseMode"), #0 single
  454. 45130: ("SequenceNumber"), #0 single
  455. 45138: ("IntelligentAuto"),
  456. 45140: ("WhiteBalance"),
  457. }
  458.  
  459. relative_offset = 0
  460. MAX_PRINT = 128
  461. MAX_EXCERPT = 16
  462. skipexif=False
  463. pause = False
  464.  
  465. # indexed by field type
  466. type_handler = {}
  467.  
  468. # indexed by tag
  469. tag_handler = {}
  470.  
  471. # indexed by tag
  472. type_posthandler = {}
  473.  
  474. def read_offset(f):
  475. return read_int(f)
  476.  
  477. def subifd_reader(f, ifd):
  478. #raw_input('>')
  479. voffsets = default_reader(f, ifd)
  480. cpos = f.tell()
  481. for i,voffset in enumerate(voffsets):
  482. f.seek(relative_offset+voffset)
  483. print("---SubIFD {} of {}".format(i+1, ifd['count']))
  484. while read_IFD(f):
  485. pass
  486. print("---End SubIFD")
  487. f.seek(cpos)
  488.  
  489. def nikon_lenstype_posthandler(content):
  490. ctype = ord(content[0])
  491. bincode = "{0:b}".format(ctype)[::-1]
  492. result = []
  493. if bincode[0] == '1': result.append('MF')
  494. if bincode[1] == '1': result.append('D')
  495. if bincode[2] == '1': result.append('G')
  496. if bincode[3] == '1': result.append('VR')
  497. print (" ".join(result))
  498.  
  499. def makernote_reader(f, ifd):
  500. print (default_reader(f, ifd)[:MAX_PRINT])
  501. #sony_makernote_reader(f, ifd)
  502.  
  503. def sony_makernote_reader(f, ifd):
  504. voffset = read_offset(f)
  505. current = f.tell()
  506. f.seek(relative_offset+voffset)
  507. #print(read_byte(f, 10))
  508. #print(read_short(f))
  509. read_IFD(f, read_IFD_entry, dict(td=sony_tagdict, tag={}, type=type_handler, post={}))
  510. f.seek(current)
  511. f.close()
  512. exit()
  513.  
  514. def nikon_makernote_reader(f, ifd):
  515. global endian, relative_offset
  516. old_endian = endian
  517. #print (default_reader(f, ifd)[:MAX_PRINT])
  518. voffset = read_offset(f)
  519. current = f.tell()
  520. f.seek(relative_offset+voffset)
  521. print(read_byte(f, 10))
  522. relative_offset = f.tell()
  523. endian = read_byteorder(f)
  524. print(read_short(f))
  525. print(read_int(f))
  526. raw_input('press <return>')
  527. nikon_posthandler = {
  528. 131: nikon_lenstype_posthandler
  529. }
  530. read_IFD(f, read_IFD_entry, dict(td=makernote_nikon_tagdict, tag={}, type=type_handler, post=nikon_posthandler))
  531.  
  532. f.seek(current)
  533. raw_input('press <return>')
  534.  
  535. endian = old_endian
  536. relative_offset=0
  537.  
  538. def exif_reader(f, ifd):
  539. print("EXIF")
  540. voffset = read_offset(f)
  541.  
  542. cpos = f.tell()
  543. f.seek(voffset)
  544. if not skipexif:
  545. read_IFD(f)
  546. else:
  547. print(voffset)
  548. f.seek(cpos)
  549.  
  550. def gpsinfo_reader(f, ifd):
  551. print("GPS")
  552. voffset = read_offset(f)
  553.  
  554. cpos = f.tell()
  555. f.seek(voffset)
  556. if not skipexif:
  557. read_IFD(f, read_IFD_entry, dict(td=gps_tagdict, tag={}, type=type_handler, post={}))
  558. else:
  559. print(voffset)
  560. f.seek(cpos)
  561.  
  562. def default_reader(f, ifd):
  563. #print(endian+ifd['pycode']*ifd['count'])
  564. is_offset = ifd['bytesize'] > 4 or ifd['bytesize'] <= 0
  565. is_padding = ifd['bytesize']<4
  566.  
  567. if is_offset:
  568. offset = read_offset(f)
  569. current = f.tell()
  570. f.seek(relative_offset+offset)
  571.  
  572. if not is_offset and is_padding:
  573. remaining = 4-ifd['bytesize']
  574. try:
  575. content = unpack(endian+ifd['pycode']*ifd['count']+'x'*remaining, f.read(4))
  576. except:
  577. print(remaining, endian+ifd['pycode']+'x'*remaining)
  578. exit(1)
  579. else:
  580. content = unpack(endian+ifd['pycode']*ifd['count'], f.read(ifd['bytesize']))
  581.  
  582. if is_offset:
  583. f.seek(current)
  584.  
  585. return content
  586.  
  587. def read_byte(f, n=1):
  588. if n==1:
  589. return unpack(endian+'c', f.read(1))[0]
  590. else:
  591. return unpack(endian+'c'*n, f.read(n))
  592.  
  593. def read_short(f, n=1):
  594. if n==1:
  595. return unpack(endian+'H', f.read(2))[0]
  596. else:
  597. return unpack(endian+'H'*n, f.read(2*n))
  598.  
  599. def read_int(f, n=1):
  600. if n==1:
  601. return unpack(endian+'I', f.read(4))[0]
  602. else:
  603. return unpack(endian+'I'*n, f.read(4*n))
  604.  
  605. def read_string(f, encoding="ascii"):
  606. tmp = []
  607. scode = 'c'
  608. while True:
  609. try:
  610. cc = unpack(scode, f.read(calcsize(scode)))[0]
  611. if(cc== b'\x00'):
  612. break
  613. except:
  614. break
  615. tmp.append(cc.decode(encoding))
  616. content = repr("".join(tmp))
  617. return content
  618.  
  619. def string_reader(f, ifd):
  620. # 2
  621. offset = read_offset(f)
  622. current = f.tell()
  623. f.seek(relative_offset+offset)
  624. content = read_string(f)
  625. f.seek(current)
  626. return content
  627.  
  628. def skip_posthandler(content):
  629. print("SKIPPED")
  630. pass
  631.  
  632. def photointerp_posthandler(content):
  633. sftype = content[0]
  634. if sftype == 0: type_text = "White is zero"
  635. elif sftype == 1: type_text = "Black is zero"
  636. elif sftype == 2: type_text = "RGB"
  637. elif sftype == 3: type_text = "RGB Palette"
  638. elif sftype == 4: type_text = "Transparency mask"
  639. elif sftype == 5: type_text = "CMYK"
  640. elif sftype == 6: type_text = "YCbCr"
  641. elif sftype == 8: type_text = "CIE L*a*b*"
  642. elif sftype == 9: type_text = "ICC L*a*b*"
  643. elif sftype == 10: type_text = "ITU L*a*b*"
  644. elif sftype == 32803: type_text = "Color Filter Array"
  645. elif sftype == 34892: type_text = "Linear Raw"
  646. else: type_text = "unknown"
  647. print ("{}({})".format(sftype, type_text))
  648.  
  649. def subfiletype_posthandler(content):
  650. sftype = content[0]
  651. if sftype == 0: type_text = "Full resolution image"
  652. elif sftype == 1: type_text = "Reduced resolution image"
  653. elif sftype == 2: type_text = "one page of multi-page"
  654. elif sftype == 3: type_text = "one page of multi-page reduced"
  655. elif sftype == 4: type_text = "transparency mask"
  656. elif sftype == 5: type_text = "transparency mask of reduced resolution image"
  657. elif sftype == 6: type_text = "transparency mask of multi-page image"
  658. elif sftype == 7: type_text = "transparency mask of multi-page reduced"
  659. else: type_text = "unknown"
  660. print ("{}({})".format(sftype, type_text))
  661.  
  662. def samplefmt_posthandler(content):
  663. sftype = content[0]
  664. if sftype == 1: type_text = "Unsigned"
  665. elif sftype == 2: type_text = "Signed"
  666. elif sftype == 3: type_text = "Float"
  667. elif sftype == 4: type_text = "Undefined"
  668. elif sftype == 5: type_text = "Complex int"
  669. elif sftype == 6: type_text = "Complex float"
  670. else: type_text = "unknown"
  671. print ("{}({})".format(sftype, type_text))
  672.  
  673. def compression_posthandler(content):
  674. ctype = content[0]
  675. label = "unknown compression type"
  676. # 1=None
  677. # 2=CCITT modified Huffman RLE
  678. # 3=CCITT Group 3 fax encoding (T.4)
  679. # 4=CCITT Group 4 fax encoding (T.6)
  680. # 5=LZW
  681. # 6=JPEG
  682. # 7=JPEG DCT
  683. # 9=TIFF/FX T.85 JBIG
  684. # 10=TIFF/FX T.43 Colour by layered JBIG
  685. # 32766=NeXT 2-bit RLE
  686. # 32767=Sony ARW
  687. # 32769=Packed RAW
  688. # 32771=#1 w/ word alignment (CCITRLEW)
  689. # 32773=Macintosh RLE (packbits)
  690. # 32809=Thunderscan RLE
  691. # 32946=Deflate
  692. # 8=Adobe Deflate
  693. # 34712=JPEG2000
  694. # 34925=LZMA2
  695. if ctype == 1: label = "Uncompressed"
  696. elif ctype == 5: label = "LZW"
  697. elif ctype in [6,7,99]: label = "JPEG"
  698. elif ctype == 32767: label = "Sony ARW"
  699. elif ctype == 32769: label = "Packed RAW"
  700. elif ctype == 32770: label = "Samsung SRW"
  701. elif ctype == 34713: label = "Nikon NEF"
  702. print("{}({})".format(ctype, label))
  703.  
  704. def planarconfig_posthandler(content):
  705. ctype = content[0]
  706. if ctype == 0: label = "Contiguous"
  707. elif ctype == 1: label = "Planar"
  708. print("{}({})".format(ctype, label))
  709.  
  710. def resunit_posthandler(content):
  711. ctype = content[0]
  712. label = "None"
  713. # 1=None
  714. if ctype == 2:
  715. label = "inch"
  716. elif ctype == 3:
  717. label = "centimeter"
  718. print("{}({})".format(ctype, label))
  719.  
  720. def read_IFD_entry(f, handler):
  721. # Bytes 0-1 The Tag that identifies the field
  722. # Bytes 2-3 The field Type
  723.  
  724. # field Tag, field Type
  725. tag, vtype = unpack(endian+'HH', f.read(4))
  726.  
  727. if tag in handler['td']:
  728. #known Tag type
  729. print("{} ({})".format(tag, handler['td'][tag]))
  730. else:
  731. print("{} (Unknown Tag)".format(tag))
  732.  
  733. # Bytes 4-7 The number of values, 'Count' of the indicated type
  734. vcount = unpack(endian+'i', f.read(4))[0]
  735. print("value count: {}\tType:{}({})".format(vcount, vtype, fieldtype_label[vtype]))
  736.  
  737. if vtype==0:
  738. print("Unknown data type '{}', skipping".format(vtype))
  739. return
  740.  
  741. # estimate data size, if datasize > 4-byte then the value contains offset instead of value
  742. tsize,tcode = vtypes[vtype]
  743. datasize = tsize*vcount
  744.  
  745. ifd_entry_info = dict(tag=tag, type=vtype, count=vcount, pycode=tcode, elemsize=tsize, bytesize=datasize)
  746.  
  747. # tag require special bytestream reader
  748. if tag in handler['tag']:
  749. return handler['tag'][tag](f, ifd_entry_info)
  750.  
  751. if vtype in handler['type']:
  752. # bytestream extraction of type requires preprocessing or padding
  753. content = handler['type'][vtype](f, ifd_entry_info)
  754. else:
  755. content = default_reader(f, ifd_entry_info)
  756.  
  757. if tag in handler['post']:
  758. handler['post'][tag](content)
  759. else:
  760. if(vcount)<MAX_PRINT:
  761. print("value: ", content)
  762. else:
  763. print("excerpt: ", content[:MAX_EXCERPT], '...')
  764.  
  765.  
  766. def read_IFD(f, entry_fn=read_IFD_entry, entry_handler=dict(td=tagdict, tag=tag_handler, type=type_handler, post=type_posthandler)):
  767. print("--------------------------BEGIN IFD")
  768. print(f.tell())
  769.  
  770. # num IFD
  771. num_ifd = unpack(endian+'H', f.read(2))[0]
  772. if num_ifd==0: print("0 IFD entries")
  773. for i in range(num_ifd):
  774. #IFD entries
  775. print("\nIFD #{} of {}\toffset:{}".format(i+1, num_ifd, f.tell()))
  776. entry_fn(f, entry_handler)
  777.  
  778. if pause:
  779. print()
  780. inp = raw_input("press <return> to continue >")
  781. if inp.lower() in ['q', 'quit', 'exit']:
  782. return False
  783.  
  784. tmp = unpack(endian+'I', f.read(4))[0]
  785. print("--------------------------END IFD. Next : ", tmp)
  786. if tmp != 0:
  787. f.seek(relative_offset+tmp)
  788. return tmp!=0
  789.  
  790. def read_byteorder(f):
  791. tmp = "".join([b.decode("utf-8") for b in unpack("cc", f.read(2))])
  792. if tmp=="II":
  793. _endian = "<"
  794. print("little-endian")
  795. else:
  796. _endian = ">"
  797. print("big-endian")
  798. return _endian
  799.  
  800. def init_handlers():
  801. """ populate default handlers """
  802.  
  803. #data type-specific reader
  804. type_handler[2] = string_reader
  805.  
  806. #tag-specific
  807. tag_handler[330] = subifd_reader
  808. tag_handler[34665] = exif_reader
  809. tag_handler[34853] = gpsinfo_reader
  810. tag_handler[34893] = subifd_reader
  811. tag_handler[37500] = makernote_reader
  812.  
  813. #existing data types, but requires post-processing
  814. type_posthandler[254] = subfiletype_posthandler
  815. type_posthandler[259] = compression_posthandler
  816. type_posthandler[262] = photointerp_posthandler
  817. type_posthandler[284] = planarconfig_posthandler
  818. type_posthandler[296] = resunit_posthandler
  819. type_posthandler[324] = skip_posthandler
  820. type_posthandler[325] = skip_posthandler
  821. type_posthandler[339] = samplefmt_posthandler
  822.  
  823. #type_posthandler[34735] = geokey_posthandler
  824.  
  825. if __name__=="__main__":
  826. parser = argparse.ArgumentParser()
  827. parser.add_argument('inputfile', nargs=1)
  828. parser.add_argument('-pause', help='pause on each display of IFD entry', action='store_true', default=False)
  829. parser.add_argument('-skipexif', help='do not read exif sub IFD', action='store_true', default=False)
  830. parser.add_argument('-maxlen', help='maximum length of array element to display', type=int, default=MAX_PRINT)
  831. parser.add_argument('-exlen', help='maximum length of displayed excerpt of array elements', type=int, default=MAX_EXCERPT)
  832. args = parser.parse_args()
  833.  
  834. if not path.exists(args.inputfile[0]):
  835. exit("file not found")
  836.  
  837. pause = args.pause
  838. skipexif = args.skipexif
  839.  
  840. MAX_PRINT = args.maxlen
  841. MAX_EXCERPT = args.exlen
  842.  
  843. filename = args.inputfile[0]
  844. base, ext = path.splitext(filename)
  845.  
  846. init_handlers()
  847.  
  848. with open(filename, "rb") as f:
  849. current = f.tell()
  850. f.seek(0, os.SEEK_END)
  851. fsize = f.tell()
  852. print('file size: ', fsize)
  853. f.seek(current)
  854. #
  855. # Byte 0-1 endianness
  856. #
  857. endian = read_byteorder(f)
  858.  
  859. #
  860. # Byte 2-3 TIFF Identifier
  861. #
  862. tmp = unpack(endian+'H', f.read(2))[0]
  863. print("TIFF Identifier: 42 = ", tmp)
  864. assert(tmp==42)
  865.  
  866. # offset of the first IFD, usually 0
  867. tmp = unpack(endian+'I', f.read(4))[0]
  868. print("Offset of 1st IFD : {} bytes\ncur. offset: {}".format(tmp, f.tell()))
  869. if(tmp != 0 and tmp != f.tell() and tmp<fsize):
  870. f.seek(tmp)
  871.  
  872. while read_IFD(f):
  873. pass
Add Comment
Please, Sign In to add comment