|
@@ -0,0 +1,2320 @@
|
|
|
|
+// @ts-nocheck
|
|
|
|
+// 源于piexifjs
|
|
|
|
+import { cloneDeep } from '../cloneDeep'
|
|
|
|
+import { isString } from '../isString'
|
|
|
|
+const TAGS = {
|
|
|
|
+ 'Image': {
|
|
|
|
+ 11: {
|
|
|
|
+ 'name': 'ProcessingSoftware',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 254: {
|
|
|
|
+ 'name': 'NewSubfileType',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 255: {
|
|
|
|
+ 'name': 'SubfileType',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 256: {
|
|
|
|
+ 'name': 'ImageWidth',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 257: {
|
|
|
|
+ 'name': 'ImageLength',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 258: {
|
|
|
|
+ 'name': 'BitsPerSample',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 259: {
|
|
|
|
+ 'name': 'Compression',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 262: {
|
|
|
|
+ 'name': 'PhotometricInterpretation',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 263: {
|
|
|
|
+ 'name': 'Threshholding',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 264: {
|
|
|
|
+ 'name': 'CellWidth',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 265: {
|
|
|
|
+ 'name': 'CellLength',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 266: {
|
|
|
|
+ 'name': 'FillOrder',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 269: {
|
|
|
|
+ 'name': 'DocumentName',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 270: {
|
|
|
|
+ 'name': 'ImageDescription',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 271: {
|
|
|
|
+ 'name': 'Make',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 272: {
|
|
|
|
+ 'name': 'Model',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 273: {
|
|
|
|
+ 'name': 'StripOffsets',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 274: {
|
|
|
|
+ 'name': 'Orientation',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 277: {
|
|
|
|
+ 'name': 'SamplesPerPixel',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 278: {
|
|
|
|
+ 'name': 'RowsPerStrip',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 279: {
|
|
|
|
+ 'name': 'StripByteCounts',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 282: {
|
|
|
|
+ 'name': 'XResolution',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 283: {
|
|
|
|
+ 'name': 'YResolution',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 284: {
|
|
|
|
+ 'name': 'PlanarConfiguration',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 290: {
|
|
|
|
+ 'name': 'GrayResponseUnit',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 291: {
|
|
|
|
+ 'name': 'GrayResponseCurve',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 292: {
|
|
|
|
+ 'name': 'T4Options',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 293: {
|
|
|
|
+ 'name': 'T6Options',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 296: {
|
|
|
|
+ 'name': 'ResolutionUnit',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 301: {
|
|
|
|
+ 'name': 'TransferFunction',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 305: {
|
|
|
|
+ 'name': 'Software',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 306: {
|
|
|
|
+ 'name': 'DateTime',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 315: {
|
|
|
|
+ 'name': 'Artist',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 316: {
|
|
|
|
+ 'name': 'HostComputer',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 317: {
|
|
|
|
+ 'name': 'Predictor',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 318: {
|
|
|
|
+ 'name': 'WhitePoint',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 319: {
|
|
|
|
+ 'name': 'PrimaryChromaticities',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 320: {
|
|
|
|
+ 'name': 'ColorMap',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 321: {
|
|
|
|
+ 'name': 'HalftoneHints',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 322: {
|
|
|
|
+ 'name': 'TileWidth',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 323: {
|
|
|
|
+ 'name': 'TileLength',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 324: {
|
|
|
|
+ 'name': 'TileOffsets',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 325: {
|
|
|
|
+ 'name': 'TileByteCounts',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 330: {
|
|
|
|
+ 'name': 'SubIFDs',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 332: {
|
|
|
|
+ 'name': 'InkSet',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 333: {
|
|
|
|
+ 'name': 'InkNames',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 334: {
|
|
|
|
+ 'name': 'NumberOfInks',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 336: {
|
|
|
|
+ 'name': 'DotRange',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 337: {
|
|
|
|
+ 'name': 'TargetPrinter',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 338: {
|
|
|
|
+ 'name': 'ExtraSamples',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 339: {
|
|
|
|
+ 'name': 'SampleFormat',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 340: {
|
|
|
|
+ 'name': 'SMinSampleValue',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 341: {
|
|
|
|
+ 'name': 'SMaxSampleValue',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 342: {
|
|
|
|
+ 'name': 'TransferRange',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 343: {
|
|
|
|
+ 'name': 'ClipPath',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 344: {
|
|
|
|
+ 'name': 'XClipPathUnits',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 345: {
|
|
|
|
+ 'name': 'YClipPathUnits',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 346: {
|
|
|
|
+ 'name': 'Indexed',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 347: {
|
|
|
|
+ 'name': 'JPEGTables',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 351: {
|
|
|
|
+ 'name': 'OPIProxy',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 512: {
|
|
|
|
+ 'name': 'JPEGProc',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 513: {
|
|
|
|
+ 'name': 'JPEGInterchangeFormat',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 514: {
|
|
|
|
+ 'name': 'JPEGInterchangeFormatLength',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 515: {
|
|
|
|
+ 'name': 'JPEGRestartInterval',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 517: {
|
|
|
|
+ 'name': 'JPEGLosslessPredictors',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 518: {
|
|
|
|
+ 'name': 'JPEGPointTransforms',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 519: {
|
|
|
|
+ 'name': 'JPEGQTables',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 520: {
|
|
|
|
+ 'name': 'JPEGDCTables',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 521: {
|
|
|
|
+ 'name': 'JPEGACTables',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 529: {
|
|
|
|
+ 'name': 'YCbCrCoefficients',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 530: {
|
|
|
|
+ 'name': 'YCbCrSubSampling',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 531: {
|
|
|
|
+ 'name': 'YCbCrPositioning',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 532: {
|
|
|
|
+ 'name': 'ReferenceBlackWhite',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 700: {
|
|
|
|
+ 'name': 'XMLPacket',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 18246: {
|
|
|
|
+ 'name': 'Rating',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 18249: {
|
|
|
|
+ 'name': 'RatingPercent',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 32781: {
|
|
|
|
+ 'name': 'ImageID',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 33421: {
|
|
|
|
+ 'name': 'CFARepeatPatternDim',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 33422: {
|
|
|
|
+ 'name': 'CFAPattern',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 33423: {
|
|
|
|
+ 'name': 'BatteryLevel',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 33432: {
|
|
|
|
+ 'name': 'Copyright',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 33434: {
|
|
|
|
+ 'name': 'ExposureTime',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 34377: {
|
|
|
|
+ 'name': 'ImageResources',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 34665: {
|
|
|
|
+ 'name': 'ExifTag',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 34675: {
|
|
|
|
+ 'name': 'InterColorProfile',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 34853: {
|
|
|
|
+ 'name': 'GPSTag',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 34857: {
|
|
|
|
+ 'name': 'Interlace',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 34858: {
|
|
|
|
+ 'name': 'TimeZoneOffset',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 34859: {
|
|
|
|
+ 'name': 'SelfTimerMode',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 37387: {
|
|
|
|
+ 'name': 'FlashEnergy',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 37388: {
|
|
|
|
+ 'name': 'SpatialFrequencyResponse',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 37389: {
|
|
|
|
+ 'name': 'Noise',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 37390: {
|
|
|
|
+ 'name': 'FocalPlaneXResolution',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 37391: {
|
|
|
|
+ 'name': 'FocalPlaneYResolution',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 37392: {
|
|
|
|
+ 'name': 'FocalPlaneResolutionUnit',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 37393: {
|
|
|
|
+ 'name': 'ImageNumber',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 37394: {
|
|
|
|
+ 'name': 'SecurityClassification',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 37395: {
|
|
|
|
+ 'name': 'ImageHistory',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 37397: {
|
|
|
|
+ 'name': 'ExposureIndex',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 37398: {
|
|
|
|
+ 'name': 'TIFFEPStandardID',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 37399: {
|
|
|
|
+ 'name': 'SensingMethod',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 40091: {
|
|
|
|
+ 'name': 'XPTitle',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 40092: {
|
|
|
|
+ 'name': 'XPComment',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 40093: {
|
|
|
|
+ 'name': 'XPAuthor',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 40094: {
|
|
|
|
+ 'name': 'XPKeywords',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 40095: {
|
|
|
|
+ 'name': 'XPSubject',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50341: {
|
|
|
|
+ 'name': 'PrintImageMatching',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 50706: {
|
|
|
|
+ 'name': 'DNGVersion',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50707: {
|
|
|
|
+ 'name': 'DNGBackwardVersion',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50708: {
|
|
|
|
+ 'name': 'UniqueCameraModel',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 50709: {
|
|
|
|
+ 'name': 'LocalizedCameraModel',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50710: {
|
|
|
|
+ 'name': 'CFAPlaneColor',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50711: {
|
|
|
|
+ 'name': 'CFALayout',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50712: {
|
|
|
|
+ 'name': 'LinearizationTable',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50713: {
|
|
|
|
+ 'name': 'BlackLevelRepeatDim',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50714: {
|
|
|
|
+ 'name': 'BlackLevel',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50715: {
|
|
|
|
+ 'name': 'BlackLevelDeltaH',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50716: {
|
|
|
|
+ 'name': 'BlackLevelDeltaV',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50717: {
|
|
|
|
+ 'name': 'WhiteLevel',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50718: {
|
|
|
|
+ 'name': 'DefaultScale',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50719: {
|
|
|
|
+ 'name': 'DefaultCropOrigin',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50720: {
|
|
|
|
+ 'name': 'DefaultCropSize',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50721: {
|
|
|
|
+ 'name': 'ColorMatrix1',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50722: {
|
|
|
|
+ 'name': 'ColorMatrix2',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50723: {
|
|
|
|
+ 'name': 'CameraCalibration1',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50724: {
|
|
|
|
+ 'name': 'CameraCalibration2',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50725: {
|
|
|
|
+ 'name': 'ReductionMatrix1',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50726: {
|
|
|
|
+ 'name': 'ReductionMatrix2',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50727: {
|
|
|
|
+ 'name': 'AnalogBalance',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50728: {
|
|
|
|
+ 'name': 'AsShotNeutral',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50729: {
|
|
|
|
+ 'name': 'AsShotWhiteXY',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50730: {
|
|
|
|
+ 'name': 'BaselineExposure',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50731: {
|
|
|
|
+ 'name': 'BaselineNoise',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50732: {
|
|
|
|
+ 'name': 'BaselineSharpness',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50733: {
|
|
|
|
+ 'name': 'BayerGreenSplit',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 50734: {
|
|
|
|
+ 'name': 'LinearResponseLimit',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50735: {
|
|
|
|
+ 'name': 'CameraSerialNumber',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 50736: {
|
|
|
|
+ 'name': 'LensInfo',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50737: {
|
|
|
|
+ 'name': 'ChromaBlurRadius',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50738: {
|
|
|
|
+ 'name': 'AntiAliasStrength',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50739: {
|
|
|
|
+ 'name': 'ShadowScale',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50740: {
|
|
|
|
+ 'name': 'DNGPrivateData',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50741: {
|
|
|
|
+ 'name': 'MakerNoteSafety',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50778: {
|
|
|
|
+ 'name': 'CalibrationIlluminant1',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50779: {
|
|
|
|
+ 'name': 'CalibrationIlluminant2',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50780: {
|
|
|
|
+ 'name': 'BestQualityScale',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50781: {
|
|
|
|
+ 'name': 'RawDataUniqueID',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50827: {
|
|
|
|
+ 'name': 'OriginalRawFileName',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50828: {
|
|
|
|
+ 'name': 'OriginalRawFileData',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 50829: {
|
|
|
|
+ 'name': 'ActiveArea',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50830: {
|
|
|
|
+ 'name': 'MaskedAreas',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50831: {
|
|
|
|
+ 'name': 'AsShotICCProfile',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 50832: {
|
|
|
|
+ 'name': 'AsShotPreProfileMatrix',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50833: {
|
|
|
|
+ 'name': 'CurrentICCProfile',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 50834: {
|
|
|
|
+ 'name': 'CurrentPreProfileMatrix',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50879: {
|
|
|
|
+ 'name': 'ColorimetricReference',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 50931: {
|
|
|
|
+ 'name': 'CameraCalibrationSignature',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50932: {
|
|
|
|
+ 'name': 'ProfileCalibrationSignature',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50934: {
|
|
|
|
+ 'name': 'AsShotProfileName',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50935: {
|
|
|
|
+ 'name': 'NoiseReductionApplied',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 50936: {
|
|
|
|
+ 'name': 'ProfileName',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50937: {
|
|
|
|
+ 'name': 'ProfileHueSatMapDims',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 50938: {
|
|
|
|
+ 'name': 'ProfileHueSatMapData1',
|
|
|
|
+ 'type': 'Float'
|
|
|
|
+ },
|
|
|
|
+ 50939: {
|
|
|
|
+ 'name': 'ProfileHueSatMapData2',
|
|
|
|
+ 'type': 'Float'
|
|
|
|
+ },
|
|
|
|
+ 50940: {
|
|
|
|
+ 'name': 'ProfileToneCurve',
|
|
|
|
+ 'type': 'Float'
|
|
|
|
+ },
|
|
|
|
+ 50941: {
|
|
|
|
+ 'name': 'ProfileEmbedPolicy',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 50942: {
|
|
|
|
+ 'name': 'ProfileCopyright',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50964: {
|
|
|
|
+ 'name': 'ForwardMatrix1',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50965: {
|
|
|
|
+ 'name': 'ForwardMatrix2',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 50966: {
|
|
|
|
+ 'name': 'PreviewApplicationName',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50967: {
|
|
|
|
+ 'name': 'PreviewApplicationVersion',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50968: {
|
|
|
|
+ 'name': 'PreviewSettingsName',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50969: {
|
|
|
|
+ 'name': 'PreviewSettingsDigest',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 50970: {
|
|
|
|
+ 'name': 'PreviewColorSpace',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 50971: {
|
|
|
|
+ 'name': 'PreviewDateTime',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 50972: {
|
|
|
|
+ 'name': 'RawImageDigest',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 50973: {
|
|
|
|
+ 'name': 'OriginalRawFileDigest',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 50974: {
|
|
|
|
+ 'name': 'SubTileBlockSize',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 50975: {
|
|
|
|
+ 'name': 'RowInterleaveFactor',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 50981: {
|
|
|
|
+ 'name': 'ProfileLookTableDims',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 50982: {
|
|
|
|
+ 'name': 'ProfileLookTableData',
|
|
|
|
+ 'type': 'Float'
|
|
|
|
+ },
|
|
|
|
+ 51008: {
|
|
|
|
+ 'name': 'OpcodeList1',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 51009: {
|
|
|
|
+ 'name': 'OpcodeList2',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 51022: {
|
|
|
|
+ 'name': 'OpcodeList3',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ 'Exif': {
|
|
|
|
+ 33434: {
|
|
|
|
+ 'name': 'ExposureTime',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 33437: {
|
|
|
|
+ 'name': 'FNumber',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 34850: {
|
|
|
|
+ 'name': 'ExposureProgram',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 34852: {
|
|
|
|
+ 'name': 'SpectralSensitivity',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 34855: {
|
|
|
|
+ 'name': 'ISOSpeedRatings',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 34856: {
|
|
|
|
+ 'name': 'OECF',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 34864: {
|
|
|
|
+ 'name': 'SensitivityType',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 34865: {
|
|
|
|
+ 'name': 'StandardOutputSensitivity',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 34866: {
|
|
|
|
+ 'name': 'RecommendedExposureIndex',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 34867: {
|
|
|
|
+ 'name': 'ISOSpeed',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 34868: {
|
|
|
|
+ 'name': 'ISOSpeedLatitudeyyy',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 34869: {
|
|
|
|
+ 'name': 'ISOSpeedLatitudezzz',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 36864: {
|
|
|
|
+ 'name': 'ExifVersion',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 36867: {
|
|
|
|
+ 'name': 'DateTimeOriginal',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 36868: {
|
|
|
|
+ 'name': 'DateTimeDigitized',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 37121: {
|
|
|
|
+ 'name': 'ComponentsConfiguration',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 37122: {
|
|
|
|
+ 'name': 'CompressedBitsPerPixel',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 37377: {
|
|
|
|
+ 'name': 'ShutterSpeedValue',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 37378: {
|
|
|
|
+ 'name': 'ApertureValue',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 37379: {
|
|
|
|
+ 'name': 'BrightnessValue',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 37380: {
|
|
|
|
+ 'name': 'ExposureBiasValue',
|
|
|
|
+ 'type': 'SRational'
|
|
|
|
+ },
|
|
|
|
+ 37381: {
|
|
|
|
+ 'name': 'MaxApertureValue',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 37382: {
|
|
|
|
+ 'name': 'SubjectDistance',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 37383: {
|
|
|
|
+ 'name': 'MeteringMode',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 37384: {
|
|
|
|
+ 'name': 'LightSource',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 37385: {
|
|
|
|
+ 'name': 'Flash',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 37386: {
|
|
|
|
+ 'name': 'FocalLength',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 37396: {
|
|
|
|
+ 'name': 'SubjectArea',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 37500: {
|
|
|
|
+ 'name': 'MakerNote',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 37510: {
|
|
|
|
+ 'name': 'UserComment',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 37520: {
|
|
|
|
+ 'name': 'SubSecTime',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 37521: {
|
|
|
|
+ 'name': 'SubSecTimeOriginal',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 37522: {
|
|
|
|
+ 'name': 'SubSecTimeDigitized',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 40960: {
|
|
|
|
+ 'name': 'FlashpixVersion',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 40961: {
|
|
|
|
+ 'name': 'ColorSpace',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 40962: {
|
|
|
|
+ 'name': 'PixelXDimension',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 40963: {
|
|
|
|
+ 'name': 'PixelYDimension',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 40964: {
|
|
|
|
+ 'name': 'RelatedSoundFile',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 40965: {
|
|
|
|
+ 'name': 'InteroperabilityTag',
|
|
|
|
+ 'type': 'Long'
|
|
|
|
+ },
|
|
|
|
+ 41483: {
|
|
|
|
+ 'name': 'FlashEnergy',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 41484: {
|
|
|
|
+ 'name': 'SpatialFrequencyResponse',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 41486: {
|
|
|
|
+ 'name': 'FocalPlaneXResolution',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 41487: {
|
|
|
|
+ 'name': 'FocalPlaneYResolution',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 41488: {
|
|
|
|
+ 'name': 'FocalPlaneResolutionUnit',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41492: {
|
|
|
|
+ 'name': 'SubjectLocation',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41493: {
|
|
|
|
+ 'name': 'ExposureIndex',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 41495: {
|
|
|
|
+ 'name': 'SensingMethod',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41728: {
|
|
|
|
+ 'name': 'FileSource',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 41729: {
|
|
|
|
+ 'name': 'SceneType',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 41730: {
|
|
|
|
+ 'name': 'CFAPattern',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 41985: {
|
|
|
|
+ 'name': 'CustomRendered',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41986: {
|
|
|
|
+ 'name': 'ExposureMode',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41987: {
|
|
|
|
+ 'name': 'WhiteBalance',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41988: {
|
|
|
|
+ 'name': 'DigitalZoomRatio',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 41989: {
|
|
|
|
+ 'name': 'FocalLengthIn35mmFilm',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41990: {
|
|
|
|
+ 'name': 'SceneCaptureType',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41991: {
|
|
|
|
+ 'name': 'GainControl',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41992: {
|
|
|
|
+ 'name': 'Contrast',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41993: {
|
|
|
|
+ 'name': 'Saturation',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41994: {
|
|
|
|
+ 'name': 'Sharpness',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 41995: {
|
|
|
|
+ 'name': 'DeviceSettingDescription',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 41996: {
|
|
|
|
+ 'name': 'SubjectDistanceRange',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 42016: {
|
|
|
|
+ 'name': 'ImageUniqueID',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 42032: {
|
|
|
|
+ 'name': 'CameraOwnerName',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 42033: {
|
|
|
|
+ 'name': 'BodySerialNumber',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 42034: {
|
|
|
|
+ 'name': 'LensSpecification',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 42035: {
|
|
|
|
+ 'name': 'LensMake',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 42036: {
|
|
|
|
+ 'name': 'LensModel',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 42037: {
|
|
|
|
+ 'name': 'LensSerialNumber',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 42240: {
|
|
|
|
+ 'name': 'Gamma',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ 'GPS': {
|
|
|
|
+ 0: {
|
|
|
|
+ 'name': 'GPSVersionID',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 1: {
|
|
|
|
+ 'name': 'GPSLatitudeRef',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 2: {
|
|
|
|
+ 'name': 'GPSLatitude',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 3: {
|
|
|
|
+ 'name': 'GPSLongitudeRef',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 4: {
|
|
|
|
+ 'name': 'GPSLongitude',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 5: {
|
|
|
|
+ 'name': 'GPSAltitudeRef',
|
|
|
|
+ 'type': 'Byte'
|
|
|
|
+ },
|
|
|
|
+ 6: {
|
|
|
|
+ 'name': 'GPSAltitude',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 7: {
|
|
|
|
+ 'name': 'GPSTimeStamp',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 8: {
|
|
|
|
+ 'name': 'GPSSatellites',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 9: {
|
|
|
|
+ 'name': 'GPSStatus',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 10: {
|
|
|
|
+ 'name': 'GPSMeasureMode',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 11: {
|
|
|
|
+ 'name': 'GPSDOP',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 12: {
|
|
|
|
+ 'name': 'GPSSpeedRef',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 13: {
|
|
|
|
+ 'name': 'GPSSpeed',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 14: {
|
|
|
|
+ 'name': 'GPSTrackRef',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 15: {
|
|
|
|
+ 'name': 'GPSTrack',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 16: {
|
|
|
|
+ 'name': 'GPSImgDirectionRef',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 17: {
|
|
|
|
+ 'name': 'GPSImgDirection',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 18: {
|
|
|
|
+ 'name': 'GPSMapDatum',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 19: {
|
|
|
|
+ 'name': 'GPSDestLatitudeRef',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 20: {
|
|
|
|
+ 'name': 'GPSDestLatitude',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 21: {
|
|
|
|
+ 'name': 'GPSDestLongitudeRef',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 22: {
|
|
|
|
+ 'name': 'GPSDestLongitude',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 23: {
|
|
|
|
+ 'name': 'GPSDestBearingRef',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 24: {
|
|
|
|
+ 'name': 'GPSDestBearing',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 25: {
|
|
|
|
+ 'name': 'GPSDestDistanceRef',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 26: {
|
|
|
|
+ 'name': 'GPSDestDistance',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ },
|
|
|
|
+ 27: {
|
|
|
|
+ 'name': 'GPSProcessingMethod',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 28: {
|
|
|
|
+ 'name': 'GPSAreaInformation',
|
|
|
|
+ 'type': 'Undefined'
|
|
|
|
+ },
|
|
|
|
+ 29: {
|
|
|
|
+ 'name': 'GPSDateStamp',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ },
|
|
|
|
+ 30: {
|
|
|
|
+ 'name': 'GPSDifferential',
|
|
|
|
+ 'type': 'Short'
|
|
|
|
+ },
|
|
|
|
+ 31: {
|
|
|
|
+ 'name': 'GPSHPositioningError',
|
|
|
|
+ 'type': 'Rational'
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ 'Interop': {
|
|
|
|
+ 1: {
|
|
|
|
+ 'name': 'InteroperabilityIndex',
|
|
|
|
+ 'type': 'Ascii'
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+const TYPES = {
|
|
|
|
+ "Byte": 1,
|
|
|
|
+ "Ascii": 2,
|
|
|
|
+ "Short": 3,
|
|
|
|
+ "Long": 4,
|
|
|
|
+ "Rational": 5,
|
|
|
|
+ "Undefined": 7,
|
|
|
|
+ "SLong": 9,
|
|
|
|
+ "SRational": 10
|
|
|
|
+};
|
|
|
|
+TAGS["0th"] = TAGS["Image"];
|
|
|
|
+TAGS["1st"] = TAGS["Image"];
|
|
|
|
+class Piexif {
|
|
|
|
+ version = "1.0.4"
|
|
|
|
+ TAGS = TAGS
|
|
|
|
+ ImageIFD = {
|
|
|
|
+ ProcessingSoftware: 11,
|
|
|
|
+ NewSubfileType: 254,
|
|
|
|
+ SubfileType: 255,
|
|
|
|
+ ImageWidth: 256,
|
|
|
|
+ ImageLength: 257,
|
|
|
|
+ BitsPerSample: 258,
|
|
|
|
+ Compression: 259,
|
|
|
|
+ PhotometricInterpretation: 262,
|
|
|
|
+ Threshholding: 263,
|
|
|
|
+ CellWidth: 264,
|
|
|
|
+ CellLength: 265,
|
|
|
|
+ FillOrder: 266,
|
|
|
|
+ DocumentName: 269,
|
|
|
|
+ ImageDescription: 270,
|
|
|
|
+ Make: 271,
|
|
|
|
+ Model: 272,
|
|
|
|
+ StripOffsets: 273,
|
|
|
|
+ Orientation: 274,
|
|
|
|
+ SamplesPerPixel: 277,
|
|
|
|
+ RowsPerStrip: 278,
|
|
|
|
+ StripByteCounts: 279,
|
|
|
|
+ XResolution: 282,
|
|
|
|
+ YResolution: 283,
|
|
|
|
+ PlanarConfiguration: 284,
|
|
|
|
+ GrayResponseUnit: 290,
|
|
|
|
+ GrayResponseCurve: 291,
|
|
|
|
+ T4Options: 292,
|
|
|
|
+ T6Options: 293,
|
|
|
|
+ ResolutionUnit: 296,
|
|
|
|
+ TransferFunction: 301,
|
|
|
|
+ Software: 305,
|
|
|
|
+ DateTime: 306,
|
|
|
|
+ Artist: 315,
|
|
|
|
+ HostComputer: 316,
|
|
|
|
+ Predictor: 317,
|
|
|
|
+ WhitePoint: 318,
|
|
|
|
+ PrimaryChromaticities: 319,
|
|
|
|
+ ColorMap: 320,
|
|
|
|
+ HalftoneHints: 321,
|
|
|
|
+ TileWidth: 322,
|
|
|
|
+ TileLength: 323,
|
|
|
|
+ TileOffsets: 324,
|
|
|
|
+ TileByteCounts: 325,
|
|
|
|
+ SubIFDs: 330,
|
|
|
|
+ InkSet: 332,
|
|
|
|
+ InkNames: 333,
|
|
|
|
+ NumberOfInks: 334,
|
|
|
|
+ DotRange: 336,
|
|
|
|
+ TargetPrinter: 337,
|
|
|
|
+ ExtraSamples: 338,
|
|
|
|
+ SampleFormat: 339,
|
|
|
|
+ SMinSampleValue: 340,
|
|
|
|
+ SMaxSampleValue: 341,
|
|
|
|
+ TransferRange: 342,
|
|
|
|
+ ClipPath: 343,
|
|
|
|
+ XClipPathUnits: 344,
|
|
|
|
+ YClipPathUnits: 345,
|
|
|
|
+ Indexed: 346,
|
|
|
|
+ JPEGTables: 347,
|
|
|
|
+ OPIProxy: 351,
|
|
|
|
+ JPEGProc: 512,
|
|
|
|
+ JPEGInterchangeFormat: 513,
|
|
|
|
+ JPEGInterchangeFormatLength: 514,
|
|
|
|
+ JPEGRestartInterval: 515,
|
|
|
|
+ JPEGLosslessPredictors: 517,
|
|
|
|
+ JPEGPointTransforms: 518,
|
|
|
|
+ JPEGQTables: 519,
|
|
|
|
+ JPEGDCTables: 520,
|
|
|
|
+ JPEGACTables: 521,
|
|
|
|
+ YCbCrCoefficients: 529,
|
|
|
|
+ YCbCrSubSampling: 530,
|
|
|
|
+ YCbCrPositioning: 531,
|
|
|
|
+ ReferenceBlackWhite: 532,
|
|
|
|
+ XMLPacket: 700,
|
|
|
|
+ Rating: 18246,
|
|
|
|
+ RatingPercent: 18249,
|
|
|
|
+ ImageID: 32781,
|
|
|
|
+ CFARepeatPatternDim: 33421,
|
|
|
|
+ CFAPattern: 33422,
|
|
|
|
+ BatteryLevel: 33423,
|
|
|
|
+ Copyright: 33432,
|
|
|
|
+ ExposureTime: 33434,
|
|
|
|
+ ImageResources: 34377,
|
|
|
|
+ ExifTag: 34665,
|
|
|
|
+ InterColorProfile: 34675,
|
|
|
|
+ GPSTag: 34853,
|
|
|
|
+ Interlace: 34857,
|
|
|
|
+ TimeZoneOffset: 34858,
|
|
|
|
+ SelfTimerMode: 34859,
|
|
|
|
+ FlashEnergy: 37387,
|
|
|
|
+ SpatialFrequencyResponse: 37388,
|
|
|
|
+ Noise: 37389,
|
|
|
|
+ FocalPlaneXResolution: 37390,
|
|
|
|
+ FocalPlaneYResolution: 37391,
|
|
|
|
+ FocalPlaneResolutionUnit: 37392,
|
|
|
|
+ ImageNumber: 37393,
|
|
|
|
+ SecurityClassification: 37394,
|
|
|
|
+ ImageHistory: 37395,
|
|
|
|
+ ExposureIndex: 37397,
|
|
|
|
+ TIFFEPStandardID: 37398,
|
|
|
|
+ SensingMethod: 37399,
|
|
|
|
+ XPTitle: 40091,
|
|
|
|
+ XPComment: 40092,
|
|
|
|
+ XPAuthor: 40093,
|
|
|
|
+ XPKeywords: 40094,
|
|
|
|
+ XPSubject: 40095,
|
|
|
|
+ PrintImageMatching: 50341,
|
|
|
|
+ DNGVersion: 50706,
|
|
|
|
+ DNGBackwardVersion: 50707,
|
|
|
|
+ UniqueCameraModel: 50708,
|
|
|
|
+ LocalizedCameraModel: 50709,
|
|
|
|
+ CFAPlaneColor: 50710,
|
|
|
|
+ CFALayout: 50711,
|
|
|
|
+ LinearizationTable: 50712,
|
|
|
|
+ BlackLevelRepeatDim: 50713,
|
|
|
|
+ BlackLevel: 50714,
|
|
|
|
+ BlackLevelDeltaH: 50715,
|
|
|
|
+ BlackLevelDeltaV: 50716,
|
|
|
|
+ WhiteLevel: 50717,
|
|
|
|
+ DefaultScale: 50718,
|
|
|
|
+ DefaultCropOrigin: 50719,
|
|
|
|
+ DefaultCropSize: 50720,
|
|
|
|
+ ColorMatrix1: 50721,
|
|
|
|
+ ColorMatrix2: 50722,
|
|
|
|
+ CameraCalibration1: 50723,
|
|
|
|
+ CameraCalibration2: 50724,
|
|
|
|
+ ReductionMatrix1: 50725,
|
|
|
|
+ ReductionMatrix2: 50726,
|
|
|
|
+ AnalogBalance: 50727,
|
|
|
|
+ AsShotNeutral: 50728,
|
|
|
|
+ AsShotWhiteXY: 50729,
|
|
|
|
+ BaselineExposure: 50730,
|
|
|
|
+ BaselineNoise: 50731,
|
|
|
|
+ BaselineSharpness: 50732,
|
|
|
|
+ BayerGreenSplit: 50733,
|
|
|
|
+ LinearResponseLimit: 50734,
|
|
|
|
+ CameraSerialNumber: 50735,
|
|
|
|
+ LensInfo: 50736,
|
|
|
|
+ ChromaBlurRadius: 50737,
|
|
|
|
+ AntiAliasStrength: 50738,
|
|
|
|
+ ShadowScale: 50739,
|
|
|
|
+ DNGPrivateData: 50740,
|
|
|
|
+ MakerNoteSafety: 50741,
|
|
|
|
+ CalibrationIlluminant1: 50778,
|
|
|
|
+ CalibrationIlluminant2: 50779,
|
|
|
|
+ BestQualityScale: 50780,
|
|
|
|
+ RawDataUniqueID: 50781,
|
|
|
|
+ OriginalRawFileName: 50827,
|
|
|
|
+ OriginalRawFileData: 50828,
|
|
|
|
+ ActiveArea: 50829,
|
|
|
|
+ MaskedAreas: 50830,
|
|
|
|
+ AsShotICCProfile: 50831,
|
|
|
|
+ AsShotPreProfileMatrix: 50832,
|
|
|
|
+ CurrentICCProfile: 50833,
|
|
|
|
+ CurrentPreProfileMatrix: 50834,
|
|
|
|
+ ColorimetricReference: 50879,
|
|
|
|
+ CameraCalibrationSignature: 50931,
|
|
|
|
+ ProfileCalibrationSignature: 50932,
|
|
|
|
+ AsShotProfileName: 50934,
|
|
|
|
+ NoiseReductionApplied: 50935,
|
|
|
|
+ ProfileName: 50936,
|
|
|
|
+ ProfileHueSatMapDims: 50937,
|
|
|
|
+ ProfileHueSatMapData1: 50938,
|
|
|
|
+ ProfileHueSatMapData2: 50939,
|
|
|
|
+ ProfileToneCurve: 50940,
|
|
|
|
+ ProfileEmbedPolicy: 50941,
|
|
|
|
+ ProfileCopyright: 50942,
|
|
|
|
+ ForwardMatrix1: 50964,
|
|
|
|
+ ForwardMatrix2: 50965,
|
|
|
|
+ PreviewApplicationName: 50966,
|
|
|
|
+ PreviewApplicationVersion: 50967,
|
|
|
|
+ PreviewSettingsName: 50968,
|
|
|
|
+ PreviewSettingsDigest: 50969,
|
|
|
|
+ PreviewColorSpace: 50970,
|
|
|
|
+ PreviewDateTime: 50971,
|
|
|
|
+ RawImageDigest: 50972,
|
|
|
|
+ OriginalRawFileDigest: 50973,
|
|
|
|
+ SubTileBlockSize: 50974,
|
|
|
|
+ RowInterleaveFactor: 50975,
|
|
|
|
+ ProfileLookTableDims: 50981,
|
|
|
|
+ ProfileLookTableData: 50982,
|
|
|
|
+ OpcodeList1: 51008,
|
|
|
|
+ OpcodeList2: 51009,
|
|
|
|
+ OpcodeList3: 51022,
|
|
|
|
+ NoiseProfile: 51041,
|
|
|
|
+ }
|
|
|
|
+ ExifIFD = {
|
|
|
|
+ ExposureTime: 33434,
|
|
|
|
+ FNumber: 33437,
|
|
|
|
+ ExposureProgram: 34850,
|
|
|
|
+ SpectralSensitivity: 34852,
|
|
|
|
+ ISOSpeedRatings: 34855,
|
|
|
|
+ OECF: 34856,
|
|
|
|
+ SensitivityType: 34864,
|
|
|
|
+ StandardOutputSensitivity: 34865,
|
|
|
|
+ RecommendedExposureIndex: 34866,
|
|
|
|
+ ISOSpeed: 34867,
|
|
|
|
+ ISOSpeedLatitudeyyy: 34868,
|
|
|
|
+ ISOSpeedLatitudezzz: 34869,
|
|
|
|
+ ExifVersion: 36864,
|
|
|
|
+ DateTimeOriginal: 36867,
|
|
|
|
+ DateTimeDigitized: 36868,
|
|
|
|
+ ComponentsConfiguration: 37121,
|
|
|
|
+ CompressedBitsPerPixel: 37122,
|
|
|
|
+ ShutterSpeedValue: 37377,
|
|
|
|
+ ApertureValue: 37378,
|
|
|
|
+ BrightnessValue: 37379,
|
|
|
|
+ ExposureBiasValue: 37380,
|
|
|
|
+ MaxApertureValue: 37381,
|
|
|
|
+ SubjectDistance: 37382,
|
|
|
|
+ MeteringMode: 37383,
|
|
|
|
+ LightSource: 37384,
|
|
|
|
+ Flash: 37385,
|
|
|
|
+ FocalLength: 37386,
|
|
|
|
+ SubjectArea: 37396,
|
|
|
|
+ MakerNote: 37500,
|
|
|
|
+ UserComment: 37510,
|
|
|
|
+ SubSecTime: 37520,
|
|
|
|
+ SubSecTimeOriginal: 37521,
|
|
|
|
+ SubSecTimeDigitized: 37522,
|
|
|
|
+ FlashpixVersion: 40960,
|
|
|
|
+ ColorSpace: 40961,
|
|
|
|
+ PixelXDimension: 40962,
|
|
|
|
+ PixelYDimension: 40963,
|
|
|
|
+ RelatedSoundFile: 40964,
|
|
|
|
+ InteroperabilityTag: 40965,
|
|
|
|
+ FlashEnergy: 41483,
|
|
|
|
+ SpatialFrequencyResponse: 41484,
|
|
|
|
+ FocalPlaneXResolution: 41486,
|
|
|
|
+ FocalPlaneYResolution: 41487,
|
|
|
|
+ FocalPlaneResolutionUnit: 41488,
|
|
|
|
+ SubjectLocation: 41492,
|
|
|
|
+ ExposureIndex: 41493,
|
|
|
|
+ SensingMethod: 41495,
|
|
|
|
+ FileSource: 41728,
|
|
|
|
+ SceneType: 41729,
|
|
|
|
+ CFAPattern: 41730,
|
|
|
|
+ CustomRendered: 41985,
|
|
|
|
+ ExposureMode: 41986,
|
|
|
|
+ WhiteBalance: 41987,
|
|
|
|
+ DigitalZoomRatio: 41988,
|
|
|
|
+ FocalLengthIn35mmFilm: 41989,
|
|
|
|
+ SceneCaptureType: 41990,
|
|
|
|
+ GainControl: 41991,
|
|
|
|
+ Contrast: 41992,
|
|
|
|
+ Saturation: 41993,
|
|
|
|
+ Sharpness: 41994,
|
|
|
|
+ DeviceSettingDescription: 41995,
|
|
|
|
+ SubjectDistanceRange: 41996,
|
|
|
|
+ ImageUniqueID: 42016,
|
|
|
|
+ CameraOwnerName: 42032,
|
|
|
|
+ BodySerialNumber: 42033,
|
|
|
|
+ LensSpecification: 42034,
|
|
|
|
+ LensMake: 42035,
|
|
|
|
+ LensModel: 42036,
|
|
|
|
+ LensSerialNumber: 42037,
|
|
|
|
+ Gamma: 42240,
|
|
|
|
+ }
|
|
|
|
+ GPSIFD = {
|
|
|
|
+ GPSVersionID: 0,
|
|
|
|
+ GPSLatitudeRef: 1,
|
|
|
|
+ GPSLatitude: 2,
|
|
|
|
+ GPSLongitudeRef: 3,
|
|
|
|
+ GPSLongitude: 4,
|
|
|
|
+ GPSAltitudeRef: 5,
|
|
|
|
+ GPSAltitude: 6,
|
|
|
|
+ GPSTimeStamp: 7,
|
|
|
|
+ GPSSatellites: 8,
|
|
|
|
+ GPSStatus: 9,
|
|
|
|
+ GPSMeasureMode: 10,
|
|
|
|
+ GPSDOP: 11,
|
|
|
|
+ GPSSpeedRef: 12,
|
|
|
|
+ GPSSpeed: 13,
|
|
|
|
+ GPSTrackRef: 14,
|
|
|
|
+ GPSTrack: 15,
|
|
|
|
+ GPSImgDirectionRef: 16,
|
|
|
|
+ GPSImgDirection: 17,
|
|
|
|
+ GPSMapDatum: 18,
|
|
|
|
+ GPSDestLatitudeRef: 19,
|
|
|
|
+ GPSDestLatitude: 20,
|
|
|
|
+ GPSDestLongitudeRef: 21,
|
|
|
|
+ GPSDestLongitude: 22,
|
|
|
|
+ GPSDestBearingRef: 23,
|
|
|
|
+ GPSDestBearing: 24,
|
|
|
|
+ GPSDestDistanceRef: 25,
|
|
|
|
+ GPSDestDistance: 26,
|
|
|
|
+ GPSProcessingMethod: 27,
|
|
|
|
+ GPSAreaInformation: 28,
|
|
|
|
+ GPSDateStamp: 29,
|
|
|
|
+ GPSDifferential: 30,
|
|
|
|
+ GPSHPositioningError: 31,
|
|
|
|
+ }
|
|
|
|
+ InteropIFD = {
|
|
|
|
+ InteroperabilityIndex: 1,
|
|
|
|
+ }
|
|
|
|
+ GPSHelper = {
|
|
|
|
+ degToDmsRational(degFloat : number) {
|
|
|
|
+ const degAbs = Math.abs(degFloat);
|
|
|
|
+ const minFloat = degAbs % 1 * 60;
|
|
|
|
+ const secFloat = minFloat % 1 * 60;
|
|
|
|
+ const deg = Math.floor(degAbs);
|
|
|
|
+ const min = Math.floor(minFloat);
|
|
|
|
+ const sec = Math.round(secFloat * 100);
|
|
|
|
+
|
|
|
|
+ return [
|
|
|
|
+ [deg, 1],
|
|
|
|
+ [min, 1],
|
|
|
|
+ [sec, 100]
|
|
|
|
+ ];
|
|
|
|
+ },
|
|
|
|
+ dmsRationalToDeg(dmsArray : number[][], ref : string) {
|
|
|
|
+ const sign = (ref === 'S' || ref === 'W') ? -1.0 : 1.0;
|
|
|
|
+ const deg = dmsArray[0][0] / dmsArray[0][1] +
|
|
|
|
+ dmsArray[1][0] / dmsArray[1][1] / 60.0 +
|
|
|
|
+ dmsArray[2][0] / dmsArray[2][1] / 3600.0;
|
|
|
|
+
|
|
|
|
+ return deg * sign;
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ remove(jpeg) {
|
|
|
|
+ let b64 = false;
|
|
|
|
+ if (jpeg.slice(0, 2) == "\xff\xd8") { } else if (jpeg.slice(0, 23) == "data:image/jpeg;base64," || jpeg
|
|
|
|
+ .slice(0, 22) == "data:image/jpg;base64,") {
|
|
|
|
+ jpeg = atob(jpeg.split(",")[1]);
|
|
|
|
+ b64 = true;
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("Given data is not jpeg.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const segments = splitIntoSegments(jpeg);
|
|
|
|
+ const newSegments = segments.filter(function (seg) {
|
|
|
|
+ return !(seg.slice(0, 2) == "\xff\xe1" &&
|
|
|
|
+ seg.slice(4, 10) == "Exif\x00\x00");
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ let new_data = newSegments.join("");
|
|
|
|
+ if (b64) {
|
|
|
|
+ new_data = "data:image/jpeg;base64," + btoa(new_data);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return new_data;
|
|
|
|
+ }
|
|
|
|
+ insert(exif, jpeg) {
|
|
|
|
+ let b64 = false;
|
|
|
|
+ if (exif.slice(0, 6) != "\x45\x78\x69\x66\x00\x00") {
|
|
|
|
+ throw new Error("Given data is not exif.");
|
|
|
|
+ }
|
|
|
|
+ if (jpeg.slice(0, 2) == "\xff\xd8") { } else if (jpeg.slice(0, 23) == "data:image/jpeg;base64," || jpeg
|
|
|
|
+ .slice(0, 22) == "data:image/jpg;base64,") {
|
|
|
|
+ jpeg = atob(jpeg.split(",")[1]);
|
|
|
|
+ b64 = true;
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("Given data is not jpeg.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const exifStr = "\xff\xe1" + pack(">H", [exif.length + 2]) + exif;
|
|
|
|
+ const segments = splitIntoSegments(jpeg);
|
|
|
|
+ let new_data = mergeSegments(segments, exifStr);
|
|
|
|
+ if (b64) {
|
|
|
|
+ new_data = "data:image/jpeg;base64," + btoa(new_data);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return new_data;
|
|
|
|
+ }
|
|
|
|
+ load(data) {
|
|
|
|
+ let input_data;
|
|
|
|
+ if (isString(data)) {
|
|
|
|
+ if (data.slice(0, 2) == "\xff\xd8") {
|
|
|
|
+ input_data = data;
|
|
|
|
+ } else if (data.slice(0, 23) == "data:image/jpeg;base64," || data.slice(0, 22) == "data:image/jpg;base64,") {
|
|
|
|
+ input_data = atob(data.split(",")[1]);
|
|
|
|
+ } else if (data.slice(0, 4) == "Exif") {
|
|
|
|
+ input_data = data.slice(6);
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("'load' gots invalid file data.");
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("'load' gots invalid type argument.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let exifDict = {};
|
|
|
|
+ let exif_dict = {
|
|
|
|
+ "0th": {},
|
|
|
|
+ "Exif": {},
|
|
|
|
+ "GPS": {},
|
|
|
|
+ "Interop": {},
|
|
|
|
+ "1st": {},
|
|
|
|
+ "thumbnail": null
|
|
|
|
+ };
|
|
|
|
+ const exifReader = new ExifReader(input_data);
|
|
|
|
+ if (exifReader.tiftag === null) {
|
|
|
|
+ return exif_dict;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (exifReader.tiftag.slice(0, 2) == "\x49\x49") {
|
|
|
|
+ exifReader.endian_mark = "<";
|
|
|
|
+ } else {
|
|
|
|
+ exifReader.endian_mark = ">";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let pointer = unpack(exifReader.endian_mark + "L",
|
|
|
|
+ exifReader.tiftag.slice(4, 8))[0];
|
|
|
|
+ exif_dict["0th"] = exifReader.get_ifd(pointer, "0th");
|
|
|
|
+
|
|
|
|
+ const first_ifd_pointer = exif_dict["0th"]["first_ifd_pointer"];
|
|
|
|
+ delete exif_dict["0th"]["first_ifd_pointer"];
|
|
|
|
+
|
|
|
|
+ if (34665 in exif_dict["0th"]) {
|
|
|
|
+ pointer = exif_dict["0th"][34665];
|
|
|
|
+ exif_dict["Exif"] = exifReader.get_ifd(pointer, "Exif");
|
|
|
|
+ }
|
|
|
|
+ if (34853 in exif_dict["0th"]) {
|
|
|
|
+ pointer = exif_dict["0th"][34853];
|
|
|
|
+ exif_dict["GPS"] = exifReader.get_ifd(pointer, "GPS");
|
|
|
|
+ }
|
|
|
|
+ if (40965 in exif_dict["Exif"]) {
|
|
|
|
+ pointer = exif_dict["Exif"][40965];
|
|
|
|
+ exif_dict["Interop"] = exifReader.get_ifd(pointer, "Interop");
|
|
|
|
+ }
|
|
|
|
+ if (first_ifd_pointer != "\x00\x00\x00\x00") {
|
|
|
|
+ pointer = unpack(exifReader.endian_mark + "L",
|
|
|
|
+ first_ifd_pointer)[0];
|
|
|
|
+ exif_dict["1st"] = exifReader.get_ifd(pointer, "1st");
|
|
|
|
+ if ((513 in exif_dict["1st"]) && (514 in exif_dict["1st"])) {
|
|
|
|
+ var end = exif_dict["1st"][513] + exif_dict["1st"][514];
|
|
|
|
+ var thumb = exifReader.tiftag.slice(exif_dict["1st"][513], end);
|
|
|
|
+ exif_dict["thumbnail"] = thumb;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return exif_dict;
|
|
|
|
+ }
|
|
|
|
+ dump(exif_dict_original) {
|
|
|
|
+ const TIFF_HEADER_LENGTH = 8;
|
|
|
|
+
|
|
|
|
+ const exif_dict : any = cloneDeep(exif_dict_original);
|
|
|
|
+ const header = "Exif\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08";
|
|
|
|
+ let exif_is = 0//false;
|
|
|
|
+ let gps_is = 0 //false;
|
|
|
|
+ let interop_is = 0//false;
|
|
|
|
+ let first_is = false;
|
|
|
|
+
|
|
|
|
+ let zeroth_ifd,
|
|
|
|
+ exif_ifd,
|
|
|
|
+ interop_ifd,
|
|
|
|
+ gps_ifd,
|
|
|
|
+ first_ifd;
|
|
|
|
+
|
|
|
|
+ if ("0th" in exif_dict) {
|
|
|
|
+ zeroth_ifd = exif_dict["0th"];
|
|
|
|
+ } else {
|
|
|
|
+ zeroth_ifd = {};
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ((("Exif" in exif_dict) && (Object.keys(exif_dict["Exif"]).length)) ||
|
|
|
|
+ (("Interop" in exif_dict) && (Object.keys(exif_dict["Interop"]).length))) {
|
|
|
|
+ zeroth_ifd[34665] = 1;
|
|
|
|
+ exif_is = 1//true;
|
|
|
|
+ exif_ifd = exif_dict["Exif"];
|
|
|
|
+ if (("Interop" in exif_dict) && Object.keys(exif_dict["Interop"]).length) {
|
|
|
|
+ exif_ifd[40965] = 1;
|
|
|
|
+ interop_is = 1//true;
|
|
|
|
+ interop_ifd = exif_dict["Interop"];
|
|
|
|
+ } else if (Object.keys(exif_ifd).indexOf(this.ExifIFD.InteroperabilityTag.toString()) > -1) {
|
|
|
|
+ delete exif_ifd[40965];
|
|
|
|
+ }
|
|
|
|
+ } else if (Object.keys(zeroth_ifd).indexOf(this.ImageIFD.ExifTag.toString()) > -1) {
|
|
|
|
+ delete zeroth_ifd[34665];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (("GPS" in exif_dict) && (Object.keys(exif_dict["GPS"]).length)) {
|
|
|
|
+ zeroth_ifd[this.ImageIFD.GPSTag] = 1;
|
|
|
|
+ gps_is = 1 //true;
|
|
|
|
+ gps_ifd = exif_dict["GPS"];
|
|
|
|
+ } else if (Object.keys(zeroth_ifd).indexOf(this.ImageIFD.GPSTag.toString()) > -1) {
|
|
|
|
+ delete zeroth_ifd[this.ImageIFD.GPSTag];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (("1st" in exif_dict) &&
|
|
|
|
+ ("thumbnail" in exif_dict) &&
|
|
|
|
+ (exif_dict["thumbnail"] != null)) {
|
|
|
|
+ first_is = true;
|
|
|
|
+ exif_dict["1st"][513] = 1;
|
|
|
|
+ exif_dict["1st"][514] = 1;
|
|
|
|
+ first_ifd = exif_dict["1st"];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const zeroth_set = _dict_to_bytes(zeroth_ifd, "0th", 0);
|
|
|
|
+ const zeroth_length = (zeroth_set[0].length + exif_is * 12 + gps_is * 12 + 4 +
|
|
|
|
+ zeroth_set[1].length);
|
|
|
|
+
|
|
|
|
+ let exif_set,
|
|
|
|
+ exif_bytes = "",
|
|
|
|
+ exif_length = 0,
|
|
|
|
+ gps_set,
|
|
|
|
+ gps_bytes = "",
|
|
|
|
+ gps_length = 0,
|
|
|
|
+ interop_set,
|
|
|
|
+ interop_bytes = "",
|
|
|
|
+ interop_length = 0,
|
|
|
|
+ first_set,
|
|
|
|
+ first_bytes = "",
|
|
|
|
+ thumbnail;
|
|
|
|
+ if (exif_is) {
|
|
|
|
+ exif_set = _dict_to_bytes(exif_ifd, "Exif", zeroth_length);
|
|
|
|
+ exif_length = exif_set[0].length + interop_is * 12 + exif_set[1].length;
|
|
|
|
+ }
|
|
|
|
+ if (gps_is) {
|
|
|
|
+ gps_set = _dict_to_bytes(gps_ifd, "GPS", zeroth_length + exif_length);
|
|
|
|
+ gps_bytes = gps_set.join("");
|
|
|
|
+ gps_length = gps_bytes.length;
|
|
|
|
+ }
|
|
|
|
+ if (interop_is) {
|
|
|
|
+ const offset = zeroth_length + exif_length + gps_length;
|
|
|
|
+ interop_set = _dict_to_bytes(interop_ifd, "Interop", offset);
|
|
|
|
+ interop_bytes = interop_set.join("");
|
|
|
|
+ interop_length = interop_bytes.length;
|
|
|
|
+ }
|
|
|
|
+ if (first_is) {
|
|
|
|
+ const offset = zeroth_length + exif_length + gps_length + interop_length;
|
|
|
|
+ first_set = _dict_to_bytes(first_ifd, "1st", offset);
|
|
|
|
+ thumbnail = _get_thumbnail(exif_dict["thumbnail"]);
|
|
|
|
+ if (thumbnail.length > 64000) {
|
|
|
|
+ throw new Error("Given thumbnail is too large. max 64kB");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let exif_pointer = "",
|
|
|
|
+ gps_pointer = "",
|
|
|
|
+ interop_pointer = "",
|
|
|
|
+ first_ifd_pointer = "\x00\x00\x00\x00";
|
|
|
|
+ if (exif_is) {
|
|
|
|
+ const pointer_value = TIFF_HEADER_LENGTH + zeroth_length;
|
|
|
|
+ const pointer_str = pack(">L", [pointer_value]);
|
|
|
|
+ const key = 34665;
|
|
|
|
+ const key_str = pack(">H", [key]);
|
|
|
|
+ const type_str = pack(">H", [TYPES["Long"]]);
|
|
|
|
+ const length_str = pack(">L", [1]);
|
|
|
|
+ exif_pointer = key_str + type_str + length_str + pointer_str;
|
|
|
|
+ }
|
|
|
|
+ if (gps_is) {
|
|
|
|
+ const pointer_value = TIFF_HEADER_LENGTH + zeroth_length + exif_length;
|
|
|
|
+ const pointer_str = pack(">L", [pointer_value]);
|
|
|
|
+ const key = 34853;
|
|
|
|
+ const key_str = pack(">H", [key]);
|
|
|
|
+ const type_str = pack(">H", [TYPES["Long"]]);
|
|
|
|
+ const length_str = pack(">L", [1]);
|
|
|
|
+ gps_pointer = key_str + type_str + length_str + pointer_str;
|
|
|
|
+ }
|
|
|
|
+ if (interop_is) {
|
|
|
|
+ const pointer_value = (TIFF_HEADER_LENGTH +
|
|
|
|
+ zeroth_length + exif_length + gps_length);
|
|
|
|
+ const pointer_str = pack(">L", [pointer_value]);
|
|
|
|
+ const key = 40965;
|
|
|
|
+ const key_str = pack(">H", [key]);
|
|
|
|
+ const type_str = pack(">H", [TYPES["Long"]]);
|
|
|
|
+ const length_str = pack(">L", [1]);
|
|
|
|
+ interop_pointer = key_str + type_str + length_str + pointer_str;
|
|
|
|
+ }
|
|
|
|
+ if (first_is) {
|
|
|
|
+ const pointer_value = (TIFF_HEADER_LENGTH + zeroth_length +
|
|
|
|
+ exif_length + gps_length + interop_length);
|
|
|
|
+ first_ifd_pointer = pack(">L", [pointer_value]);
|
|
|
|
+ const thumbnail_pointer = (pointer_value + first_set[0].length + 24 +
|
|
|
|
+ 4 + first_set[1].length);
|
|
|
|
+ const thumbnail_p_bytes = ("\x02\x01\x00\x04\x00\x00\x00\x01" +
|
|
|
|
+ pack(">L", [thumbnail_pointer]));
|
|
|
|
+ const thumbnail_length_bytes = ("\x02\x02\x00\x04\x00\x00\x00\x01" +
|
|
|
|
+ pack(">L", [thumbnail.length]));
|
|
|
|
+ first_bytes = (first_set[0] + thumbnail_p_bytes +
|
|
|
|
+ thumbnail_length_bytes + "\x00\x00\x00\x00" +
|
|
|
|
+ first_set[1] + thumbnail);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const zeroth_bytes = (zeroth_set[0] + exif_pointer + gps_pointer +
|
|
|
|
+ first_ifd_pointer + zeroth_set[1]);
|
|
|
|
+ if (exif_is) {
|
|
|
|
+ exif_bytes = exif_set[0] + interop_pointer + exif_set[1];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return (header + zeroth_bytes + exif_bytes + gps_bytes +
|
|
|
|
+ interop_bytes + first_bytes);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function _get_thumbnail(jpeg) {
|
|
|
|
+ let segments = splitIntoSegments(jpeg);
|
|
|
|
+ while (("\xff\xe0" <= segments[1].slice(0, 2)) && (segments[1].slice(0, 2) <= "\xff\xef")) {
|
|
|
|
+ segments = [segments[0]].concat(segments.slice(2));
|
|
|
|
+ }
|
|
|
|
+ return segments.join("");
|
|
|
|
+}
|
|
|
|
+function _pack_byte(array) {
|
|
|
|
+ return pack(">" + nStr("B", array.length), array);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function _pack_short(array) {
|
|
|
|
+ return pack(">" + nStr("H", array.length), array);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function _pack_long(array) {
|
|
|
|
+ return pack(">" + nStr("L", array.length), array);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function _value_to_bytes(raw_value, value_type, offset) {
|
|
|
|
+ let four_bytes_over = "";
|
|
|
|
+ let value_str = "";
|
|
|
|
+ let length,
|
|
|
|
+ new_value,
|
|
|
|
+ num,
|
|
|
|
+ den;
|
|
|
|
+
|
|
|
|
+ if (value_type == "Byte") {
|
|
|
|
+ length = raw_value.length;
|
|
|
|
+ if (length <= 4) {
|
|
|
|
+ value_str = (_pack_byte(raw_value) +
|
|
|
|
+ nStr("\x00", 4 - length));
|
|
|
|
+ } else {
|
|
|
|
+ value_str = pack(">L", [offset]);
|
|
|
|
+ four_bytes_over = _pack_byte(raw_value);
|
|
|
|
+ }
|
|
|
|
+ } else if (value_type == "Short") {
|
|
|
|
+ length = raw_value.length;
|
|
|
|
+ if (length <= 2) {
|
|
|
|
+ value_str = (_pack_short(raw_value) +
|
|
|
|
+ nStr("\x00\x00", 2 - length));
|
|
|
|
+ } else {
|
|
|
|
+ value_str = pack(">L", [offset]);
|
|
|
|
+ four_bytes_over = _pack_short(raw_value);
|
|
|
|
+ }
|
|
|
|
+ } else if (value_type == "Long") {
|
|
|
|
+ length = raw_value.length;
|
|
|
|
+ if (length <= 1) {
|
|
|
|
+ value_str = _pack_long(raw_value);
|
|
|
|
+ } else {
|
|
|
|
+ value_str = pack(">L", [offset]);
|
|
|
|
+ four_bytes_over = _pack_long(raw_value);
|
|
|
|
+ }
|
|
|
|
+ } else if (value_type == "Ascii") {
|
|
|
|
+ new_value = raw_value + "\x00";
|
|
|
|
+ length = new_value.length;
|
|
|
|
+ if (length > 4) {
|
|
|
|
+ value_str = pack(">L", [offset]);
|
|
|
|
+ four_bytes_over = new_value;
|
|
|
|
+ } else {
|
|
|
|
+ value_str = new_value + nStr("\x00", 4 - length);
|
|
|
|
+ }
|
|
|
|
+ } else if (value_type == "Rational") {
|
|
|
|
+ if (typeof (raw_value[0]) == "number") {
|
|
|
|
+ length = 1;
|
|
|
|
+ num = raw_value[0];
|
|
|
|
+ den = raw_value[1];
|
|
|
|
+ new_value = pack(">L", [num]) + pack(">L", [den]);
|
|
|
|
+ } else {
|
|
|
|
+ length = raw_value.length;
|
|
|
|
+ new_value = "";
|
|
|
|
+ for (var n = 0; n < length; n++) {
|
|
|
|
+ num = raw_value[n][0];
|
|
|
|
+ den = raw_value[n][1];
|
|
|
|
+ new_value += (pack(">L", [num]) +
|
|
|
|
+ pack(">L", [den]));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ value_str = pack(">L", [offset]);
|
|
|
|
+ four_bytes_over = new_value;
|
|
|
|
+ } else if (value_type == "SRational") {
|
|
|
|
+ if (typeof (raw_value[0]) == "number") {
|
|
|
|
+ length = 1;
|
|
|
|
+ num = raw_value[0];
|
|
|
|
+ den = raw_value[1];
|
|
|
|
+ new_value = pack(">l", [num]) + pack(">l", [den]);
|
|
|
|
+ } else {
|
|
|
|
+ length = raw_value.length;
|
|
|
|
+ new_value = "";
|
|
|
|
+ for (var n = 0; n < length; n++) {
|
|
|
|
+ num = raw_value[n][0];
|
|
|
|
+ den = raw_value[n][1];
|
|
|
|
+ new_value += (pack(">l", [num]) +
|
|
|
|
+ pack(">l", [den]));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ value_str = pack(">L", [offset]);
|
|
|
|
+ four_bytes_over = new_value;
|
|
|
|
+ } else if (value_type == "Undefined") {
|
|
|
|
+ length = raw_value.length;
|
|
|
|
+ if (length > 4) {
|
|
|
|
+ value_str = pack(">L", [offset]);
|
|
|
|
+ four_bytes_over = raw_value;
|
|
|
|
+ } else {
|
|
|
|
+ value_str = raw_value + nStr("\x00", 4 - length);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var length_str = pack(">L", [length]);
|
|
|
|
+
|
|
|
|
+ return [length_str, value_str, four_bytes_over];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function _dict_to_bytes(ifd_dict, ifd, ifd_offset) {
|
|
|
|
+ const TIFF_HEADER_LENGTH = 8;
|
|
|
|
+ const tag_count = Object.keys(ifd_dict).length;
|
|
|
|
+ const entry_header = pack(">H", [tag_count]);
|
|
|
|
+ let entries_length;
|
|
|
|
+ if (["0th", "1st"].indexOf(ifd) > -1) {
|
|
|
|
+ entries_length = 2 + tag_count * 12 + 4;
|
|
|
|
+ } else {
|
|
|
|
+ entries_length = 2 + tag_count * 12;
|
|
|
|
+ }
|
|
|
|
+ let entries = "";
|
|
|
|
+ let values = "";
|
|
|
|
+ let key;
|
|
|
|
+
|
|
|
|
+ for (key in ifd_dict) {
|
|
|
|
+ if (typeof (key) == "string") {
|
|
|
|
+ key = parseInt(key);
|
|
|
|
+ }
|
|
|
|
+ if ((ifd == "0th") && ([34665, 34853].indexOf(key) > -1)) {
|
|
|
|
+ continue;
|
|
|
|
+ } else if ((ifd == "Exif") && (key == 40965)) {
|
|
|
|
+ continue;
|
|
|
|
+ } else if ((ifd == "1st") && ([513, 514].indexOf(key) > -1)) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var raw_value = ifd_dict[key];
|
|
|
|
+ var key_str = pack(">H", [key]);
|
|
|
|
+ var value_type = TAGS[ifd][key]["type"];
|
|
|
|
+ var type_str = pack(">H", [TYPES[value_type]]);
|
|
|
|
+
|
|
|
|
+ if (typeof (raw_value) == "number") {
|
|
|
|
+ raw_value = [raw_value];
|
|
|
|
+ }
|
|
|
|
+ var offset = TIFF_HEADER_LENGTH + entries_length + ifd_offset + values.length;
|
|
|
|
+ var b = _value_to_bytes(raw_value, value_type, offset);
|
|
|
|
+ var length_str = b[0];
|
|
|
|
+ var value_str = b[1];
|
|
|
|
+ var four_bytes_over = b[2];
|
|
|
|
+
|
|
|
|
+ entries += key_str + type_str + length_str + value_str;
|
|
|
|
+ values += four_bytes_over;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return [entry_header + entries, values];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class ExifReader {
|
|
|
|
+ tiftag = null
|
|
|
|
+ endian_mark = ''
|
|
|
|
+ constructor(data) {
|
|
|
|
+ let segments,
|
|
|
|
+ app1;
|
|
|
|
+ if (data.slice(0, 2) == "\xff\xd8") { // JPEG
|
|
|
|
+ segments = splitIntoSegments(data);
|
|
|
|
+ app1 = getExifSeg(segments);
|
|
|
|
+ if (app1) {
|
|
|
|
+ this.tiftag = app1.slice(10);
|
|
|
|
+ }
|
|
|
|
+ } else if (["\x49\x49", "\x4d\x4d"].indexOf(data.slice(0, 2)) > -1) { // TIFF
|
|
|
|
+ this.tiftag = data;
|
|
|
|
+ } else if (data.slice(0, 4) == "Exif") { // Exif
|
|
|
|
+ this.tiftag = data.slice(6);
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("Given file is neither JPEG nor TIFF.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ get_ifd(pointer, ifd_name) {
|
|
|
|
+ let ifd_dict = {};
|
|
|
|
+ let tag_count = unpack(this.endian_mark + "H",
|
|
|
|
+ this.tiftag.slice(pointer, pointer + 2))[0];
|
|
|
|
+ const offset = pointer + 2;
|
|
|
|
+ let t;
|
|
|
|
+ if (["0th", "1st"].indexOf(ifd_name) > -1) {
|
|
|
|
+ t = "Image";
|
|
|
|
+ } else {
|
|
|
|
+ t = ifd_name;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (let x = 0; x < tag_count; x++) {
|
|
|
|
+ pointer = offset + 12 * x;
|
|
|
|
+ const tag = unpack(this.endian_mark + "H",
|
|
|
|
+ this.tiftag.slice(pointer, pointer + 2))[0];
|
|
|
|
+ const value_type = unpack(this.endian_mark + "H",
|
|
|
|
+ this.tiftag.slice(pointer + 2, pointer + 4))[0];
|
|
|
|
+ const value_num = unpack(this.endian_mark + "L",
|
|
|
|
+ this.tiftag.slice(pointer + 4, pointer + 8))[0];
|
|
|
|
+ const value = this.tiftag.slice(pointer + 8, pointer + 12);
|
|
|
|
+
|
|
|
|
+ const v_set = [value_type, value_num, value];
|
|
|
|
+ if (tag in TAGS[t]) {
|
|
|
|
+ ifd_dict[tag] = this.convert_value(v_set);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (ifd_name == "0th") {
|
|
|
|
+ pointer = offset + 12 * tag_count;
|
|
|
|
+ ifd_dict["first_ifd_pointer"] = this.tiftag.slice(pointer, pointer + 4);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ifd_dict;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ convert_value(val) {
|
|
|
|
+ let data = null;
|
|
|
|
+ const t = val[0];
|
|
|
|
+ const length = val[1];
|
|
|
|
+ const value = val[2];
|
|
|
|
+ let pointer;
|
|
|
|
+
|
|
|
|
+ if (t == 1) { // BYTE
|
|
|
|
+ if (length > 4) {
|
|
|
|
+ pointer = unpack(this.endian_mark + "L", value)[0];
|
|
|
|
+ data = unpack(this.endian_mark + nStr("B", length),
|
|
|
|
+ this.tiftag.slice(pointer, pointer + length));
|
|
|
|
+ } else {
|
|
|
|
+ data = unpack(this.endian_mark + nStr("B", length), value.slice(0, length));
|
|
|
|
+ }
|
|
|
|
+ } else if (t == 2) { // ASCII
|
|
|
|
+ if (length > 4) {
|
|
|
|
+ pointer = unpack(this.endian_mark + "L", value)[0];
|
|
|
|
+ data = this.tiftag.slice(pointer, pointer + length - 1);
|
|
|
|
+ } else {
|
|
|
|
+ data = value.slice(0, length - 1);
|
|
|
|
+ }
|
|
|
|
+ } else if (t == 3) { // SHORT
|
|
|
|
+ if (length > 2) {
|
|
|
|
+ pointer = unpack(this.endian_mark + "L", value)[0];
|
|
|
|
+ data = unpack(this.endian_mark + nStr("H", length),
|
|
|
|
+ this.tiftag.slice(pointer, pointer + length * 2));
|
|
|
|
+ } else {
|
|
|
|
+ data = unpack(this.endian_mark + nStr("H", length),
|
|
|
|
+ value.slice(0, length * 2));
|
|
|
|
+ }
|
|
|
|
+ } else if (t == 4) { // LONG
|
|
|
|
+ if (length > 1) {
|
|
|
|
+ pointer = unpack(this.endian_mark + "L", value)[0];
|
|
|
|
+ data = unpack(this.endian_mark + nStr("L", length),
|
|
|
|
+ this.tiftag.slice(pointer, pointer + length * 4));
|
|
|
|
+ } else {
|
|
|
|
+ data = unpack(this.endian_mark + nStr("L", length),
|
|
|
|
+ value);
|
|
|
|
+ }
|
|
|
|
+ } else if (t == 5) { // RATIONAL
|
|
|
|
+ pointer = unpack(this.endian_mark + "L", value)[0];
|
|
|
|
+ if (length > 1) {
|
|
|
|
+ data = [];
|
|
|
|
+ for (let x = 0; x < length; x++) {
|
|
|
|
+ data.push([unpack(this.endian_mark + "L",
|
|
|
|
+ this.tiftag.slice(pointer + x * 8, pointer + 4 + x * 8))[0],
|
|
|
|
+ unpack(this.endian_mark + "L",
|
|
|
|
+ this.tiftag.slice(pointer + 4 + x * 8, pointer + 8 + x * 8))[0]
|
|
|
|
+ ]);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ data = [unpack(this.endian_mark + "L",
|
|
|
|
+ this.tiftag.slice(pointer, pointer + 4))[0],
|
|
|
|
+ unpack(this.endian_mark + "L",
|
|
|
|
+ this.tiftag.slice(pointer + 4, pointer + 8))[0]
|
|
|
|
+ ];
|
|
|
|
+ }
|
|
|
|
+ } else if (t == 7) { // UNDEFINED BYTES
|
|
|
|
+ if (length > 4) {
|
|
|
|
+ pointer = unpack(this.endian_mark + "L", value)[0];
|
|
|
|
+ data = this.tiftag.slice(pointer, pointer + length);
|
|
|
|
+ } else {
|
|
|
|
+ data = value.slice(0, length);
|
|
|
|
+ }
|
|
|
|
+ } else if (t == 9) { // SLONG
|
|
|
|
+ if (length > 1) {
|
|
|
|
+ pointer = unpack(this.endian_mark + "L", value)[0];
|
|
|
|
+ data = unpack(this.endian_mark + nStr("l", length),
|
|
|
|
+ this.tiftag.slice(pointer, pointer + length * 4));
|
|
|
|
+ } else {
|
|
|
|
+ data = unpack(this.endian_mark + nStr("l", length),
|
|
|
|
+ value);
|
|
|
|
+ }
|
|
|
|
+ } else if (t == 10) { // SRATIONAL
|
|
|
|
+ pointer = unpack(this.endian_mark + "L", value)[0];
|
|
|
|
+ if (length > 1) {
|
|
|
|
+ data = [];
|
|
|
|
+ for (let x = 0; x < length; x++) {
|
|
|
|
+ data.push([unpack(this.endian_mark + "l",
|
|
|
|
+ this.tiftag.slice(pointer + x * 8, pointer + 4 + x * 8))[0],
|
|
|
|
+ unpack(this.endian_mark + "l",
|
|
|
|
+ this.tiftag.slice(pointer + 4 + x * 8, pointer + 8 + x * 8))[0]
|
|
|
|
+ ]);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ data = [unpack(this.endian_mark + "l",
|
|
|
|
+ this.tiftag.slice(pointer, pointer + 4))[0],
|
|
|
|
+ unpack(this.endian_mark + "l",
|
|
|
|
+ this.tiftag.slice(pointer + 4, pointer + 8))[0]
|
|
|
|
+ ];
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("Exif might be wrong. Got incorrect value " +
|
|
|
|
+ "type to decode. type:" + t);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ((data instanceof Array) && (data.length == 1)) {
|
|
|
|
+ return data[0];
|
|
|
|
+ } else {
|
|
|
|
+ return data;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function pack(mark, array) {
|
|
|
|
+ if (!(array instanceof Array)) {
|
|
|
|
+ throw new Error("'pack' error. Got invalid type argument.");
|
|
|
|
+ }
|
|
|
|
+ if ((mark.length - 1) != array.length) {
|
|
|
|
+ throw new Error("'pack' error. " + (mark.length - 1) + " marks, " + array.length + " elements.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let littleEndian;
|
|
|
|
+ if (mark[0] == "<") {
|
|
|
|
+ littleEndian = true;
|
|
|
|
+ } else if (mark[0] == ">") {
|
|
|
|
+ littleEndian = false;
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("");
|
|
|
|
+ }
|
|
|
|
+ let packed = "";
|
|
|
|
+ let p = 1;
|
|
|
|
+ let val = null;
|
|
|
|
+ let c = null;
|
|
|
|
+ let valStr = null;
|
|
|
|
+
|
|
|
|
+ while (c = mark[p]) {
|
|
|
|
+ if (c.toLowerCase() == "b") {
|
|
|
|
+ val = array[p - 1];
|
|
|
|
+ if ((c == "b") && (val < 0)) {
|
|
|
|
+ val += 0x100;
|
|
|
|
+ }
|
|
|
|
+ if ((val > 0xff) || (val < 0)) {
|
|
|
|
+ throw new Error("'pack' error.");
|
|
|
|
+ } else {
|
|
|
|
+ valStr = String.fromCharCode(val);
|
|
|
|
+ }
|
|
|
|
+ } else if (c == "H") {
|
|
|
|
+ val = array[p - 1];
|
|
|
|
+ if ((val > 0xffff) || (val < 0)) {
|
|
|
|
+ throw new Error("'pack' error.");
|
|
|
|
+ } else {
|
|
|
|
+ valStr = String.fromCharCode(Math.floor((val % 0x10000) / 0x100)) +
|
|
|
|
+ String.fromCharCode(val % 0x100);
|
|
|
|
+ if (littleEndian) {
|
|
|
|
+ valStr = valStr.split("").reverse().join("");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else if (c.toLowerCase() == "l") {
|
|
|
|
+ val = array[p - 1];
|
|
|
|
+ if ((c == "l") && (val < 0)) {
|
|
|
|
+ val += 0x100000000;
|
|
|
|
+ }
|
|
|
|
+ if ((val > 0xffffffff) || (val < 0)) {
|
|
|
|
+ throw new Error("'pack' error.");
|
|
|
|
+ } else {
|
|
|
|
+ valStr = String.fromCharCode(Math.floor(val / 0x1000000)) +
|
|
|
|
+ String.fromCharCode(Math.floor((val % 0x1000000) / 0x10000)) +
|
|
|
|
+ String.fromCharCode(Math.floor((val % 0x10000) / 0x100)) +
|
|
|
|
+ String.fromCharCode(val % 0x100);
|
|
|
|
+ if (littleEndian) {
|
|
|
|
+ valStr = valStr.split("").reverse().join("");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("'pack' error.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ packed += valStr;
|
|
|
|
+ p += 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return packed;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function unpack(mark, str) {
|
|
|
|
+ if (typeof (str) != "string") {
|
|
|
|
+ throw new Error("'unpack' error. Got invalid type argument.");
|
|
|
|
+ }
|
|
|
|
+ let l = 0;
|
|
|
|
+ for (let markPointer = 1; markPointer < mark.length; markPointer++) {
|
|
|
|
+ if (mark[markPointer].toLowerCase() == "b") {
|
|
|
|
+ l += 1;
|
|
|
|
+ } else if (mark[markPointer].toLowerCase() == "h") {
|
|
|
|
+ l += 2;
|
|
|
|
+ } else if (mark[markPointer].toLowerCase() == "l") {
|
|
|
|
+ l += 4;
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("'unpack' error. Got invalid mark.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (l != str.length) {
|
|
|
|
+ throw new Error("'unpack' error. Mismatch between symbol and string length. " + l + ":" + str.length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let littleEndian;
|
|
|
|
+ if (mark[0] == "<") {
|
|
|
|
+ littleEndian = true;
|
|
|
|
+ } else if (mark[0] == ">") {
|
|
|
|
+ littleEndian = false;
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("'unpack' error.");
|
|
|
|
+ }
|
|
|
|
+ let unpacked = [];
|
|
|
|
+ let strPointer = 0;
|
|
|
|
+ let p = 1;
|
|
|
|
+ let val = null;
|
|
|
|
+ let c = null;
|
|
|
|
+ let length = null;
|
|
|
|
+ let sliced = "";
|
|
|
|
+
|
|
|
|
+ while (c = mark[p]) {
|
|
|
|
+ if (c.toLowerCase() == "b") {
|
|
|
|
+ length = 1;
|
|
|
|
+ sliced = str.slice(strPointer, strPointer + length);
|
|
|
|
+ val = sliced.charCodeAt(0);
|
|
|
|
+ if ((c == "b") && (val >= 0x80)) {
|
|
|
|
+ val -= 0x100;
|
|
|
|
+ }
|
|
|
|
+ } else if (c == "H") {
|
|
|
|
+ length = 2;
|
|
|
|
+ sliced = str.slice(strPointer, strPointer + length);
|
|
|
|
+ if (littleEndian) {
|
|
|
|
+ sliced = sliced.split("").reverse().join("");
|
|
|
|
+ }
|
|
|
|
+ val = sliced.charCodeAt(0) * 0x100 +
|
|
|
|
+ sliced.charCodeAt(1);
|
|
|
|
+ } else if (c.toLowerCase() == "l") {
|
|
|
|
+ length = 4;
|
|
|
|
+ sliced = str.slice(strPointer, strPointer + length);
|
|
|
|
+ if (littleEndian) {
|
|
|
|
+ sliced = sliced.split("").reverse().join("");
|
|
|
|
+ }
|
|
|
|
+ val = sliced.charCodeAt(0) * 0x1000000 +
|
|
|
|
+ sliced.charCodeAt(1) * 0x10000 +
|
|
|
|
+ sliced.charCodeAt(2) * 0x100 +
|
|
|
|
+ sliced.charCodeAt(3);
|
|
|
|
+ if ((c == "l") && (val >= 0x80000000)) {
|
|
|
|
+ val -= 0x100000000;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error("'unpack' error. " + c);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ unpacked.push(val);
|
|
|
|
+ strPointer += length;
|
|
|
|
+ p += 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return unpacked;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function nStr(ch, num) {
|
|
|
|
+ let str = "";
|
|
|
|
+ for (let i = 0; i < num; i++) {
|
|
|
|
+ str += ch;
|
|
|
|
+ }
|
|
|
|
+ return str;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function splitIntoSegments(data) {
|
|
|
|
+ if (data.slice(0, 2) != "\xff\xd8") {
|
|
|
|
+ throw new Error("Given data isn't JPEG.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let head = 2;
|
|
|
|
+ const segments = ["\xff\xd8"];
|
|
|
|
+ while (true) {
|
|
|
|
+ if (data.slice(head, head + 2) == "\xff\xda") {
|
|
|
|
+ segments.push(data.slice(head));
|
|
|
|
+ break;
|
|
|
|
+ } else {
|
|
|
|
+ var length = unpack(">H", data.slice(head + 2, head + 4))[0];
|
|
|
|
+ var endPoint = head + length + 2;
|
|
|
|
+ segments.push(data.slice(head, endPoint));
|
|
|
|
+ head = endPoint;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (head >= data.length) {
|
|
|
|
+ throw new Error("Wrong JPEG data.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return segments;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function getExifSeg(segments) {
|
|
|
|
+ let seg;
|
|
|
|
+ for (let i = 0; i < segments.length; i++) {
|
|
|
|
+ seg = segments[i];
|
|
|
|
+ if (seg.slice(0, 2) == "\xff\xe1" &&
|
|
|
|
+ seg.slice(4, 10) == "Exif\x00\x00") {
|
|
|
|
+ return seg;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function mergeSegments(segments, exif) {
|
|
|
|
+ let hasExifSegment = false;
|
|
|
|
+ let additionalAPP1ExifSegments = [];
|
|
|
|
+
|
|
|
|
+ segments.forEach(function (segment, i) {
|
|
|
|
+ // Replace first occurence of APP1:Exif segment
|
|
|
|
+ if (segment.slice(0, 2) == "\xff\xe1" &&
|
|
|
|
+ segment.slice(4, 10) == "Exif\x00\x00"
|
|
|
|
+ ) {
|
|
|
|
+ if (!hasExifSegment) {
|
|
|
|
+ segments[i] = exif;
|
|
|
|
+ hasExifSegment = true;
|
|
|
|
+ } else {
|
|
|
|
+ additionalAPP1ExifSegments.unshift(i);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // Remove additional occurences of APP1:Exif segment
|
|
|
|
+ additionalAPP1ExifSegments.forEach(function (segmentIndex) {
|
|
|
|
+ segments.splice(segmentIndex, 1);
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ if (!hasExifSegment && exif) {
|
|
|
|
+ segments = [segments[0], exif].concat(segments.slice(1));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return segments.join("");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|