/ccr-exif/CCR.Exif.pas

https://bitbucket.org/sas_team/sas.requires · Pascal · 7404 lines · 6459 code · 690 blank · 255 comment · 544 complexity · 4c8faa505b5c20b70482dd69f01ec26b MD5 · raw file

Large files are truncated click here to view the full file

  1. {**************************************************************************************}
  2. { }
  3. { CCR Exif - Delphi class library for reading and writing image metadata }
  4. { Version 1.5.3 }
  5. { }
  6. { The contents of this file are subject to the Mozilla Public License Version 1.1 }
  7. { (the "License"); you may not use this file except in compliance with the License. }
  8. { You may obtain a copy of the License at http://www.mozilla.org/MPL/ }
  9. { }
  10. { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT }
  11. { WARRANTY OF ANY KIND, either express or implied. See the License for the specific }
  12. { language governing rights and limitations under the License. }
  13. { }
  14. { The Original Code is CCR.Exif.pas. }
  15. { }
  16. { The Initial Developer of the Original Code is Chris Rolliston. Portions created by }
  17. { Chris Rolliston are Copyright (C) 2009-2014 Chris Rolliston. All Rights Reserved. }
  18. { }
  19. {**************************************************************************************}
  20. {$I CCR.Exif.inc}
  21. unit CCR.Exif;
  22. {
  23. Notes:
  24. - In Exif-jargon, we have 'tags' and 'IFDs' (including 'sub-IFDs'). In the jargon of
  25. this unit, we have 'tags' and 'sections'.
  26. - The basic usage pattern is this: construct a TExifData instance; call LoadFromGraphic,
  27. which has file name, TStream and TGraphic/TBitmap overloads; read and write
  28. the published tag properties as you so wish; and call SaveToGraphic to persist the
  29. changes made. Supported graphic types are JPEG, PSD and TIFF. LoadFromGraphic (which
  30. is a function) returns True if the source was of a supported graphic type, False
  31. otherwise. In contrast, SaveToGraphic will simply raise an exception if the
  32. destination isn't of a supported type.
  33. - The idea is that, in general, if your sole concern is reading and/or writing Exif
  34. metadata, you only need to explicitly add CCR.Exif to your uses clause. This unit
  35. does still itself use the other ones (CCR.Exif.BaseUtils etc.) though.
  36. - You enumerate the tags of a section with the for-in syntax. No traditional indexing
  37. is provided so as to avoid confusing tag IDs with tag indices.
  38. - The enumerator implementation for TExifSection allows calling Delete on a tag while
  39. you are enumerating the container section.
  40. - When tags are loaded from a graphic, any associated XMP packet is loaded too, though
  41. XMP data is only actually parsed when required.
  42. - When setting a tag property, the default behaviour is for the loaded XMP packet
  43. to be updated if the equivalent XMP tag already exists. This can be changed however
  44. by setting the XMPWritePolicy property of TExifData.
  45. - Maker note rewriting is *not* supported in TExifData. While you can make changes to
  46. the loaded maker note tags, these changes won't ever be persisted.
  47. - When compiling in XE2+, you need to set a 'FMX' global define for this unit to work
  48. properly in a FireMonkey application.
  49. }
  50. interface
  51. uses
  52. Types, SysUtils, Classes, TypInfo, CCR.Exif.BaseUtils, CCR.Exif.IPTC,
  53. {$IFDEF HasGenerics}Generics.Collections, Generics.Defaults,{$ENDIF}
  54. {$IFDEF VCL}Graphics, Jpeg,{$ENDIF}
  55. {$IFDEF FMX}FMX.Types,{$IF CompilerVersion >= 26}FMX.Graphics, FMX.Surfaces,{$IFEND}{$ENDIF}
  56. CCR.Exif.StreamHelper, CCR.Exif.TagIDs, CCR.Exif.TiffUtils, CCR.Exif.XMPUtils;
  57. const
  58. SmallEndian = CCR.Exif.StreamHelper.SmallEndian;
  59. BigEndian = CCR.Exif.StreamHelper.BigEndian;
  60. xwAlwaysUpdate = CCR.Exif.XMPUtils.xwAlwaysUpdate;
  61. xwUpdateIfExists = CCR.Exif.XMPUtils.xwUpdateIfExists;
  62. xwRemove = CCR.Exif.XMPUtils.xwRemove;
  63. type
  64. EInvalidJPEGHeader = CCR.Exif.BaseUtils.EInvalidJPEGHeader;
  65. ECCRExifException = CCR.Exif.BaseUtils.ECCRExifException;
  66. EInvalidTiffData = CCR.Exif.TiffUtils.EInvalidTiffData;
  67. TEndianness = CCR.Exif.StreamHelper.TEndianness;
  68. const
  69. tdExifFraction = tdLongWordFraction;
  70. tdExifSignedFraction = tdLongIntFraction;
  71. leBadOffset = CCR.Exif.BaseUtils.leBadOffset;
  72. leBadTagCount = CCR.Exif.BaseUtils.leBadTagCount;
  73. leBadTagHeader = CCR.Exif.BaseUtils.leBadTagHeader;
  74. tdUndefined = CCR.Exif.TiffUtils.tdUndefined;
  75. StandardExifThumbnailWidth = 160;
  76. StandardExifThumbnailHeight = 120;
  77. type
  78. {$IFDEF FMX}
  79. TGraphic = TBitmap;
  80. TJPEGImage = class(TBitmap, IStreamPersist)
  81. public
  82. constructor Create; reintroduce;
  83. procedure SaveToStream(Stream: TStream);
  84. property Empty: Boolean read IsEmpty;
  85. end;
  86. {$ENDIF}
  87. {$IF NOT Declared(TJPEGImage)}
  88. {$DEFINE DummyTJpegImage}
  89. TJPEGImage = class(TInterfacedPersistent, IStreamPersist)
  90. strict private
  91. FData: TMemoryStream;
  92. FWidth, FHeight: Integer;
  93. FOnChange: TNotifyEvent;
  94. function GetWidth: Integer;
  95. function GetHeight: Integer;
  96. procedure SizeFieldsNeeded;
  97. protected
  98. procedure AssignTo(Dest: TPersistent); override;
  99. procedure Changed; virtual;
  100. function GetEmpty: Boolean;
  101. public
  102. constructor Create;
  103. destructor Destroy; override;
  104. procedure Assign(Source: TPersistent); override;
  105. procedure LoadFromStream(Stream: TStream);
  106. procedure SaveToStream(Stream: TStream);
  107. property Empty: Boolean read GetEmpty;
  108. property Width: Integer read GetWidth;
  109. property Height: Integer read GetHeight;
  110. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  111. end;
  112. {$IFEND}
  113. ENotOnlyASCIIError = class(EInvalidTiffData);
  114. TExifTag = class;
  115. TExifSection = class;
  116. TExtendableExifSection = class;
  117. TCustomExifData = class;
  118. TExifData = class;
  119. TExifTagID = TTiffTagID;
  120. TExifDataType = TTiffDataType;
  121. TExifDataTypes = TTiffDataTypes;
  122. PExifFraction = ^TExifFraction;
  123. TExifFraction = TTiffLongWordFraction;
  124. TExifSignedFraction = TTiffLongIntFraction;
  125. {$Z2}
  126. TWindowsStarRating = (urUndefined, urOneStar, urTwoStars, urThreeStars,
  127. urFourStars, urFiveStars);
  128. {$Z1}
  129. TExifTagChangeType = (tcData, tcDataSize, tcID);
  130. TExifPaddingTagSize = 2..High(LongInt);
  131. TExifTag = class(TNoRefCountInterfacedObject, IMetadataBlock, ITiffTag)
  132. strict private
  133. FAsStringCache: string;
  134. FData: Pointer;
  135. FDataStream: TUserMemoryStream;
  136. FDataType: TExifDataType;
  137. FElementCount: LongInt;
  138. FID: TExifTagID;
  139. FOriginalDataOffset: Int64;
  140. FOriginalDataSize: Integer;
  141. FWellFormed: Boolean;
  142. function GetAsString: string;
  143. procedure SetAsString(const Value: string);
  144. function GetDataSize: Integer; inline;
  145. procedure SetDataType(const NewDataType: TExifDataType);
  146. function GetElementAsString(Index: Integer): string;
  147. procedure SetElementCount(const NewCount: LongInt);
  148. procedure SetID(const Value: TExifTagID);
  149. protected
  150. { IMetadataBlock }
  151. function GetData: TCustomMemoryStream;
  152. function IsExifBlock(CheckID: Boolean = True): Boolean;
  153. function IsIPTCBlock(CheckID: Boolean = True): Boolean;
  154. function IsXMPBlock(CheckID: Boolean = True): Boolean;
  155. { ITiffTag }
  156. function GetDataType: TTiffDataType;
  157. function GetElementCount: Integer;
  158. function GetID: TTiffTagID;
  159. function GetOriginalDataOffset: LongWord;
  160. function GetParent: ITiffDirectory;
  161. protected
  162. {$IFDEF WEAKREF}[Weak]{$ENDIF}FSection: TExifSection;
  163. procedure Changing(NewID: TExifTagID; NewDataType: TExifDataType;
  164. NewElementCount: LongInt; NewData: Boolean);
  165. procedure Changed(ChangeType: TExifTagChangeType); overload;
  166. procedure WriteHeader(Stream: TStream; Endianness: TEndianness; DataOffset: LongInt);
  167. procedure WriteOffsettedData(Stream: TStream; Endianness: TEndianness);
  168. constructor Create(Section: TExifSection; const Directory: IFoundTiffDirectory;
  169. Index: Integer); overload;
  170. property DataStream: TUserMemoryStream read FDataStream;
  171. public
  172. constructor Create(const Section: TExifSection; const ID: TExifTagID;
  173. DataType: TExifDataType; ElementCount: LongInt); overload;
  174. destructor Destroy; override;
  175. procedure Assign(Source: TExifTag);
  176. procedure Changed; overload; //call this if Data is modified directly
  177. procedure Delete; inline;
  178. function HasWindowsStringData: Boolean;
  179. function IsPadding: Boolean;
  180. procedure SetAsPadding(Size: TExifPaddingTagSize);
  181. procedure UpdateData(NewDataType: TExifDataType; NewElementCount: LongInt;
  182. const NewData); overload;
  183. procedure UpdateData(const NewData); overload;
  184. function ReadFraction(Index: Integer; const Default: TExifFraction): TExifFraction;
  185. function ReadLongWord(Index: Integer; const Default: LongWord): LongWord;
  186. function ReadWord(Index: Integer; const Default: Word): Word;
  187. {$IFDEF HasToString}
  188. function ToString: string; override;
  189. {$ENDIF}
  190. property AsString: string read GetAsString write SetAsString;
  191. property ElementAsString[Index: Integer]: string read GetElementAsString;
  192. property Data: Pointer read FData;
  193. property DataSize: Integer read GetDataSize;
  194. property DataType: TExifDataType read FDataType write SetDataType; //this needs to be loaded before AsString
  195. property ElementCount: LongInt read FElementCount write SetElementCount;
  196. property ID: TExifTagID read FID write SetID;
  197. property OriginalDataOffset: Int64 read FOriginalDataOffset;
  198. property OriginalDataSize: Integer read FOriginalDataSize;
  199. property Section: TExifSection read FSection;
  200. property WellFormed: Boolean read FWellFormed;
  201. end;
  202. TExifSectionLoadError = TMetadataLoadError;
  203. TExifSectionLoadErrors = TMetadataLoadErrors;
  204. TExifSectionKindEx = (esUserDefined, esGeneral, esDetails, esInterop, esGPS,
  205. esThumbnail, esMakerNote);
  206. TExifSectionKind = esGeneral..esMakerNote;
  207. TExifSection = class(TNoRefCountInterfacedObject, ITiffDirectory)
  208. private type
  209. {$IFDEF HasGenerics}
  210. TTagList = class(TList<TExifTag>)
  211. constructor Create;
  212. end;
  213. {$ELSE}
  214. TTagList = class(TList)
  215. public
  216. procedure Sort;
  217. end;
  218. {$ENDIF}
  219. public type
  220. TEnumerator = class sealed(TInterfacedObject, ITiffDirectoryEnumerator)
  221. private
  222. FCurrent: TExifTag;
  223. FIndex: Integer;
  224. FTags: TTagList;
  225. constructor Create(ATagList: TTagList);
  226. function GetCurrent: ITiffTag;
  227. public
  228. function MoveNext: Boolean;
  229. property Current: TExifTag read FCurrent;
  230. end;
  231. strict private class var
  232. LastSetDateTimeValue: TDateTime;
  233. LastSetDateTimeMainStr, LastSetDateTimeSubSecStr: string;
  234. strict private
  235. FFirstTagHeaderOffset: Int64;
  236. FKind: TExifSectionKindEx;
  237. FLoadErrors: TExifSectionLoadErrors;
  238. FModified: Boolean;
  239. {$IFDEF WEAKREF}[Weak]{$ENDIF}FOwner: TCustomExifData;
  240. FTagList: TTagList;
  241. procedure DoSetFractionValue(TagID: TExifTagID; Index: Integer;
  242. DataType: TExifDataType; const Value);
  243. protected
  244. { ITiffDirectory }
  245. function FindTag(TagID: TTiffTagID; out ParsedTag: ITiffTag): Boolean;
  246. function GetEnumeratorIntf: ITiffDirectoryEnumerator;
  247. function ITiffDirectory.GetEnumerator = GetEnumeratorIntf;
  248. function GetIndex: Integer;
  249. function GetParent: ITiffDirectory;
  250. function GetTagCount: Integer;
  251. function LoadSubDirectory(OffsetTagID: TTiffTagID): ITiffDirectory;
  252. { other }
  253. constructor Create(const AOwner: TCustomExifData; AKind: TExifSectionKindEx);
  254. function Add(ID: TExifTagID; DataType: TExifDataType; ElementCount: LongInt): TExifTag;
  255. procedure Changed;
  256. function CheckExtendable: TExtendableExifSection;
  257. procedure DoDelete(TagIndex: Integer; FreeTag: Boolean);
  258. function EnforceASCII: Boolean;
  259. function FindIndex(ID: TExifTagID; var TagIndex: Integer): Boolean;
  260. function ForceSetElement(ID: TExifTagID; DataType: TExifDataType;
  261. Index: Integer; const Value): TExifTag;
  262. procedure Load(const Directory: IFoundTiffDirectory; TiffImageSource: Boolean);
  263. procedure TagChanging(Tag: TExifTag; NewID: TExifTagID;
  264. NewDataType: TExifDataType; NewElementCount: LongInt; NewData: Boolean);
  265. procedure TagChanged(Tag: TExifTag; ChangeType: TExifTagChangeType);
  266. procedure TagDeleting(Tag: TExifTag);
  267. property FirstTagHeaderOffset: Int64 read FFirstTagHeaderOffset;
  268. public
  269. destructor Destroy; override;
  270. function GetEnumerator: TEnumerator;
  271. procedure Clear;
  272. function Find(ID: TExifTagID; out Tag: TExifTag): Boolean;
  273. function GetByteValue(TagID: TExifTagID; Index: Integer; Default: Byte;
  274. MinValue: Byte = 0; MaxValue: Byte = High(Byte)): Byte;
  275. function GetDateTimeValue(MainID, SubSecsID: TExifTagID): TDateTimeTagValue;
  276. function GetFractionValue(TagID: TExifTagID; Index: Integer): TExifFraction; overload;
  277. function GetFractionValue(TagID: TExifTagID; Index: Integer;
  278. const Default: TExifFraction): TExifFraction; overload;
  279. function GetLongIntValue(TagID: TExifTagID; Index: Integer): TLongIntTagValue; overload;
  280. function GetLongIntValue(TagID: TExifTagID; Index: Integer; Default: LongInt): LongInt; overload;
  281. function GetLongWordValue(TagID: TExifTagID; Index: Integer): TLongWordTagValue; overload;
  282. function GetLongWordValue(TagID: TExifTagID; Index: Integer; Default: LongWord): LongWord; overload;
  283. function GetSmallIntValue(TagID: TExifTagID; Index: Integer; Default: SmallInt;
  284. MinValue: SmallInt = Low(SmallInt); MaxValue: SmallInt = High(SmallInt)): SmallInt;
  285. function GetStringValue(TagID: TExifTagID; const Default: string = ''): string;
  286. function GetWindowsStringValue(TagID: TExifTagID; const Default: UnicodeString = ''): UnicodeString;
  287. function GetWordValue(TagID: TExifTagID; Index: Integer): TWordTagValue; overload;
  288. function GetWordValue(TagID: TExifTagID; Index: Integer; Default: Word;
  289. MinValue: Word = 0; MaxValue: Word = High(Word)): Word; overload;
  290. function IsExtendable: Boolean; inline;
  291. function Remove(ID: TExifTagID): Boolean; overload; //returns True if contained a tag with the specified ID
  292. procedure Remove(const IDs: array of TExifTagID); overload;
  293. function RemovePaddingTag: Boolean; //returns True if contained a padding tag
  294. function SetByteValue(TagID: TExifTagID; Index: Integer; Value: Byte): TExifTag;
  295. procedure SetDateTimeValue(MainID, SubSecsID: TExifTagID; const DateTime: TDateTimeTagValue);
  296. procedure SetFractionValue(TagID: TExifTagID; Index: Integer; const Value: TExifFraction);
  297. function SetLongWordValue(TagID: TExifTagID; Index: Integer; Value: LongWord): TExifTag;
  298. procedure SetSignedFractionValue(TagID: TExifTagID; Index: Integer;
  299. const Value: TExifSignedFraction);
  300. procedure SetStringValue(TagID: TExifTagID; const Value: string);
  301. procedure SetWindowsStringValue(TagID: TExifTagID; const Value: UnicodeString);
  302. function SetWordValue(TagID: TExifTagID; Index: Integer; Value: Word): TExifTag;
  303. function TagExists(ID: TExifTagID; ValidDataTypes: TExifDataTypes =
  304. [Low(TExifDataType)..High(TExifDataType)]; MinElementCount: LongInt = 1;
  305. MaxElementCount: LongInt = MaxLongInt): Boolean;
  306. function TryGetByteValue(TagID: TExifTagID; Index: Integer; var Value): Boolean;
  307. function TryGetLongWordValue(TagID: TExifTagID; Index: Integer; var Value): Boolean;
  308. function TryGetWordValue(TagID: TExifTagID; Index: Integer; var Value): Boolean;
  309. function TryGetStringValue(TagID: TExifTagID; var Value: string): Boolean;
  310. function TryGetWindowsStringValue(TagID: TExifTagID; var Value: UnicodeString): Boolean;
  311. property Count: Integer read GetTagCount;
  312. property Kind: TExifSectionKindEx read FKind;
  313. property LoadErrors: TExifSectionLoadErrors read FLoadErrors write FLoadErrors;
  314. property Modified: Boolean read FModified write FModified;
  315. property Owner: TCustomExifData read FOwner;
  316. end;
  317. TExifSectionClass = class of TExifSection;
  318. TExtendableExifSection = class(TExifSection)
  319. public
  320. function Add(ID: TExifTagID; DataType: TExifDataType;
  321. ElementCount: LongInt = 1): TExifTag;
  322. function AddOrUpdate(ID: TExifTagID; DataType: TExifDataType;
  323. ElementCount: LongInt): TExifTag; overload;
  324. function AddOrUpdate(ID: TExifTagID; DataType: TExifDataType;
  325. ElementCount: LongInt; const Data): TExifTag; overload;
  326. function AddOrUpdate(ID: TExifTagID; DataType: TExifDataType;
  327. const Source: IStreamPersist): TExifTag; overload;
  328. procedure Assign(Source: TExifSection);
  329. procedure CopyTags(Section: TExifSection);
  330. end;
  331. EInvalidMakerNoteFormat = class(EInvalidTiffData);
  332. TObjectTagValue = class(TInterfacedPersistent)
  333. strict private
  334. {$IFDEF WEAKREF}[Weak]{$ENDIF}FOwner: TCustomExifData;
  335. protected
  336. constructor Create(const AOwner: TCustomExifData);
  337. function GetOwner: TPersistent; override;
  338. property Owner: TCustomExifData read FOwner;
  339. public
  340. function MissingOrInvalid: Boolean; virtual; abstract;
  341. {$IFNDEF HasToString}
  342. function ToString: string; virtual;
  343. {$ENDIF}
  344. end;
  345. IEnumToCharMapper = interface
  346. ['{B068C720-1832-4A3F-97F1-0321809EC33B}']
  347. function EnumValueToChar(OrdValue: Integer): AnsiChar;
  348. function CharToEnumValue(Ch: AnsiChar): Integer;
  349. function GetEnumTypeInfo: PTypeInfo;
  350. property EnumTypeInfo: PTypeInfo read GetEnumTypeInfo;
  351. end;
  352. IEnumToCharMapperEx = interface(IEnumToCharMapper)
  353. ['{7911A192-BEA4-42A8-B1A7-EB5749972FB0}']
  354. function GetEnumName(OrdValue: Integer): string;
  355. function GetMinEnumValue: Integer;
  356. function GetMaxEnumValue: Integer;
  357. property MinEnumValue: Integer read GetMinEnumValue;
  358. property MaxEnumValue: Integer read GetMaxEnumValue;
  359. end;
  360. TEnumObjectTagValue = class(TObjectTagValue)
  361. strict private
  362. FValidCharsToAssign: TSysCharSet;
  363. function GetValidCharsToAssign: TSysCharSet;
  364. protected
  365. property ValidCharsToAssign: TSysCharSet read GetValidCharsToAssign;
  366. end;
  367. TExifFlashMode = (efUnknown, efCompulsoryFire, efCompulsorySuppression, efAuto);
  368. TExifStrobeLight = (esNoDetectionFunction, esUndetected, esDetected);
  369. TWordBitEnum = 0..SizeOf(Word) * 8 - 1;
  370. TWordBitSet = set of TWordBitEnum;
  371. TExifFlashInfo = class(TObjectTagValue)
  372. strict private const
  373. FiredBit = 0;
  374. NotPresentBit = 5;
  375. RedEyeReductionBit = 6;
  376. strict private
  377. function GetBitSet: TWordBitSet;
  378. procedure SetBitSet(const Value: TWordBitSet);
  379. function GetFired: Boolean;
  380. procedure SetFired(Value: Boolean);
  381. function GetMode: TExifFlashMode;
  382. procedure SetMode(const Value: TExifFlashMode);
  383. function GetPresent: Boolean;
  384. procedure SetPresent(Value: Boolean);
  385. function GetRedEyeReduction: Boolean;
  386. procedure SetRedEyeReduction(Value: Boolean);
  387. function GetStrobeEnergy: TExifFraction;
  388. procedure SetStrobeEnergy(const Value: TExifFraction);
  389. function GetStrobeLight: TExifStrobeLight;
  390. procedure SetStrobeLight(const Value: TExifStrobeLight);
  391. public
  392. procedure Assign(Source: TPersistent); override;
  393. function MissingOrInvalid: Boolean; override;
  394. property BitSet: TWordBitSet read GetBitSet write SetBitSet stored False;
  395. published
  396. property Fired: Boolean read GetFired write SetFired stored False;
  397. property Mode: TExifFlashMode read GetMode write SetMode stored False;
  398. property Present: Boolean read GetPresent write SetPresent stored False;
  399. property RedEyeReduction: Boolean read GetRedEyeReduction write SetRedEyeReduction stored False;
  400. property StrobeEnergy: TExifFraction read GetStrobeEnergy write SetStrobeEnergy stored False;
  401. property StrobeLight: TExifStrobeLight read GetStrobeLight write SetStrobeLight stored False;
  402. end;
  403. TExifVersionElement = 0..9;
  404. TCustomExifVersion = class abstract(TObjectTagValue)
  405. strict private
  406. function GetAsString: string;
  407. procedure SetAsString(const Value: string);
  408. function GetMajor: TExifVersionElement;
  409. procedure SetMajor(Value: TExifVersionElement);
  410. function GetMinor: TExifVersionElement;
  411. procedure SetMinor(Value: TExifVersionElement);
  412. function GetRelease: TExifVersionElement;
  413. procedure SetRelease(Value: TExifVersionElement);
  414. protected
  415. FMajorIndex: Integer;
  416. FSectionKind: TExifSectionKind;
  417. FStoreAsChar: Boolean;
  418. FTagID: TExifTagID;
  419. FTiffDataType: TTiffDataType;
  420. constructor Create(const AOwner: TCustomExifData);
  421. procedure Initialize; virtual; abstract;
  422. function GetValue(Index: Integer): TExifVersionElement; virtual;
  423. procedure SetValue(Index: Integer; Value: TExifVersionElement); virtual;
  424. public
  425. procedure Assign(Source: TPersistent); override;
  426. procedure Clear; virtual;
  427. function MissingOrInvalid: Boolean; override;
  428. function ToString: string; override;
  429. property AsString: string read GetAsString write SetAsString;
  430. published
  431. property Major: TExifVersionElement read GetMajor write SetMajor stored False;
  432. property Minor: TExifVersionElement read GetMinor write SetMinor stored False;
  433. property Release: TExifVersionElement read GetRelease write SetRelease stored False;
  434. end;
  435. TExifVersion = class(TCustomExifVersion)
  436. strict private
  437. FValues: array[1..3] of TExifVersionElement;
  438. protected
  439. procedure Initialize; override;
  440. function GetValue(Index: Integer): TExifVersionElement; override;
  441. procedure SetValue(Index: Integer; Value: TExifVersionElement); override;
  442. public
  443. constructor Create(const AOwner: TCustomExifData); overload;
  444. constructor Create; overload;
  445. procedure Clear; override;
  446. end;
  447. TFlashPixVersion = class(TCustomExifVersion)
  448. protected
  449. procedure Initialize; override;
  450. end;
  451. TGPSVersion = class(TCustomExifVersion)
  452. protected
  453. procedure Initialize; override;
  454. end;
  455. TInteropVersion = class(TCustomExifVersion)
  456. protected
  457. procedure Initialize; override;
  458. end;
  459. {$Z2}
  460. TTiffOrientation = (toUndefined, toTopLeft, toTopRight, toBottomRight,
  461. toBottomLeft, toLeftTop{i.e., rotated}, toRightTop, toRightBottom, toLeftBottom);
  462. TExifOrientation = TTiffOrientation;
  463. TTiffResolutionUnit = (trNone = 1, trInch, trCentimetre);
  464. TExifResolutionUnit = TTiffResolutionUnit;
  465. TExifColorSpace = (csTagMissing = 0, csRGB = 1, csAdobeRGB = 2, csWideGamutRGB = $FFFD,
  466. csICCProfile = $FFFE, csUncalibrated = $FFFF);
  467. TExifContrast = (cnTagMissing = -1, cnNormal, cnSoft, cnHard);
  468. TExifExposureMode = (exTagMissing = -1, exAuto, exManual, exAutoBracket);
  469. TExifExposureProgram = (eeTagMissing = -1, eeUndefined, eeManual, eeNormal,
  470. eeAperturePriority, eeShutterPriority, eeCreative, eeAction, eePortrait, eeLandscape);
  471. TExifGainControl = (egTagMissing = -1, egNone, egLowGainUp, egHighGainUp, egLowGainDown, egHighGainDown);
  472. TExifLightSource = (elTagMissing = -1, elUnknown, elDaylight, elFluorescent,
  473. elTungsten, elFlash, elFineWeather = 9, elCloudyWeather, elShade, elDaylightFluorescent,
  474. elDayWhiteFluorescent, elCoolWhiteFluorescent, elWhiteFluorescent,
  475. elStandardLightA = 17, elStandardLightB, elStandardLightC, elD55, elD65,
  476. elD75, elD50, elISOStudioTungsten, elOther = 255);
  477. TExifMeteringMode = (emTagMissing = -1, emUnknown, emAverage, emCenterWeightedAverage,
  478. emSpot, emMultiSpot, emPattern, emPartial);
  479. TExifRendering = (erTagMissing = -1, erNormal, erCustom);
  480. TExifSaturation = (euTagMissing = -1, euNormal, euLow, euHigh);
  481. TExifSceneCaptureType = (ecTagMissing = -1, ecStandard, ecLandscape, ecPortrait, ecNightScene);
  482. TExifSensingMethod = (esTagMissing = -1, esMonochrome = 1, esOneChip, esTwoChip,
  483. esThreeChip, esColorSequential, esTrilinear = 7, esColorSequentialLinear); //esMonochrome was esUndefined before 0.9.7
  484. TExifSharpness = (ehTagMissing = -1, ehNormal, ehSoft, ehHard);
  485. TExifSubjectDistanceRange = (edTagMissing = -1, edUnknown, edMacro, edClose, edDistant);
  486. TExifWhiteBalanceMode = (ewTagMissing = -1, ewAuto, ewManual);
  487. {$Z1}
  488. TCustomExifResolution = class(TObjectTagValue)
  489. strict private
  490. FSchema: TXMPNamespace;
  491. FSection: TExifSection;
  492. FXTagID, FYTagID, FUnitTagID: TExifTagID;
  493. FXName, FYName, FUnitName: UnicodeString;
  494. protected
  495. function GetUnit: TExifResolutionUnit; virtual;
  496. function GetX: TExifFraction; virtual;
  497. function GetY: TExifFraction; virtual;
  498. procedure SetUnit(const Value: TExifResolutionUnit); virtual;
  499. procedure SetX(const Value: TExifFraction); virtual;
  500. procedure SetY(const Value: TExifFraction); virtual;
  501. procedure GetTagInfo(var Section: TExifSectionKind;
  502. var XTag, YTag, UnitTag: TExifTagID; var Schema: TXMPNamespace;
  503. var XName, YName, UnitName: UnicodeString); virtual; abstract;
  504. public
  505. constructor Create(const AOwner: TCustomExifData);
  506. procedure Assign(Source: TPersistent); override;
  507. function MissingOrInvalid: Boolean; override;
  508. function ToString: string; override;
  509. property Section: TExifSection read FSection;
  510. published
  511. property X: TExifFraction read GetX write SetX stored False;
  512. property Y: TExifFraction read GetY write SetY stored False;
  513. property Units: TExifResolutionUnit read GetUnit write SetUnit stored False;
  514. end;
  515. TExifResolution = class(TCustomExifResolution) //standalone
  516. strict private
  517. FX, FY: TExifFraction;
  518. FUnit: TExifResolutionUnit;
  519. protected
  520. function GetUnit: TExifResolutionUnit; override;
  521. function GetX: TExifFraction; override;
  522. function GetY: TExifFraction; override;
  523. procedure SetUnit(const Value: TExifResolutionUnit); override;
  524. procedure SetX(const Value: TExifFraction); override;
  525. procedure SetY(const Value: TExifFraction); override;
  526. procedure GetTagInfo(var Section: TExifSectionKind;
  527. var XTag, YTag, UnitTag: TExifTagID; var Schema: TXMPNamespace;
  528. var XName, YName, UnitName: UnicodeString); override;
  529. public
  530. constructor Create;
  531. procedure Assign(Source: TPersistent); override;
  532. function MissingOrInvalid: Boolean; override;
  533. end;
  534. TImageResolution = class(TCustomExifResolution)
  535. protected
  536. procedure GetTagInfo(var Section: TExifSectionKind;
  537. var XTag, YTag, UnitTag: TExifTagID; var Schema: TXMPNamespace;
  538. var XName, YName, UnitName: UnicodeString); override;
  539. end;
  540. TFocalPlaneResolution = class(TCustomExifResolution)
  541. protected
  542. procedure GetTagInfo(var Section: TExifSectionKind;
  543. var XTag, YTag, UnitTag: TExifTagID; var Schema: TXMPNamespace;
  544. var XName, YName, UnitName: UnicodeString); override;
  545. end;
  546. TThumbnailResolution = class(TCustomExifResolution)
  547. protected
  548. procedure GetTagInfo(var Section: TExifSectionKind;
  549. var XTag, YTag, UnitTag: TExifTagID; var Schema: TXMPNamespace;
  550. var XName, YName, UnitName: UnicodeString); override;
  551. end;
  552. TISOSpeedRatings = class(TObjectTagValue)
  553. strict private const
  554. XMPSchema = xsExif;
  555. XMPKind = xpSeqArray;
  556. XMPName = UnicodeString('ISOSpeedRatings');
  557. strict private
  558. function GetAsString: string;
  559. procedure SetAsString(const Value: string);
  560. function GetCount: Integer;
  561. function GetItem(Index: Integer): Word;
  562. procedure SetCount(const Value: Integer);
  563. procedure SetItem(Index: Integer; const Value: Word);
  564. protected
  565. procedure Clear;
  566. function FindTag(VerifyDataType: Boolean; out Tag: TExifTag): Boolean;
  567. public
  568. procedure Assign(Source: TPersistent); override;
  569. function MissingOrInvalid: Boolean; override;
  570. function ToString: string; override;
  571. property Items[Index: Integer]: Word read GetItem write SetItem; default;
  572. published
  573. property AsString: string read GetAsString write SetAsString stored False;
  574. property Count: Integer read GetCount write SetCount stored False;
  575. end;
  576. TExifFileSource = (fsUnknown, fsFilmScanner, fsReflectionPrintScanner, fsDigitalCamera);
  577. TExifSceneType = (esUnknown, esDirectlyPhotographed);
  578. TGPSLatitudeRef = (ltMissingOrInvalid, ltNorth, ltSouth);
  579. TGPSLongitudeRef = (lnMissingOrInvalid, lnWest, lnEast);
  580. TGPSAltitudeRef = (alTagMissing = -1, alAboveSeaLevel, alBelowSeaLevel); //!!!corrected v1.5.2
  581. TGPSStatus = (stMissingOrInvalid, stMeasurementActive, stMeasurementVoid);
  582. TGPSMeasureMode = (mmUnknown, mm2D, mm3D);
  583. TGPSSpeedRef = (srMissingOrInvalid, srKilometresPerHour, srMilesPerHour, srKnots); //Exif spec makes KM/h the default value
  584. TGPSDirectionRef = (drMissingOrInvalid, drTrueNorth, drMagneticNorth);
  585. TGPSDistanceRef = (dsMissingOrInvalid, dsKilometres, dsMiles, dsKnots);
  586. {$Z2}
  587. TGPSDifferential = (dfTagMissing = -1, dfWithoutCorrection, dfCorrectionApplied);
  588. {$Z1}
  589. TCustomGPSFraction = class(TEnumObjectTagValue)
  590. strict private
  591. FMainTagID, FRefTagID: TExifTagID;
  592. function GetDenominator: LongWord;
  593. function GetNumerator: LongWord;
  594. function GetQuotient: Extended;
  595. protected
  596. constructor Create(const AOwner: TCustomExifData;
  597. AMainTagID, ARefTagID: TExifTagID); overload;
  598. function GetValue: TExifFraction; virtual;
  599. procedure SetValue(const Value: TExifFraction); virtual;
  600. function GetRefChar: AnsiChar; virtual;
  601. procedure SetRefChar(const Value: AnsiChar); virtual;
  602. property MainTagID: TExifTagID read FMainTagID;
  603. property RefTagID: TExifTagID read FRefTagID;
  604. public
  605. procedure Assign(Source: TPersistent); override;
  606. function MissingOrInvalid: Boolean; override;
  607. function ToString: string; override;
  608. property Numerator: LongWord read GetNumerator;
  609. property Denominator: LongWord read GetDenominator;
  610. property Quotient: Extended read GetQuotient;
  611. property Ref: AnsiChar read GetRefChar write SetRefChar;
  612. property Value: TExifFraction read GetValue write SetValue;
  613. end;
  614. TGPSFraction = class(TCustomGPSFraction) //standalone
  615. strict private
  616. FRefChar: AnsiChar;
  617. FValue: TExifFraction;
  618. protected
  619. function GetValue: TExifFraction; override;
  620. procedure SetValue(const NewValue: TExifFraction); override;
  621. function GetRefChar: AnsiChar; override;
  622. procedure SetRefChar(const Value: AnsiChar); override;
  623. public
  624. constructor Create;
  625. end;
  626. TGPSAltitude = class(TCustomGPSFraction, IEnumToCharMapper, IEnumToCharMapperEx)
  627. strict private
  628. function GetRef: TGPSAltitudeRef;
  629. procedure SetRef(const Value: TGPSAltitudeRef);
  630. protected
  631. function GetRefChar: AnsiChar; override;
  632. procedure SetRefChar(const Value: AnsiChar); override;
  633. { IEnumToCharMapper/Ex - no RTTI, so need to provide min and max ordinal values explicitly }
  634. function EnumValueToChar(OrdValue: Integer): AnsiChar;
  635. function CharToEnumValue(Ch: AnsiChar): Integer;
  636. function GetEnumTypeInfo: PTypeInfo;
  637. function GetMinEnumValue: Integer;
  638. function GetMaxEnumValue: Integer;
  639. function GetEnumName(OrdValue: Integer): string;
  640. public
  641. function ToString: string; override;
  642. property Ref: TGPSAltitudeRef read GetRef write SetRef;
  643. end;
  644. TGPSSpeed = class(TCustomGPSFraction, IEnumToCharMapper)
  645. strict private
  646. function GetRef: TGPSSpeedRef; inline;
  647. procedure SetRef(const Value: TGPSSpeedRef); inline;
  648. protected
  649. { IEnumToCharMapper }
  650. function EnumValueToChar(OrdValue: Integer): AnsiChar;
  651. function CharToEnumValue(Ch: AnsiChar): Integer;
  652. function GetEnumTypeInfo: PTypeInfo;
  653. public
  654. function ToString: string; override;
  655. property Ref: TGPSSpeedRef read GetRef write SetRef;
  656. end;
  657. TCustomGPSFractionWithDirection = class(TCustomGPSFraction, IEnumToCharMapper)
  658. strict private
  659. function GetRef: TGPSDirectionRef; inline;
  660. procedure SetRef(const Value: TGPSDirectionRef); inline;
  661. protected
  662. { IEnumToCharMapper }
  663. function EnumValueToChar(OrdValue: Integer): AnsiChar;
  664. function CharToEnumValue(Ch: AnsiChar): Integer;
  665. function GetEnumTypeInfo: PTypeInfo;
  666. public
  667. function ToString: string; override;
  668. property Ref: TGPSDirectionRef read GetRef write SetRef;
  669. end;
  670. TGPSTrack = class(TCustomGPSFractionWithDirection)
  671. end;
  672. TGPSImgDirection = class(TCustomGPSFractionWithDirection)
  673. end;
  674. TGPSDestBearing = class(TCustomGPSFractionWithDirection)
  675. end;
  676. TGPSDestDistance = class(TCustomGPSFraction, IEnumToCharMapper)
  677. strict private
  678. function GetRef: TGPSDistanceRef; inline;
  679. procedure SetRef(const Value: TGPSDistanceRef); inline;
  680. protected
  681. { IEnumToCharMapper }
  682. function EnumValueToChar(OrdValue: Integer): AnsiChar;
  683. function CharToEnumValue(Ch: AnsiChar): Integer;
  684. function GetEnumTypeInfo: PTypeInfo;
  685. public
  686. function ToString: string; override;
  687. property Ref: TGPSDistanceRef read GetRef write SetRef;
  688. end;
  689. TCustomGPSCoordinate = class(TEnumObjectTagValue)
  690. strict private
  691. FRefTagID, FTagID: TExifTagID;
  692. FXMPName: UnicodeString;
  693. procedure AssignCoordinate(Source: TCustomGPSCoordinate);
  694. protected
  695. constructor Create(const AOwner: TCustomExifData; const ATagID: TExifTagID); overload;
  696. procedure Assign(const ADegrees, AMinutes, ASeconds: TExifFraction;
  697. ADirectionChar: AnsiChar); reintroduce; overload; virtual;
  698. function GetDirectionChar: AnsiChar; virtual;
  699. function GetValue(Index: Integer): TExifFraction; virtual;
  700. procedure SetDirectionChar(NewChar: AnsiChar); virtual;
  701. function TryGetTag(out Tag: TExifTag): Boolean;
  702. property RefTagID: TExifTagID read FRefTagID;
  703. property TagID: TExifTagID read FTagID;
  704. property XMPName: UnicodeString read FXMPName;
  705. public
  706. procedure Assign(Source: TPersistent); overload; override;
  707. function MissingOrInvalid: Boolean; override;
  708. function ToString: string; override;
  709. property Degrees: TExifFraction index 0 read GetValue;
  710. property Minutes: TExifFraction index 1 read GetValue;
  711. property Seconds: TExifFraction index 2 read GetValue;
  712. property Direction: AnsiChar read GetDirectionChar write SetDirectionChar; //not DirectionChar so that it gets hidden by properly typed version in descendant classes
  713. published
  714. property AsString: string read ToString;
  715. end;
  716. TGPSCoordinate = class(TCustomGPSCoordinate) //standalone
  717. strict private
  718. FDirectionChar: AnsiChar;
  719. FValues: array[0..2] of TExifFraction;
  720. protected
  721. procedure AssignTo(Dest: TPersistent); override;
  722. function GetDirectionChar: AnsiChar; override;
  723. function GetValue(Index: Integer): TExifFraction; override;
  724. procedure SetDirectionChar(NewChar: AnsiChar); override;
  725. public
  726. constructor Create;
  727. procedure Assign(const ADegrees, AMinutes, ASeconds: TExifFraction;
  728. ADirectionChar: AnsiChar); override;
  729. property Degrees write FValues[0];
  730. property Minutes write FValues[1];
  731. property Seconds write FValues[2];
  732. end;
  733. TGPSLatitude = class(TCustomGPSCoordinate, IEnumToCharMapper)
  734. strict private
  735. function GetDirection: TGPSLatitudeRef; inline;
  736. protected
  737. { IEnumToCharMapper }
  738. function EnumValueToChar(OrdValue: Integer): AnsiChar;
  739. function CharToEnumValue(Ch: AnsiChar): Integer;
  740. function GetEnumTypeInfo: PTypeInfo;
  741. public
  742. procedure Assign(const ADegrees, AMinutes, ASeconds: TExifFraction;
  743. ADirection: TGPSLatitudeRef); reintroduce; overload;
  744. procedure Assign(ADegrees, AMinutes: LongWord; const ASeconds: TExifFraction;
  745. ADirection: TGPSLatitudeRef); reintroduce; overload; inline;
  746. procedure Assign(ADegrees, AMinutes: LongWord; const ASeconds: Currency;
  747. ADirection: TGPSLatitudeRef); reintroduce; overload; inline;
  748. procedure Assign(ADegrees, AMinutes, ASeconds: LongWord;
  749. ADirection: TGPSLatitudeRef); reintroduce; overload; inline;
  750. property Direction: TGPSLatitudeRef read GetDirection;
  751. end;
  752. TGPSLongitude = class(TCustomGPSCoordinate, IEnumToCharMapper)
  753. strict private
  754. function GetDirection: TGPSLongitudeRef; inline;
  755. protected
  756. { IEnumToCharMapper }
  757. function EnumValueToChar(OrdValue: Integer): AnsiChar;
  758. function CharToEnumValue(Ch: AnsiChar): Integer;
  759. function GetEnumTypeInfo: PTypeInfo;
  760. public
  761. procedure Assign(const ADegrees, AMinutes, ASeconds: TExifFraction;
  762. ADirection: TGPSLongitudeRef); reintroduce; overload;
  763. procedure Assign(ADegrees, AMinutes: LongWord; const ASeconds: TExifFraction;
  764. ADirection: TGPSLongitudeRef); reintroduce; overload; inline;
  765. procedure Assign(ADegrees, AMinutes: LongWord; const ASeconds: Currency;
  766. ADirection: TGPSLongitudeRef); reintroduce; overload; inline;
  767. procedure Assign(ADegrees, AMinutes, ASeconds: LongWord;
  768. ADirection: TGPSLongitudeRef); reintroduce; overload; inline;
  769. property Direction: TGPSLongitudeRef read GetDirection;
  770. end;
  771. { To add support for a different MakerNote format, you need to write a descendent of
  772. TExifMakerNote, implementing the protected version of FormatIsOK and probably
  773. GetIFDInfo too, before registering it via TExifData.RegisterMakerNoteType. }
  774. TExifDataOffsetsType = (doFromExifStart, doFromMakerNoteStart, doFromIFDStart,
  775. doCustomFormat); //!!!added doCustomFormat v1.5.0
  776. TExifMakerNote = class abstract
  777. strict private
  778. FDataOffsetsType: TExifDataOffsetsType;
  779. FEndianness: TEndianness;
  780. FTags: TExifSection;
  781. protected
  782. class function FormatIsOK(SourceTag: TExifTag;
  783. out HeaderSize: Integer): Boolean; overload; virtual; abstract;
  784. procedure GetIFDInfo(SourceTag: TExifTag; var ProbableEndianness: TEndianness;
  785. var DataOffsetsType: TExifDataOffsetsType); virtual;
  786. function GetFractionValue(TagID: Integer): TExifFraction;
  787. function GetTagAsString(TagID: Integer): string;
  788. //procedure RewriteSourceTag(Tag: TExifTag); virtual;
  789. //procedure WriteHeader(Stream: TStream); virtual; abstract;
  790. //procedure SaveToStream(Stream: TStream; const StartPos: Int64);
  791. public
  792. constructor Create(ASection: TExifSection);
  793. class function FormatIsOK(SourceTag: TExifTag): Boolean; overload;
  794. property DataOffsetsType: TExifDataOffsetsType read FDataOffsetsType;
  795. property Endianness: TEndianness read FEndianness;
  796. property Tags: TExifSection read FTags;
  797. end;
  798. TExifMakerNoteClass = class of TExifMakerNote;
  799. TUnrecognizedMakerNote = class sealed(TExifMakerNote)
  800. protected
  801. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  802. end;
  803. THeaderlessMakerNote = class(TExifMakerNote) //special type tried as a last resort; also serves as a
  804. protected //nominal base class for a few of the concrete implementations
  805. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  806. end;
  807. TAppleMakerNote = class(TExifMakerNote)
  808. protected
  809. const Header: array[0..13] of AnsiChar = 'Apple iOS'#0#0#1'MM';
  810. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  811. procedure GetIFDInfo(SourceTag: TExifTag; var ProbableEndianness: TEndianness;
  812. var DataOffsetsType: TExifDataOffsetsType); override;
  813. end;
  814. TCanonMakerNote = class(THeaderlessMakerNote)
  815. protected
  816. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  817. procedure GetIFDInfo(SourceTag: TExifTag; var ProbableEndianness: TEndianness;
  818. var DataOffsetsType: TExifDataOffsetsType); override;
  819. end;
  820. TCasioMakerNote = class(THeaderlessMakerNote)
  821. protected
  822. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  823. end;
  824. TCasio2MakerNote = class(TExifMakerNote)
  825. protected
  826. const Header: array[0..5] of AnsiChar = 'QVC';
  827. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  828. end;
  829. TKodakMakerNote = class(TExifMakerNote) //!!!work in very early progress
  830. public type
  831. TTagSpec = record
  832. DataType: TTiffDataType;
  833. ElementCount: Byte;
  834. constructor Create(ADataType: TTiffDataType; AElementCount: Byte = 1);
  835. end;
  836. class var TagSpecs: array of TTagSpec;
  837. class procedure InitializeTagSpecs; static;
  838. protected
  839. const HeaderSize = 8;
  840. const BigEndianHeader: array[0..HeaderSize - 1] of AnsiChar = 'KDK INFO';
  841. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  842. procedure GetIFDInfo(SourceTag: TExifTag; var Endianness: TEndianness;
  843. var DataOffsetsType: TExifDataOffsetsType); override;
  844. end experimental;
  845. TKonicaMinoltaMakerNote = class(THeaderlessMakerNote)
  846. protected
  847. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  848. end;
  849. TPanasonicMakerNote = class(TExifMakerNote)
  850. protected
  851. const Header: array[0..11] of AnsiChar = 'Panasonic';
  852. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  853. procedure GetIFDInfo(SourceTag: TExifTag; var ProbableEndianness: TEndianness;
  854. var DataOffsetsType: TExifDataOffsetsType); override;
  855. end;
  856. TPentaxMakerNote = class(TExifMakerNote) //won't actually parse the structure, just identify it
  857. protected
  858. const Header: array[0..3] of AnsiChar = 'AOC'#0;
  859. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  860. end;
  861. TNikonType1MakerNote = class(TExifMakerNote)
  862. protected
  863. const Header: array[0..7] of AnsiChar = 'Nikon'#0#1#0;
  864. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  865. end;
  866. TNikonType2MakerNote = class(THeaderlessMakerNote)
  867. protected
  868. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  869. end;
  870. TNikonType3MakerNote = class(TExifMakerNote)
  871. protected
  872. const HeaderStart: array[0..6] of AnsiChar = 'Nikon'#0#2;
  873. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  874. procedure GetIFDInfo(SourceTag: TExifTag; var ProbableEndianness: TEndianness;
  875. var DataOffsetsType: TExifDataOffsetsType); override;
  876. public
  877. property ColorMode: string index ttNikonType3ColorMode read GetTagAsString;
  878. property Quality: string index ttNikonType3Quality read GetTagAsString;
  879. property WhiteBalance: string index ttNikonType3WhiteBalance read GetTagAsString;
  880. property Sharpening: string index ttNikonType3Sharpening read GetTagAsString;
  881. property FocusMode: string index ttNikonType3FocusMode read GetTagAsString;
  882. property FlashSetting: string index ttNikonType3FlashSetting read GetTagAsString;
  883. property AutoFlashMode: string index ttNikonType3AutoFlashMode read GetTagAsString;
  884. property MiscRatio: TExifFraction index ttNikonType3MiscRatio read GetFractionValue;
  885. property ISOSelection: string index ttNikonType3ISOSelection read GetTagAsString;
  886. property AutoExposureBracketComp: TExifFraction index ttNikonType3AutoExposureBracketComp read GetFractionValue;
  887. property SerialNumber: string index ttNikonType3SerialNumber read GetTagAsString;
  888. property ImageAdjustment: string index ttNikonType3ImageAdjustment read GetTagAsString;
  889. property ToneComp: string index ttNikonType3ToneComp read GetTagAsString;
  890. property AuxiliaryLens: string index ttNikonType3AuxiliaryLens read GetTagAsString;
  891. property DigitalZoom: TExifFraction index ttNikonType3DigitalZoom read GetFractionValue;
  892. property SceneMode: string index ttNikonType3SceneMode read GetTagAsString;
  893. property LightSource: string index ttNikonType3LightSource read GetTagAsString;
  894. property NoiseReduction: string index ttNikonType3NoiseReduction read GetTagAsString;
  895. property SceneAssist: string index ttNikonType3SceneAssist read GetTagAsString;
  896. property CameraSerialNumber: string index ttNikonType3CameraSerialNumber read GetTagAsString;
  897. property Saturation: string index ttNikonType3Saturation read GetTagAsString;
  898. property DigitalVarProgram: string index ttNikonType3DigitalVarProg read GetTagAsString;
  899. property ImageStabilization: string index ttNikonType3ImageStabilization read GetTagAsString;
  900. property AFResponse: string index ttNikonType3AFResponse read GetTagAsString;
  901. property CaptureVersion: string index ttNikonType3CaptureVersion read GetTagAsString;
  902. end;
  903. TSonyMakerNote = class(TExifMakerNote)
  904. protected
  905. const Header: array[0..7] of AnsiChar = 'SONY DSC';
  906. class function FormatIsOK(SourceTag: TExifTag; out HeaderSize: Integer): Boolean; override;
  907. procedure GetIFDInfo(SourceTag: TExifTag; var ProbableEndianness: TEndianness;
  908. var DataOffsetsType: TExifDataOffsetsType); override;
  909. end;
  910. EInvalidExifData = class(ECCRExifException);
  911. TJPEGMetaDataKind = (mkExif, mkIPTC, mkXMP);
  912. TJPEGMetadataKinds = set of TJPEGMetadataKind;
  913. TCustomExifData = class(TComponent)
  914. public type
  915. TEnumerator = record
  916. strict private
  917. FClient: TCustomExifData;
  918. FDoneFirst: Boolean;
  919. FSection: TExifSectionKind;
  920. function GetCurrent: TExifSection; {$IFDEF CanInline}inline;{$ENDIF}
  921. public
  922. constructor Create(AClient: TCustomExifData);
  923. function MoveNext: Boolean;
  924. property Current: TExifSection read GetCurrent;
  925. end;
  926. TMakerNoteTypePriority = (mtTestForLast, mtTestForFirst);
  927. strict private class var
  928. Diag35mm: Extended;
  929. FMakerNoteClasses: TClassList;
  930. private
  931. class procedure InitializeClass(const MakerNoteClasses: array of TExifMakerNoteClass);
  932. class procedure FinalizeClass;
  933. procedure SetGPSDestBearing(const Value: TGPSDestBearing);
  934. procedure SetGPSImgDirection(const Value: TGPSImgDirection);
  935. procedure SetGPSTrack(const Value: TGPSTrack);
  936. strict private
  937. FAlwaysWritePreciseTimes: Boolean;
  938. FChangedWhileUpdating: Boolean;
  939. FEmbeddedIPTC: TIPTCData;
  940. FEndianness: TEndianness;
  941. FEnforceASCII: Boolean;
  942. FEnsureEnumsInRange: Boolean;
  943. FExifVersion: TCustomExifVersion;
  944. FFlash: TExifFlashInfo;
  945. FFlashPixVersion: TCustomExifVersion;
  946. FFocalPlaneResolution: TCustomExifResolution;
  947. FGPSAltitude: TGPSAltitude;
  948. FGPSDestBearing: TGPSDestBearing;
  949. FGPSDestDistance: TGPSDestDistance;
  950. FGPSImgDirection: TGPSImgDirection;
  951. FGPSLatitude, FGPSDestLatitude: TGPSLatitude;
  952. FGPSLongitude, FGPSDestLongitude: TGPSLongitude;
  953. FGPSSpeed: TGPSSpeed;
  954. FGPSTrack: TGPSTrack;
  955. FGPSVersion: TCustomExifVersion;
  956. FInteropVersion: TCustomExifVersion;
  957. FISOSpeedRatings: TISOSpeedRatings;
  958. FMakerNoteType: TExifMakerNoteClass;
  959. FMakerNoteValue: TExifMakerNote;
  960. FOffsetBase: Int64;
  961. FModified: Boolean;
  962. FResolution: TCustomExifResolution;
  963. FSections: array[TExifSectionKind] of TExifSection;
  964. FThumbnailOrNil: TJPEGImage;
  965. FThumbnailResolution: TCustomExifResolution;
  966. FUpdateCount: Integer;
  967. FXMPPacket: TXMPPacket;
  968. FOnChange: TNotifyEvent;
  969. procedure SetEndianness(Value: TEndianness);
  970. function GetMakerNote: TExifMakerNote;
  971. function GetSection(Section: TExifSectionKind): TExifSection; //inline;
  972. procedure SetModified(Value: Boolean);
  973. function GetThumbnail: TJPEGImage;
  974. procedure SetThumbnail(Value: TJPEGImage);
  975. procedure ThumbnailChanged(Sender: TObject);
  976. function GetDateTime: TDateTimeTagValue;
  977. procedure SetDateTime(const Value: TDateTimeTagValue);
  978. function GetGeneralString(TagID: Integer): string;
  979. procedure SetGeneralString(TagID: Integer; const Value: string);
  980. function GetGeneralWinString(TagID: Integer): UnicodeString;
  981. procedure SetGeneralWinString(TagID: Integer; const Value: UnicodeString);
  982. function GetDetailsDateTime(TagID: Integer): TDateTimeTagValue;
  983. procedure SetDetailsDateTime(TagID: Integer; const Value: TDateTimeTagValue);
  984. function GetDetailsFraction(TagID: Integer): TExifFraction;
  985. procedure SetDetailsFraction(TagID: Integer; const Value: TExifFraction);
  986. function GetDetailsSFraction(TagID: Integer): TExifSignedFraction;
  987. procedure SetDetailsSFraction(TagID: Integer; const Value: TExifSignedFraction);
  988. function GetOffsetSchema: TLongIntTagValue;
  989. procedure SetOffsetSchema(const Value: TLongIntTagValue);
  990. function GetDetailsLongWord(TagID: Integer): TLongWordTagValue;
  991. function GetDetailsString(TagID: Integer): string;
  992. procedure SetDetailsString(TagID: Integer; const Value: string);
  993. function GetAuthor: UnicodeString;
  994. procedure SetAuthor(const Value: UnicodeString);
  995. function GetComments: UnicodeString;
  996. procedure SetComments(const Value: UnicodeString);
  997. function GetUserRating: TWindowsStarRating;
  998. procedure SetUserRating(const Value: TWindowsStarRating);
  999. procedure SetFlash(Value: TExifFlashInfo);
  1000. procedure SetFocalPlaneResolution(Value: TCustomExifResolution);
  1001. procedure SetResolution(Value: TCustomExifResolution);
  1002. procedure SetThumbnailResolution(Value: TCustomExifResolution);
  1003. procedure SetGPSVersion(Valu