(* ImageEn Build 7.0.0.06.2637 @ 7-4-17 14:58:42.679 *) (* Copyright (c) 1998-2017 by Carlotta Calandra. All rights reserved. Copyright (c) 2011-2017 by Xequte Software. This software comes without express or implied warranty. In no case shall the author be liable for any damage or unwanted behavior of any computer hardware and/or software. Author grants you the right to include the component in your application, whether COMMERCIAL, SHAREWARE, or FREEWARE. ImageEn, IEvolution and ImageEn ActiveX may not be included in any commercial, shareware or freeware libraries or components. www.ImageEn.com *) (* File: iexMetaHelpers.pas Description: Helper functions for working with EXIF, IPTC, Dicom meta data File version: 1034 Notes: - Requires: Delphi 2005 or newer - TListView enhancements by William Miller, Adirondack Software & Graphics *) // STRING GRID SUPPORT // Define to include methods for loading and saving content to/from TStringGrids {$DEFINE USE_STRINGGRIDS} // LIST VIEW SUPPORT // Define to include methods for loading and saving content to/from TListViews {$DEFINE USE_LISTVIEW} unit iexMetaHelpers; {$I ie.inc} interface uses {$IFDEF USE_STRINGGRIDS} grids, {$ENDIF} {$IFDEF USE_LISTVIEW} ComCtrls, {$ENDIF} ImageEnIO, dialogs, Sysutils, math, Graphics, Classes, iexBitmaps; type {!! TIEDicomInclude Declaration TIEDicomInclude = set of (diDeprecated, diProprietary, diChildTags, diUnknown); Description Value Description diDeprecated Include tags that have been retired in the NEMA standard diProprietary Include tags that are not in the NEMA standard (vendor specific tags) diChildTags Include subordinate tags (children of parent tags) diUnknown Include tags even if they do not have a description
!!} TIEDicomInclude = set of (diDeprecated, diProprietary, diChildTags, diUnknown); {$IFDEF Delphi2005orNewer} {!! TIOParamsHelper Declaration TIOParamsHelper = class helper for TIOParams Description !!} // TIOParamsHelper Helper Functions TIOParamsHelper = class helper for TIOParams private function GetEXIF_ApertureValue_Str : string; function GetEXIF_Camera_Str : AnsiString; function GetEXIF_ExposureTime_Str : string; function GetEXIF_FNumber_Str : string; function GetEXIF_MaxApertureValue_Str : string; function GetEXIF_ShutterSpeedValue_Str : string; function GetEXIF_XResolution_Str : AnsiString; function GetEXIF_YResolution_Str : AnsiString; function GetEXIF_AsStr(Index: Integer): string; function GetEXIF_FieldDescription(Index: Integer): string; function GetEXIF_CanWriteEXIFData : Boolean; function GetEXIF_SubjectArea_Str : string; function GetEXIF_SubjectLocation_Str : string; function GetXMP_AsStr(const Field: String): string; function GetXMP_AsInt(const Field: String): Integer; function GetXMP_AsDateTime(const Field: String): TDateTime; procedure SetEXIF_ApertureValue_Str(const value : string); procedure SetEXIF_Camera_Str(const value : AnsiString); procedure SetEXIF_ExposureTime_Str(value : string); procedure SetEXIF_FNumber_Str(value : string); procedure SetEXIF_MaxApertureValue_Str(const value : string); procedure SetEXIF_ShutterSpeedValue_Str(const value : string); procedure SetEXIF_XResolution_Str(value : AnsiString); procedure SetEXIF_YResolution_Str(value : AnsiString); procedure SetEXIF_SubjectLocation_Str(value : string); procedure SetEXIF_AsStr(Index: Integer; value : string); public property EXIF_AsStr [index : Integer]: string read GetEXIF_AsStr write SetEXIF_AsStr; property EXIF_FieldDescription [index : Integer]: string read GetEXIF_FieldDescription; property EXIF_CanWriteEXIFData : Boolean read GetEXIF_CanWriteEXIFData; property EXIF_ApertureValue_Str : string read GetEXIF_ApertureValue_Str write SetEXIF_ApertureValue_Str; property EXIF_Camera_Str : AnsiString read GetEXIF_Camera_Str write SetEXIF_Camera_Str; property EXIF_ExposureTime_Str : string read GetEXIF_ExposureTime_Str write SetEXIF_ExposureTime_Str; property EXIF_FNumber_Str : string read GetEXIF_FNumber_Str write SetEXIF_FNumber_Str; property EXIF_MaxApertureValue_Str : string read GetEXIF_MaxApertureValue_Str write SetEXIF_MaxApertureValue_Str; property EXIF_ShutterSpeedValue_Str : string read GetEXIF_ShutterSpeedValue_Str write SetEXIF_ShutterSpeedValue_Str; property EXIF_XResolution_Str : AnsiString read GetEXIF_XResolution_Str write SetEXIF_XResolution_Str; property EXIF_YResolution_Str : AnsiString read GetEXIF_YResolution_Str write SetEXIF_YResolution_Str; property EXIF_SubjectArea_Str : string read GetEXIF_SubjectArea_Str; property EXIF_SubjectLocation_Str : string read GetEXIF_SubjectLocation_Str write SetEXIF_SubjectLocation_Str; property XMP_AsStr[const Field : string] : string read GetXMP_AsStr; property XMP_AsInt[const Field : string] : Integer read GetXMP_AsInt; property XMP_AsDateTime[const Field : string] : TDateTime read GetXMP_AsDateTime; {$ifdef IEINCLUDEDICOM} function DICOM_FindTag(Group: Word; Element: Word): PIEDicomTag; {$endif} function IPTC_HasIPTCData : Boolean; function DICOM_HasDicomTags : Boolean; function XMP_HasXMPData : Boolean; function EXIF_WriteToStrings(Dest : TStrings) : Boolean; function IPTC_WriteToStrings(Dest : TStrings) : Boolean; {$ifdef IEINCLUDEDICOM} function DICOM_WriteToStrings(Dest : TStrings; TagInclude: TIEDicomInclude) : Boolean; {$endif} function XMP_WriteToStrings(Dest : TStrings) : Boolean; end; {$ENDIF} {$IFDEF USE_STRINGGRIDS} {$IFDEF Delphi2005orNewer} {!! TStringGridHelper Declaration TStringGridHelper = class helper for TStringGrid Description !!} // TStringGridHelper Helper Functions TStringGridHelper = class helper for TStringGrid private public // EXIF procedure NewGridForExif(bReadOnly : Boolean = False); function ReadGridFromExif(IOParams : TIOParams; bReadOnly : Boolean = False) : Boolean; overload; function ReadGridFromExif(const sFilename : string; bReadOnly : Boolean = False) : Boolean; overload; function WriteGridToExif(IOParams : TIOParams) : Boolean; overload; function WriteGridToExif(const sFilename : string) : Boolean; overload; // IPTC procedure NewGridForIPTC(bReadOnly : Boolean = False); function ReadGridFromIPTC(IOParams : TIOParams; bReadOnly : Boolean = False) : Boolean; overload; function ReadGridFromIPTC(const sFilename : string; bReadOnly : Boolean = False) : Boolean; overload; function WriteGridToIPTC(IOParams : TIOParams) : Boolean; overload; function WriteGridToIPTC(const sFilename : string) : Boolean; overload; // DICOM {$ifdef IEINCLUDEDICOM} function ReadGridFromDicom(IOParams : TIOParams; TagInclude: TIEDicomInclude) : Boolean; overload; function ReadGridFromDicom(const sFilename : string; TagInclude: TIEDicomInclude) : Boolean; overload; {$endif} // XMP function ReadGridFromXMP(IOParams : TIOParams) : Boolean; overload; function ReadGridFromXMP(const sFilename : string) : Boolean; overload; // GENERAL procedure InitializeGrid(bFixLayout : Boolean = True); procedure ClearGridFields; end; {$ENDIF} {$ENDIF} {$IFDEF USE_LISTVIEW} {$IFDEF Delphi2005orNewer} {!! TListViewHelper Declaration TListViewHelper = class helper for TListView Description !!} // TListViewHelper Helper Functions TListViewHelper = class helper for TListView private public // EXIF procedure NewListForExif(); function ReadListFromExif(IOParams : TIOParams) : Boolean; overload; function ReadListFromExif(const sFilename : string) : Boolean; overload; function WriteListToExif(IOParams : TIOParams) : Boolean; overload; function WriteListToExif(const sFilename : string) : Boolean; overload; // IPTC procedure NewListForIPTC(); function ReadListFromIPTC(IOParams : TIOParams) : Boolean; overload; function ReadListFromIPTC(const sFilename : string) : Boolean; overload; function WriteListToIPTC(IOParams : TIOParams) : Boolean; overload; function WriteListToIPTC(const sFilename : string) : Boolean; overload; // DICOM {$ifdef IEINCLUDEDICOM} function ReadListFromDicom(IOParams : TIOParams; TagInclude: TIEDicomInclude) : Boolean; overload; function ReadListFromDicom(const sFilename : string; TagInclude: TIEDicomInclude) : Boolean; overload; {$endif} // XMP function ReadListFromXMP(IOParams : TIOParams) : Boolean; overload; function ReadListFromXMP(const sFilename : string) : Boolean; overload; // GENERAL procedure InitializeList(bFixLayout : Boolean = True); procedure ClearListFields; end; {$ENDIF} {$ENDIF} // GENERAL EXIF METHODS function ExifCompatibleFile(const sFilename: string): boolean; {$IFDEF Delphi2005orNewer} function ReadExifCameraFieldsFromFile(const sFilename : string; out sCameraModel : string; out sExposureTime : string; out sFlashMode : string ) : boolean; {$ENDIF} function ReadExifGPSFieldsFromFile(const sFilename : string; out GPSLatitude: Double; out GPSLongitude: Double ) : boolean; overload; function ReadExifGPSFieldsFromFile(const sFilename : string; out sGPSLatitude: string; out sGPSLongitude: string ) : boolean; overload; // EXIF TAG METHODS procedure GetExifTagList(ssDest: TStrings); function ContainsExifTag(const Text: string): Boolean; {$IFDEF Delphi2005orNewer} function ReplaceExifTags(const Text: string; EXIFSource : TIOParams): string; overload; function ReplaceExifTags(const Text: string; const sEXIFSourceFilename : string): string; overload; {$ENDIF} // GENERAL IPTC METHODS function IPTCCompatibleFile(const sFilename: string): boolean; function ReadIPTCDescriptionAndKeywordsFromFile(const sFilename: string; out sDescription: string; ssKeywords: TStrings = nil) : Boolean; procedure WriteIPTCDescriptionAndKeywordsToFile(const sFilename: string; sDescription: string; ssKeywords: TStrings = nil); // OTHER METHODS function DicomCompatibleFile(const sFilename: string): boolean; function XMPCompatibleFile(const sFilename: string): boolean; // EXIF handling functions function DoubleToFraction(dValue: double): string; function FractionToDouble(dValue: string): double; function ApexToStr(dBase: double; dValue: double; const sPrepend: string): string; function StrToApex(dBase: double; Value: string; sPrepended: string ): double; {!! EXIF Consts for EXIF_AsStr Declaration } const _EXIF_UserComment = 0; _EXIF_ImageDescription = 1; _EXIF_CameraMake = 2; _EXIF_CameraModel = 3; _EXIF_XResolution = 4; _EXIF_YResolution = 5; _EXIF_DateTime = 6; _EXIF_DateTimeOriginal = 7; _EXIF_DateTimeDigitized = 8; _EXIF_Copyright = 9; _EXIF_Orientation = 10; _EXIF_ExposureTime = 11; _EXIF_FNumber = 12; _EXIF_ExposureProgram = 13; _EXIF_ISOSpeedRatings = 14; _EXIF_ShutterSpeedValue = 15; _EXIF_ApertureValue = 16; _EXIF_BrightnessValue = 17; _EXIF_ExposureBiasValue = 18; _EXIF_MaxApertureValue = 19; _EXIF_SubjectDistance = 20; _EXIF_MeteringMode = 21; _EXIF_LightSource = 22; _EXIF_Flash = 23; _EXIF_FocalLength = 24; _EXIF_FlashPixVersion = 25; _EXIF_ColorSpace = 26; _EXIF_ExifImageWidth = 27; _EXIF_ExifImageHeight = 28; _EXIF_RelatedSoundFile = 29; _EXIF_FocalPlaneXResolution = 30; _EXIF_FocalPlaneYResolution = 31; _EXIF_ExposureIndex = 32; _EXIF_SensingMethod = 33; _EXIF_FileSource = 34; _EXIF_SceneType = 35; _EXIF_YCbCrPositioning = 36; _EXIF_ExposureMode = 37; _EXIF_WhiteBalance = 38; _EXIF_DigitalZoomRatio = 39; _EXIF_FocalLengthIn35mmFilm = 40; _EXIF_SceneCaptureType = 41; _EXIF_GainControl = 42; _EXIF_Contrast = 43; _EXIF_Saturation = 44; _EXIF_Sharpness = 45; _EXIF_SubjectDistanceRange = 46; _EXIF_GPSLatitude = 47; _EXIF_GPSLongitude = 48; _EXIF_GPSAltitude = 49; _EXIF_GPSImageDirection = 50; _EXIF_GPSTrack = 51; _EXIF_GPSSpeed = 52; _EXIF_GPSDateAndTime = 53; _EXIF_GPSSatellites = 54; _EXIF_GPSVersionID = 55; _EXIF_Artist = 56; _EXIF_XPTitle = 57; _EXIF_XPComment = 58; _EXIF_XPAuthor = 59; _EXIF_XPKeywords = 60; _EXIF_XPSubject = 61; _EXIF_XPRating = 62; _EXIF_InteropVersion = 63; _EXIF_CameraOwnerName = 64; _EXIF_BodySerialNumber = 65; _EXIF_LensMake = 66; _EXIF_LensModel = 67; _EXIF_LensSerialNumber = 68; _EXIF_Gamma = 69; _EXIF_SubjectArea = 70; _EXIF_SubjectLocation = 71; _EXIF_Tag_Count = 72; {!!} { SKIPPED : Skipped the following fields : EXIF_Bitmap EXIF_ResolutionUnit EXIF_SubsecTime EXIF_SubsecTimeOriginal EXIF_SubsecTimeDigitized EXIF_WhitePoint EXIF_PrimaryChromaticities EXIF_YCbCrCoefficients EXIF_ReferenceBlackWhite EXIF_CompressedBitsPerPixel EXIF_FocalPlaneResolutionUnit EXIF_ExifVersion EXIF_Software EXIF_MakerNote EXIF_ImageUniqueID EXIF_GPSStatus EXIF_GPSMapDatum EXIF_GPSMeasureMode EXIF_GPSDOP EXIF_GPSDestLatitudeRef EXIF_GPSDestLatitudeDegrees EXIF_GPSDestLatitudeMinutes EXIF_GPSDestLatitudeSeconds EXIF_GPSDestLongitudeRef EXIF_GPSDestLongitudeDegrees EXIF_GPSDestLongitudeMinutes EXIF_GPSDestLongitudeSeconds EXIF_GPSDestBearingRef EXIF_GPSDestBearing EXIF_GPSDestDistanceRef EXIF_GPSDestDistance EXIF_InteropIndex } Example_File_Only = 'Example File'; SKIP_DESCRIPTION = 'SKIP_DESCRIPTION'; Maintain_File_Dates_On_Meta_Write : Boolean = False; // Set to true if updating the EXIF data should not modify the file date // Deprecated: Instead of Digital_Raw_Camera_Formats, use Camera_Raw_File_Extensions EXIF_COMPATIBLE_EXTENSIONS = '*.TIF;*.TIFF;*.JPE;*.JPG;*.JPEG;' + Camera_Raw_File_Extensions; XMP_COMPATIBLE_EXTENSIONS = '*.TIF;*.TIFF;*.JPE;*.JPG;*.JPEG;*.PSD;'; {!! Consts for Common XMP Fields Declaration Const XMP Property Description XMP_Aux_ApproximateFocusDistance aux:ApproximateFocusDistance Focus Distance XMP_Aux_Firmware aux:Firmware Firmware XMP_Aux_FlashCompensation aux:FlashCompensation Flash Compensation XMP_Aux_ImageNumber aux:ImageNumber Image Number XMP_Aux_Lens aux:Lens Lens XMP_Aux_LensID aux:LensID Lens ID XMP_Aux_LensInfo aux:LensInfo Lens Info XMP_Aux_LensSerialNumber aux:LensSerialNumber Lens Serial Number XMP_Aux_OwnerName aux:OwnerName Owner Name XMP_Aux_SerialNumber aux:SerialNumber Serial Number XMP_CC_AttributionName cc:AttributionName Attribution Name XMP_CC_AttributionURL cc:AttributionURL Attribution URL XMP_CC_DeprecatedOn cc:DeprecatedOn Deprecated On XMP_CC_Jurisdiction cc:Jurisdiction Jurisdiction XMP_CC_LegalCode cc:LegalCode Legal Code XMP_CC_License cc:License License XMP_CC_MorePermissions cc:MorePermissions More Permissions XMP_CC_Permits cc:Permits Permits XMP_CC_Prohibits cc:Prohibits Prohibits XMP_CC_Requires cc:Requires Requires XMP_CC_UseGuidelines cc:UseGuidelines Use Guidelines XMP_DC_Contributor dc:Contributor Contributor XMP_DC_Coverage dc:Coverage Coverage XMP_DC_Creator dc:Creator Creator XMP_DC_Date dc:Date Date XMP_DC_Description dc:Description Description XMP_DC_Format dc:Format Format XMP_DC_Identifier dc:Identifier Identifier XMP_DC_Language dc:Language Language XMP_DC_Publisher dc:Publisher Publisher XMP_DC_Relation dc:Relation Relation XMP_DC_Rights dc:Rights Rights XMP_DC_Source dc:Source Source XMP_DC_Subject dc:Subject Subject XMP_DC_Title dc:Title Title XMP_DC_Type dc:Type Type XMP_Photoshop_AuthorsPosition photoshop:AuthorsPosition Authors Position XMP_Photoshop_CaptionWriter photoshop:CaptionWriter Caption Writer XMP_Photoshop_Category photoshop:Category Category XMP_Photoshop_City photoshop:City City XMP_Photoshop_ColorMode photoshop:ColorMode Color Mode XMP_Photoshop_Country photoshop:Country Country XMP_Photoshop_Credit photoshop:Credit Credit XMP_Photoshop_DateCreated photoshop:DateCreated Date Created XMP_Photoshop_DocumentAncestorID photoshop:DocumentAncestorID Document Ancestor ID XMP_Photoshop_Headline photoshop:Headline Headline XMP_Photoshop_History photoshop:History History XMP_Photoshop_ICCProfileName photoshop:ICCProfileName ICC Profile Name XMP_Photoshop_Instructions photoshop:Instructions Instructions XMP_Photoshop_Source photoshop:Source Source XMP_Photoshop_State photoshop:State State XMP_Photoshop_SupplementalCategories photoshop:SupplementalCategories Supplemental Categories XMP_Photoshop_TextLayerName photoshop:TextLayerName Text Layer Name XMP_Photoshop_TextLayerText photoshop:TextLayerText Text Layer Text XMP_Photoshop_TransmissionReference photoshop:TransmissionReference Transmission Reference XMP_Photoshop_Urgency photoshop:Urgency Urgency XMP_Advisory xmp:Advisory Advisory XMP_Author xmp:Author Author XMP_BaseURL xmp:BaseURL Base URL XMP_CreateDate xmp:CreateDate Create Date XMP_CreatorTool xmp:CreatorTool Creator Tool XMP_Description xmp:Description Description XMP_Format xmp:Format Format XMP_Identifier xmp:Identifier Identifier XMP_Keywords xmp:Keywords Keywords XMP_Label xmp:Label Label XMP_MetadataDate xmp:MetadataDate Metadata Date XMP_ModifyDate xmp:ModifyDate Modify Date XMP_Nickname xmp:Nickname Nickname XMP_Rating xmp:Rating Rating XMP_Title xmp:Title Title
!!} XMP_Aux_ApproximateFocusDistance = 'aux:ApproximateFocusDistance'; XMP_Aux_Firmware = 'aux:Firmware'; XMP_Aux_FlashCompensation = 'aux:FlashCompensation'; XMP_Aux_ImageNumber = 'aux:ImageNumber'; XMP_Aux_Lens = 'aux:Lens'; XMP_Aux_LensID = 'aux:LensID'; XMP_Aux_LensInfo = 'aux:LensInfo'; XMP_Aux_LensSerialNumber = 'aux:LensSerialNumber'; XMP_Aux_OwnerName = 'aux:OwnerName'; XMP_Aux_SerialNumber = 'aux:SerialNumber'; XMP_CC_AttributionName = 'cc:AttributionName'; XMP_CC_AttributionURL = 'cc:AttributionURL'; XMP_CC_DeprecatedOn = 'cc:DeprecatedOn'; XMP_CC_Jurisdiction = 'cc:Jurisdiction'; XMP_CC_LegalCode = 'cc:LegalCode'; XMP_CC_License = 'cc:License'; XMP_CC_MorePermissions = 'cc:MorePermissions'; XMP_CC_Permits = 'cc:Permits'; XMP_CC_Prohibits = 'cc:Prohibits'; XMP_CC_Requires = 'cc:Requires'; XMP_CC_UseGuidelines = 'cc:UseGuidelines'; XMP_DC_Contributor = 'dc:Contributor'; XMP_DC_Coverage = 'dc:Coverage'; XMP_DC_Creator = 'dc:Creator'; XMP_DC_Date = 'dc:Date'; XMP_DC_Description = 'dc:Description'; XMP_DC_Format = 'dc:Format'; XMP_DC_Identifier = 'dc:Identifier'; XMP_DC_Language = 'dc:Language'; XMP_DC_Publisher = 'dc:Publisher'; XMP_DC_Relation = 'dc:Relation'; XMP_DC_Rights = 'dc:Rights'; XMP_DC_Source = 'dc:Source'; XMP_DC_Subject = 'dc:Subject'; XMP_DC_Title = 'dc:Title'; XMP_DC_Type = 'dc:Type'; XMP_Photoshop_AuthorsPosition = 'photoshop:AuthorsPosition'; XMP_Photoshop_CaptionWriter = 'photoshop:CaptionWriter'; XMP_Photoshop_Category = 'photoshop:Category'; XMP_Photoshop_City = 'photoshop:City'; XMP_Photoshop_ColorMode = 'photoshop:ColorMode'; XMP_Photoshop_Country = 'photoshop:Country'; XMP_Photoshop_Credit = 'photoshop:Credit'; XMP_Photoshop_DateCreated = 'photoshop:DateCreated'; XMP_Photoshop_DocumentAncestorID = 'photoshop:DocumentAncestorID'; XMP_Photoshop_Headline = 'photoshop:Headline'; XMP_Photoshop_History = 'photoshop:History'; XMP_Photoshop_ICCProfileName = 'photoshop:ICCProfileName'; XMP_Photoshop_Instructions = 'photoshop:Instructions'; XMP_Photoshop_Source = 'photoshop:Source'; XMP_Photoshop_State = 'photoshop:State'; XMP_Photoshop_SupplementalCategories = 'photoshop:SupplementalCategories'; XMP_Photoshop_TextLayerName = 'photoshop:TextLayerName'; XMP_Photoshop_TextLayerText = 'photoshop:TextLayerText'; XMP_Photoshop_TransmissionReference = 'photoshop:TransmissionReference'; XMP_Photoshop_Urgency = 'photoshop:Urgency'; XMP_Advisory = 'xmp:Advisory'; XMP_Author = 'xmp:Author'; XMP_BaseURL = 'xmp:BaseURL'; XMP_CreateDate = 'xmp:CreateDate'; XMP_CreatorTool = 'xmp:CreatorTool'; XMP_Description = 'xmp:Description'; XMP_Format = 'xmp:Format'; XMP_Identifier = 'xmp:Identifier'; XMP_Keywords = 'xmp:Keywords'; XMP_Label = 'xmp:Label'; XMP_MetadataDate = 'xmp:MetadataDate'; XMP_ModifyDate = 'xmp:ModifyDate'; XMP_Nickname = 'xmp:Nickname'; XMP_Rating = 'xmp:Rating'; XMP_Title = 'xmp:Title'; implementation uses Windows, hyiedefs, iedicom, hyieutils, Contnrs; type TIEMetaType = (iemEXIF, iemIPTC, iemDicom, iemXMP); TExifTag = record Desc : string; // Description VarType : Integer; // Type of field Edit : boolean; // Write support available for field end; resourcestring // EXIF Data s_UserComment = 'User Comment'; s_Description = 'Description'; s_CameraMake = 'Camera Make'; s_CameraModel = 'Camera Model'; s_Orientation = 'Camera Orientation'; s_Inch = 'inch'; s_CM = 'cm'; s_PerInch = ' / inch'; s_PerCM = ' / cm'; s_XResolution = 'Horizontal Resolution'; s_Yresolution = 'Vertical Resolution'; s_DateTime = 'Date and Time'; s_DateTimeOriginal = 'Original Date and Time'; s_DateTimeDigitized = 'Digitized Date and Time'; s_Copyright = 'Copyright'; s_ExposureTime = 'Exposure Time'; s_FNumber = 'F-Stop'; s_ExposureProgram = 'Exposure Program'; s_ManualControl = 'Manual'; s_ProgramNormal = 'Normal'; s_AperturePriority = 'Aperture Priority'; s_ShutterPriority = 'Shutter Priority'; s_CreativeProgram = 'Creative Program'; s_ActionProgram = 'Action Program'; s_Portraitmode = 'Portrait Mode'; s_LandscapeMode = 'Landscape Mode'; s_CompressedBitsPerPixel = 'Compression Ratio'; s_ShutterSpeedValue = 'Shutter Speed'; s_ApertureValue = 'Aperture Value'; s_ISOSpeedRatings = 'ISO Speed Rating'; s_BrightnessValue = 'Brightness'; s_ExposureBiasValue = 'Exposure Compensation'; s_MaxApertureValue = 'Max Aperture Value'; s_SubjectDistance = 'Subject Distance'; s_MeteringMode = 'Metering Mode'; s_average = 'Average'; s_CenterWeightedAverage = 'Center-weighted Average'; s_Spot = 'Spot'; s_MultiSpot = 'Multi-Spot'; s_MultiSegment = 'Multi-Segment'; s_partial = 'Partial'; s_Lighting = 'Lighting'; s_daylight = 'Daylight'; s_fluorescent = 'Flourescent'; s_tungsten = 'Tungsten'; s_flash = 'Flash'; s_standardLightA = 'Standard Light A'; s_standardLightB = 'Standard Light B'; s_standardLightC = 'Standard Light C'; s_D55 = 'D55'; s_D65 = 'D65'; s_D75 = 'D75'; s_FlashDidNotFire = 'Not Used'; s_flashFired = 'Fired'; s_flashFiredNoStrobeLight = 'Fired, No Strobe Return'; s_flashFiredStrobeLight = 'Fired, with Strobe Return'; s_FocalLength = 'Focal Length'; s_FlashPixVersion = 'FlashPix Version'; s_ColorSpace = 'Color Space'; s_RGB = 'RGB'; s_Uncalibrated = 'Uncalibrated'; s_WhiteBalance = 'White Balance'; s_ExifImageWidth = 'Image Width'; s_ExifImageHeight = 'Image Height'; s_RelatedSoundFile = 'Sound File'; s_FocalPlaneXResolution = 'Focal Plane Horz. Resolution'; s_FocalPlaneYResolution = 'Focal Plane Vert. Resolution'; s_ExposureIndex = 'Exposure Index'; s_SensingMethod = 'Sensing Method'; s_OneChipColorAreaSensor = 'Single Chip Color Area'; s_UnknownMethod = 'Unknown Method'; s_FileSource = 'File Source'; s_DigitalStillCamera = 'Digital Still Camera'; s_UnknownDevice = 'Unknown Device'; s_SceneType = 'Scene Type'; s_DirectlyPhotographed = 'Directly Photographed'; s_YcbCrPositioning = 'Chroma Sample Point'; s_Centered = 'Centered'; s_DataPoint = 'Data Point'; s_Seconds = 'Seconds'; s_Second = 'Second'; s_EXIFOrientation1 = 'Orientated Correctly'; s_EXIFOrientation2 = 'Horizontally Flipped'; s_EXIFOrientation3 = 'Offset by 180°'; s_EXIFOrientation4 = 'Vertically Flipped'; s_EXIFOrientation5 = 'Flipped Horiz. and Offset 90° CCW'; s_EXIFOrientation6 = 'Offset by 90° CCW'; s_EXIFOrientation7 = 'Flipped Horiz. and Offset 90° CW'; s_EXIFOrientation8 = 'Offset by 90° Clockwise'; s_ExposureMode = 'Exposure Mode'; s_DigitalZoomRatio = 'Digital Zoom Ratio'; s_FocalLengthIn35mmFilm = 'Focal Length in 35mm Film'; s_SceneCaptureType = 'Scene Capture Type'; s_GainControl = 'Gain Control'; s_Contrast = 'Contrast'; s_Saturation = 'Saturation'; s_Sharpness = 'Sharpness'; s_SubjectDistanceRange = 'Subject Distance'; s_GPSLatitude = 'GPS Latitude'; s_GPSLongitude = 'GPS Longitude'; s_GPSAltitude = 'GPS Altitude'; s_GPSImageDirection = 'GPS Image Direction'; s_GPSTrack = 'GPS Movement Direction'; s_GPSSpeed = 'GPS Movement Speed'; s_GPSDateAndTime = 'GPS Date and Time'; s_GPSSatellites = 'GPS Satellites'; s_GPSVersionID = 'GPS Version'; s_AutoExposure = 'Auto exposure'; s_ManualExposure = 'Manual exposure'; s_AutoBracket = 'Auto bracket'; s_Autowhitebalance = 'Auto white balance'; s_Manualwhitebalance = 'Manual white balance'; s_Standard = 'Standard'; s_Landscape = 'Landscape'; s_Portrait = 'Portrait'; s_NightScene = 'Night scene'; s_None = 'None'; s_LowGainup = 'Low gain up'; s_HighGainup = 'High gain up'; s_LowGaindown = 'Low gain down'; s_HighGaindown = 'High gain down'; s_Normal = 'Normal'; s_Soft = 'Soft'; s_Hard = 'Hard'; s_LowSaturation = 'Low saturation'; s_HighSaturation = 'High saturation'; s_Macro = 'Macro'; s_CloseView = 'Close view'; s_DistantView = 'Distant view'; s_Artist = 'Artist'; s_XPTitle = 'Title (Windows)'; s_XPComment = 'Comment (Windows)'; s_XPAuthor = 'Author (Windows)'; s_XPKeywords = 'Keywords (Windows)'; s_XPSubject = 'Subject (Windows)'; s_XPRating = 'Rating (Windows)'; s_InteropVersion = 'Interoperability Version'; s_CameraOwnerName = 'Camera Owner Name'; s_BodySerialNumber = 'Body Serial Number'; s_LensMake = 'Lens Make'; s_LensModel = 'Lens Model'; s_LensSerialNumber = 'Lens Serial Number'; s_Gamma = 'Gamma'; s_SubjectArea = 'Subject Area'; s_SubjectLocation = 'Subject Location'; s_PointAtXByX = 'Point at %d,%d'; s_CircleOfXCenteredAtAtXByX = 'Circle of %d centered at %d,%d'; s_RectangleOfXByXCenteredAtXByX = 'Rectangle of %d,%d centered at %d,%d'; const _vString = 1; _vInteger = 2; _vDouble = 3; ExifTags : array [0.._EXIF_Tag_Count - 1] of TExifTag = ( (Desc : s_UserComment ; VarType : _vString; Edit : TRUE ), // _EXIF_UserComment (Desc : s_Description ; VarType : _vString; Edit : TRUE ), // _EXIF_ImageDescription (Desc : s_CameraMake ; VarType : _vString; Edit : TRUE ), // _EXIF_Make (Desc : s_CameraModel ; VarType : _vString; Edit : TRUE ), // _EXIF_Model (Desc : s_XResolution ; VarType : _vDouble; Edit : TRUE ), // _EXIF_XResolution (Desc : s_YResolution ; VarType : _vDouble; Edit : TRUE ), // _EXIF_YResolution (Desc : s_DateTime ; VarType : _vString; Edit : TRUE ), // _EXIF_DateTime (Desc : s_DateTimeOriginal ; VarType : _vString; Edit : TRUE ), // _EXIF_DateTimeOriginal (Desc : s_DateTimeDigitized ; VarType : _vString; Edit : TRUE ), // _EXIF_DateTimeDigitized (Desc : s_Copyright ; VarType : _vString; Edit : TRUE ), // _EXIF_Copyright (Desc : s_Orientation ; VarType : _vInteger; Edit : TRUE ), // _EXIF_Orientation (Desc : s_ExposureTime ; VarType : _vDouble; Edit : TRUE ), // _EXIF_ExposureTime (Desc : s_FNumber ; VarType : _vDouble; Edit : TRUE ), // _EXIF_FNumber (Desc : s_ExposureProgram ; VarType : _vInteger; Edit : TRUE ), // _EXIF_ExposureProgram (Desc : s_ISOSpeedRatings ; VarType : _vInteger; Edit : TRUE ), // _EXIF_ISOSpeedRatings (Desc : s_ShutterSpeedValue ; VarType : _vDouble; Edit : TRUE ), // _EXIF_ShutterSpeedValue (Desc : s_ApertureValue ; VarType : _vDouble; Edit : TRUE ), // _EXIF_ApertureValue (Desc : s_BrightnessValue ; VarType : _vDouble; Edit : TRUE ), // _EXIF_BrightnessValue (Desc : s_ExposureBiasValue ; VarType : _vDouble; Edit : TRUE ), // _EXIF_ExposureBiasValue (Desc : s_MaxApertureValue ; VarType : _vDouble; Edit : TRUE ), // _EXIF_MaxApertureValue (Desc : s_SubjectDistance ; VarType : _vDouble; Edit : TRUE ), // _EXIF_SubjectDistance (Desc : s_MeteringMode ; VarType : _vInteger; Edit : TRUE ), // _EXIF_MeteringMode (Desc : s_Lighting ; VarType : _vInteger; Edit : TRUE ), // _EXIF_LightSource (Desc : s_Flash ; VarType : _vInteger; Edit : TRUE ), // _EXIF_Flash (Desc : s_FocalLength ; VarType : _vDouble; Edit : TRUE ), // _EXIF_FocalLength (Desc : s_FlashPixVersion ; VarType : _vString; Edit : TRUE ), // _EXIF_FlashPixVersion (Desc : s_ColorSpace ; VarType : _vInteger; Edit : TRUE ), // _EXIF_ColorSpace (Desc : s_ExifImageWidth ; VarType : _vInteger; Edit : TRUE ), // _EXIF_ExifImageWidth (Desc : s_ExifImageHeight ; VarType : _vInteger; Edit : TRUE ), // _EXIF_ExifImageHeight (Desc : s_RelatedSoundFile ; VarType : _vString; Edit : TRUE ), // _EXIF_RelatedSoundFile (Desc : s_FocalPlaneXResolution ; VarType : _vDouble; Edit : TRUE ), // _EXIF_FocalPlaneXResolution (Desc : s_FocalPlaneYResolution ; VarType : _vDouble; Edit : TRUE ), // _EXIF_FocalPlaneYResolution (Desc : s_ExposureIndex ; VarType : _vDouble; Edit : TRUE ), // _EXIF_ExposureIndex (Desc : s_SensingMethod ; VarType : _vInteger; Edit : FALSE ), // _EXIF_SensingMethod (Desc : s_FileSource ; VarType : _vInteger; Edit : FALSE ), // _EXIF_FileSource (Desc : s_SceneType ; VarType : _vInteger; Edit : FALSE ), // _EXIF_SceneType (Desc : s_YCbCrPositioning ; VarType : _vInteger; Edit : TRUE ), // _EXIF_YCbCrPositioning (Desc : s_ExposureMode ; VarType : _vInteger; Edit : FALSE ), // _EXIF_ExposureMode (Desc : s_WhiteBalance ; VarType : _vInteger; Edit : FALSE ), // _EXIF_WhiteBalance (Desc : s_DigitalZoomRatio ; VarType : _vDouble; Edit : FALSE ), // _EXIF_DigitalZoomRatio (Desc : s_FocalLengthIn35mmFilm ; VarType : _vInteger; Edit : FALSE ), // _EXIF_FocalLengthIn35mmFilm (Desc : s_SceneCaptureType ; VarType : _vInteger; Edit : FALSE ), // _EXIF_SceneCaptureType (Desc : s_GainControl ; VarType : _vInteger; Edit : FALSE ), // _EXIF_GainControl (Desc : s_Contrast ; VarType : _vInteger; Edit : FALSE ), // _EXIF_Contrast (Desc : s_Saturation ; VarType : _vInteger; Edit : FALSE ), // _EXIF_Saturation (Desc : s_Sharpness ; VarType : _vInteger; Edit : FALSE ), // _EXIF_Sharpness (Desc : s_SubjectDistanceRange ; VarType : _vInteger; Edit : FALSE ), // _EXIF_SubjectDistanceRange (Desc : s_GPSLatitude ; VarType : _vDouble; Edit : FALSE ), // _EXIF_GPSLatitude (Desc : s_GPSLongitude ; VarType : _vDouble; Edit : FALSE ), // _EXIF_GPSLongitude (Desc : s_GPSAltitude ; VarType : _vDouble; Edit : FALSE ), // _EXIF_GPSAltitude (Desc : s_GPSImageDirection ; VarType : _vDouble; Edit : FALSE ), // _EXIF_GPSImageDirection (Desc : s_GPSTrack ; VarType : _vDouble; Edit : FALSE ), // _EXIF_GPSTrack (Desc : s_GPSSpeed ; VarType : _vDouble; Edit : FALSE ), // _EXIF_GPSSpeed (Desc : s_GPSDateAndTime ; VarType : _vDouble; Edit : FALSE ), // _EXIF_GPSDateAndTime (Desc : s_GPSSatellites ; VarType : _vString; Edit : TRUE ), // _EXIF_GPSSatellites (Desc : s_GPSVersionID ; VarType : _vString; Edit : TRUE ), // _EXIF_GPSVersionID (Desc : s_Artist ; VarType : _vString; Edit : TRUE ), // _EXIF_Artist (Desc : s_XPTitle ; VarType : _vString; Edit : TRUE ), // _EXIF_XPTitle (Desc : s_XPComment ; VarType : _vString; Edit : TRUE ), // _EXIF_XPComment (Desc : s_XPAuthor ; VarType : _vString; Edit : TRUE ), // _EXIF_XPAuthor (Desc : s_XPKeywords ; VarType : _vString; Edit : TRUE ), // _EXIF_XPKeywords (Desc : s_XPSubject ; VarType : _vString; Edit : TRUE ), // _EXIF_XPSubject (Desc : s_XPRating ; VarType : _vInteger; Edit : TRUE ), // _EXIF_XPRating (Desc : s_InteropVersion ; VarType : _vString; Edit : TRUE ), // _EXIF_InteropVersion (Desc : s_CameraOwnerName ; VarType : _vString; Edit : TRUE ), // _EXIF_CameraOwnerName (Desc : s_BodySerialNumber ; VarType : _vString; Edit : TRUE ), // _EXIF_BodySerialNumber (Desc : s_LensMake ; VarType : _vString; Edit : TRUE ), // _EXIF_LensMake (Desc : s_LensModel ; VarType : _vString; Edit : TRUE ), // _EXIF_LensModel (Desc : s_LensSerialNumber ; VarType : _vString; Edit : TRUE ), // _EXIF_LensSerialNumber (Desc : s_Gamma ; VarType : _vDouble; Edit : TRUE ), // _EXIF_Gamma (Desc : s_SubjectArea ; VarType : _vString; Edit : FALSE ), // _EXIF_SubjectArea (Desc : s_SubjectLocation ; VarType : _vString; Edit : TRUE ) // _EXIF_SubjectLocation ); // Exif Tags are a representation of the exif field that a user can put in a text string to be replaced // dymanically by the actual value read from the file, e.g. %EXIF-User-Comment% Exif_Tag_Prefix = '%EXIF-'; Exif_Tag_Suffix = '%'; resourcestring s_Title = 'Title'; // Object name s_Caption = 'Caption'; // Caption/Abstract s_Keywords = 'Keywords'; s_SpecialInstructions = 'Special Instructions'; s_DateCreated_YYYYMMDD = 'Date Created (YYYYMMDD)'; s_TimeCreated_HHMMSS_HHMM = 'Time Created (HHMMSS±HHMM)'; s_Byline1 = 'By-line 1'; s_Byline2 = 'By-line 2'; s_City = 'City'; s_s_StateProvince = 'State/Province'; s_CountryPrimaryLocationCode = 'Country/Primary Location Code'; s_CountryPrimaryLocationName = 'Country/Primary Location Name'; s_OriginalTransmissionReference = 'Original Transmission Reference'; s_Credit = 'Credit'; s_Source = 'Source'; s_WriterEditor = 'Writer/Editor'; s_Editstatus = 'Edit status'; s_Urgency = 'Urgency'; s_Category = 'Category'; s_SupplementalCategory = 'Supplemental Category'; s_FixtureIdentifier = 'Fixture Identifier'; s_ReleaseDate_YYYYMMDD = 'Release Date (YYYYMMDD)'; s_ReleaseTime_HHMMSS_HHMM = 'Release Time (HHMMSS±HHMM)'; s_ReferenceService = 'Reference Service'; s_ReferenceDate_YYYYMMDD = 'Reference Date (YYYYMMDD)'; s_ReferenceNumber = 'Reference Number'; s_OriginatingProgram = 'Originating Program'; s_ProgramVersion = 'Program Version'; s_ObjectCycle_ABC = 'Object Cycle (a=AM, b=PM, c=both)'; s_CopyrightNotice = 'Copyright Notice'; s_ImageType = 'Image Type'; type TIPTCTag = record Rec : integer; // Record Number DSet : integer; // Data Set Desc : string; // Field Description end; const IPTC_COMPATIBLE_EXTENSIONS = '*.TIF;*.TIFF;*.JPE;*.JPG;*.JPEG;'; IPTCTags : array [0..30] of TIPTCTag = ( (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Title; Desc : s_Title ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Caption; Desc : s_Caption ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Keywords; Desc : s_Keywords ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Instructions; Desc : s_SpecialInstructions ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Date_Created; Desc : s_DateCreated_YYYYMMDD ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Time_Created; Desc : s_TimeCreated_HHMMSS_HHMM ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Byline_1; Desc : s_Byline1 ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Byline_2; Desc : s_Byline2 ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_City; Desc : s_City ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_State_Province; Desc : s_s_StateProvince ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Country_Code; Desc : s_CountryPrimaryLocationCode ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Country; Desc : s_CountryPrimaryLocationName ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Transmission_Reference; Desc : s_OriginalTransmissionReference ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Credit; Desc : s_Credit ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Source; Desc : s_Source ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Writer; Desc : s_WriterEditor ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Edit_Status; Desc : s_Editstatus ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Urgency; Desc : s_Urgency ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Category; Desc : s_Category ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Category_2; Desc : s_SupplementalCategory ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Fixture_Identifier; Desc : s_FixtureIdentifier ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Release_Date; Desc : s_ReleaseDate_YYYYMMDD ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Release_Time; Desc : s_ReleaseTime_HHMMSS_HHMM ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Reference_Service; Desc : s_ReferenceService ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Reference_Date; Desc : s_ReferenceDate_YYYYMMDD ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Reference_Number; Desc : s_ReferenceNumber ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Originating_Program; Desc : s_OriginatingProgram ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Program_Version; Desc : s_ProgramVersion ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Object_Cycle; Desc : s_ObjectCycle_ABC ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Copyright_Notice; Desc : s_CopyrightNotice ), (Rec : PhotoShop_IPTC_Records; DSet : IPTC_PS_Image_Type; Desc : s_ImageType ) ); resourcestring s_Unknown = 'Unknown'; resourcestring s_FocusDistance = 'Focus Distance'; s_Firmware = 'Firmware'; s_FlashCompensation = 'Flash Compensation'; s_ImageNumber = 'Image Number'; s_Lens = 'Lens'; s_LensID = 'Lens ID'; s_LensInfo = 'Lens Info'; // s_LensSerialNumber = 'Lens Serial Number'; s_OwnerName = 'Owner Name'; s_SerialNumber = 'Serial Number'; s_AttributionName = 'Attribution Name'; s_AttributionURL = 'Attribution URL'; s_DeprecatedOn = 'Deprecated On'; s_Jurisdiction = 'Jurisdiction'; s_LegalCode = 'Legal Code'; s_License = 'License'; s_MorePermissions = 'More Permissions'; s_Permits = 'Permits'; s_Prohibits = 'Prohibits'; s_Requires = 'Requires'; s_UseGuidelines = 'Use Guidelines'; s_Contributor = 'Contributor'; s_Coverage = 'Coverage'; s_Creator = 'Creator'; s_Date = 'Date'; // s_Description = 'Description'; s_Format = 'Format'; s_Identifier = 'Identifier'; s_Language = 'Language'; s_Publisher = 'Publisher'; s_Relation = 'Relation'; s_Rights = 'Rights'; // s_Source = 'Source'; s_Subject = 'Subject'; // s_Title = 'Title'; s_Type = 'Type'; s_AuthorsPosition = 'Authors Position'; s_CaptionWriter = 'Caption Writer'; // s_Category = 'Category'; // s_City = 'City'; s_ColorMode = 'Color Mode'; s_Country = 'Country'; // s_Credit = 'Credit'; s_DateCreated = 'Date Created'; s_DocumentAncestorID = 'Document Ancestor ID'; s_Headline = 'Headline'; s_History = 'History'; s_ICCProfileName = 'ICC Profile Name'; s_Instructions = 'Instructions'; // s_Source = 'Source'; s_State = 'State'; s_SupplementalCategories = 'Supplemental Categories'; s_TextLayerName = 'Text Layer Name'; s_TextLayerText = 'Text Layer Text'; s_TransmissionReference = 'Transmission Reference'; // s_Urgency = 'Urgency'; s_Advisory = 'Advisory'; s_Author = 'Author'; s_BaseURL = 'Base URL'; s_CreateDate = 'Create Date'; s_CreatorTool = 'Creator Tool'; // s_Description = 'Description'; // s_Format = 'Format'; // s_Identifier = 'Identifier'; // s_Keywords = 'Keywords'; s_Label = 'Label'; s_MetadataDate = 'Metadata Date'; s_ModifyDate = 'Modify Date'; s_Nickname = 'Nickname'; s_Rating = 'Rating'; // s_Title = 'Title'; type TXmpTag = record Field : string; // Field Name Desc : string; // Field Description end; const XmpTags : array [0..70] of TXmpTag = ( ( Field: XMP_Aux_ApproximateFocusDistance; Desc: s_FocusDistance ), ( Field: XMP_Aux_Firmware; Desc: s_Firmware ), ( Field: XMP_Aux_FlashCompensation; Desc: s_FlashCompensation ), ( Field: XMP_Aux_ImageNumber; Desc: s_ImageNumber ), ( Field: XMP_Aux_Lens; Desc: s_Lens ), ( Field: XMP_Aux_LensID; Desc: s_LensID ), ( Field: XMP_Aux_LensInfo; Desc: s_LensInfo ), ( Field: XMP_Aux_LensSerialNumber; Desc: s_LensSerialNumber ), ( Field: XMP_Aux_OwnerName; Desc: s_OwnerName ), ( Field: XMP_Aux_SerialNumber; Desc: s_SerialNumber ), ( Field: XMP_CC_AttributionName; Desc: s_AttributionName ), ( Field: XMP_CC_AttributionURL; Desc: s_AttributionURL ), ( Field: XMP_CC_DeprecatedOn; Desc: s_DeprecatedOn ), ( Field: XMP_CC_Jurisdiction; Desc: s_Jurisdiction ), ( Field: XMP_CC_LegalCode; Desc: s_LegalCode ), ( Field: XMP_CC_License; Desc: s_License ), ( Field: XMP_CC_MorePermissions; Desc: s_MorePermissions ), ( Field: XMP_CC_Permits; Desc: s_Permits ), ( Field: XMP_CC_Prohibits; Desc: s_Prohibits ), ( Field: XMP_CC_Requires; Desc: s_Requires ), ( Field: XMP_CC_UseGuidelines; Desc: s_UseGuidelines ), ( Field: XMP_DC_Contributor; Desc: s_Contributor ), ( Field: XMP_DC_Coverage; Desc: s_Coverage ), ( Field: XMP_DC_Creator; Desc: s_Creator ), ( Field: XMP_DC_Date; Desc: s_Date ), ( Field: XMP_DC_Description; Desc: s_Description ), ( Field: XMP_DC_Format; Desc: s_Format ), ( Field: XMP_DC_Identifier; Desc: s_Identifier ), ( Field: XMP_DC_Language; Desc: s_Language ), ( Field: XMP_DC_Publisher; Desc: s_Publisher ), ( Field: XMP_DC_Relation; Desc: s_Relation ), ( Field: XMP_DC_Rights; Desc: s_Rights ), ( Field: XMP_DC_Source; Desc: s_Source ), ( Field: XMP_DC_Subject; Desc: s_Subject ), ( Field: XMP_DC_Title; Desc: s_Title ), ( Field: XMP_DC_Type; Desc: s_Type ), ( Field: XMP_Photoshop_AuthorsPosition; Desc: s_AuthorsPosition ), ( Field: XMP_Photoshop_CaptionWriter; Desc: s_CaptionWriter ), ( Field: XMP_Photoshop_Category; Desc: s_Category ), ( Field: XMP_Photoshop_City; Desc: s_City ), ( Field: XMP_Photoshop_ColorMode; Desc: s_ColorMode ), ( Field: XMP_Photoshop_Country; Desc: s_Country ), ( Field: XMP_Photoshop_Credit; Desc: s_Credit ), ( Field: XMP_Photoshop_DateCreated; Desc: s_DateCreated ), ( Field: XMP_Photoshop_DocumentAncestorID; Desc: s_DocumentAncestorID ), ( Field: XMP_Photoshop_Headline; Desc: s_Headline ), ( Field: XMP_Photoshop_History; Desc: s_History ), ( Field: XMP_Photoshop_ICCProfileName; Desc: s_ICCProfileName ), ( Field: XMP_Photoshop_Instructions; Desc: s_Instructions ), ( Field: XMP_Photoshop_Source; Desc: s_Source ), ( Field: XMP_Photoshop_State; Desc: s_State ), ( Field: XMP_Photoshop_SupplementalCategories; Desc: s_SupplementalCategories ), ( Field: XMP_Photoshop_TextLayerName; Desc: s_TextLayerName ), ( Field: XMP_Photoshop_TextLayerText; Desc: s_TextLayerText ), ( Field: XMP_Photoshop_TransmissionReference; Desc: s_TransmissionReference ), ( Field: XMP_Photoshop_Urgency; Desc: s_Urgency ), ( Field: XMP_Advisory; Desc: s_Advisory ), ( Field: XMP_Author; Desc: s_Author ), ( Field: XMP_BaseURL; Desc: s_BaseURL ), ( Field: XMP_CreateDate; Desc: s_CreateDate ), ( Field: XMP_CreatorTool; Desc: s_CreatorTool ), ( Field: XMP_Description; Desc: s_Description ), ( Field: XMP_Format; Desc: s_Format ), ( Field: XMP_Identifier; Desc: s_Identifier ), ( Field: XMP_Keywords; Desc: s_Keywords ), ( Field: XMP_Label; Desc: s_Label ), ( Field: XMP_MetadataDate; Desc: s_MetadataDate ), ( Field: XMP_ModifyDate; Desc: s_ModifyDate ), ( Field: XMP_Nickname; Desc: s_Nickname ), ( Field: XMP_Rating; Desc: s_Rating ), ( Field: XMP_Title; Desc: s_Title ) ); // Return a double value as a fraction string function DoubleToFraction(dValue: double): string; begin if (dValue = 0) or (dValue = -1) then result := '' else result := '1/' + FloatToStr(dValue); end; // Convert a fraction string to a double function FractionToDouble(dValue: string): double; begin if pos('1/', dValue) <> 1 then raise EConvertError.create('Not a fraction'); delete(dValue, 1, 2); result := StrToFloat(dValue); end; // Return a float as string, if the value is not 0 or -1 function FloatToStrOrNull(dValue: double; sAppend: string = ''): string; begin if (dValue = 0) or (dValue = -1) then result := '' else result := FloatToStr(dValue) + sAppend; end; // Remove sStrip from the start of the string value function StripPrefix(const Value: string; const sStrip: string): string; begin result := value; if pos(uppercase(sStrip), uppercase(result)) = 1 then Delete(result, 1, length(sStrip)); end; // Remove sStrip from the end of the string value function StripSuffix(const Value: string; const sStrip: string): string; var iPos: Integer; begin result := value; iPos := Pos( Uppercase( sStrip), Uppercase( result )); if ( iPos > 0 ) and ( iPos = ( Length( result ) - Length( sStrip )) + 1 ) then SetLength(result, Length( result ) - Length( sStrip )); end; // Convert an apex value to a string function ApexToStr(dBase: double; dValue: double; const sPrepend: string): string; begin result := ''; if (dBase <> 0) and (dValue <> -1) then try dValue := Power(dBase, dValue); if (sPrepend = '1/') and (dValue > 0) and (dvalue <= 1) then // cope with values such as 0.17 result := IEFloatToFormatString(dValue, 1, True) else result := sPrepend + IEFloatToFormatString(dValue, 1, True); except // UNEXPECTED ERROR end; end; // Convert a string to an apex value function StrToApex(dBase: double; Value: string; sPrepended: string ): double; var dValue: double; begin if (sPrepended = '1/') and (pos('1/', Value) = 0) then begin dValue := 1 / StrToFloat(Value); end else begin Value := StripPrefix(Value, sPrepended); dValue := StrToFloat(Value); end; Result := LogN(dBase, dValue); end; // Remove the null terminator from a string function RemoveNull(Value: String): string; begin result := trim( String( Value )); if (result <> '') and (result[length(result)] = #0) then SetLength(result, length(result) - 1); result := trim(result); end; function RemoveNullA(Value: AnsiString): string; begin result := RemoveNull( String( Value )); end; // Convert EXIF_Flash to a descriptive string function FlashModeToString(iFlash: Integer): string; begin Case iFlash of 0: result := s_FlashDidNotFire; 1: result := s_flashFired; 5: result := s_flashFiredNoStrobeLight; 7: result := s_flashFiredStrobeLight; else result := ''; end; end; // Return any text found before SeekStr function GetTextBeforeChar(const Value, SeekStr: string; bNullIfNotFound: boolean = false): string; var iPos: integer; begin result := Value; iPos := pos(uppercase(SeekStr), uppercase(Value)); if iPos > 0 then delete(Result, iPos, (length(Result) - iPos) + 1) else if bNullIfNotFound then result := ''; end; // Return any text found after SeekStr function GetTextAfterChar(const Value, SeekStr: string; bNullIfNotFound: boolean = false): string; var ipos: integer; begin result := Value; iPos := pos(uppercase(SeekStr), uppercase(Value)); if ipos > 0 then Delete(Result, 1, iPos + (length(SeekStr) - 1)) else if bNullIfNotFound then result := ''; end; {$IFDEF Delphi2005orNewer} function _ReadFromEXIF_Params(ADest: TObject; IOParams : TIOParams) : Boolean; var i: integer; begin if ADest is TStrings then TStrings(ADest).Clear; result := IOParams.EXIF_HasEXIFData; if result = False then exit; for i := low(ExifTags) to high(ExifTags) do begin {$IFDEF USE_STRINGGRIDS} if ADest is TStringGrid then TStringGrid(ADest).Cells[1, i + TStringGrid(ADest).FixedRows] := IOParams.EXIF_AsStr[ i ] else {$endif} {$IFDEF USE_LISTVIEW} if ADest is TListView then TListView(ADest).Items.Item[i].SubItems[0] := IOParams.EXIF_AsStr[ i ] else {$endif} if ADest is TStrings then TStrings(ADest).Add( ExifTags[ i ].Desc + ': ' + IOParams.EXIF_AsStr[ i ] ) else raise EIEException.create('Invalid'); end; end; function _ReadFromIPTC_Params(ADest: TObject; IOParams : TIOParams) : Boolean; var i: integer; sValue: string; begin result := false; if ADest is TStrings then TStrings(ADest).Clear; if IOParams.IPTC_HasIPTCData = False then exit; // set properties to grid for i := low(IPTCTags) to high(IPTCTags) do begin sValue := IOParams.ReadIPTCField(IPTCTags[i].Rec, IPTCTags[i].DSet); {$IFDEF USE_STRINGGRIDS} if ADest is TStringGrid then TStringGrid(ADest).Cells[1, i + TStringGrid(ADest).FixedRows] := sValue else {$endif} {$IFDEF USE_LISTVIEW} if ADest is TListView then TListView(ADest).Items[i].SubItems[0] := sValue else {$endif} if ADest is TStrings then TStrings(ADest).Add( IPTCTags[i].Desc + ': ' + sValue ) else raise EIEException.create('Invalid'); if sValue <> '' then result := true; end; end; {$ifdef IEINCLUDEDICOM} function _ReadFromDicom_Params(ADest: TObject; IOParams : TIOParams; TagInclude: TIEDicomInclude) : Boolean; var iRows: Integer; procedure _ParseTags(tags: TIEDicomTags); var i, j: integer; tag: PIEDicomTag; sDescription: string; sValue: String; aListItem: TListItem; aTagSource: TIEDicomTagSource; bAllowTag: Boolean; begin for i := 0 to tags.Count - 1 do begin // GET DATA tag := tags.GetTag(i); sDescription := tags.GetTagDescription(i, aTagSource); bAllowTag := True; if (aTagSource = dsDeprecated) and ((diDeprecated in TagInclude) = False) then bAllowTag := False else if (aTagSource = dsProprietary) and ((diProprietary in TagInclude) = False) then bAllowTag := False; if (sDescription = '') then begin if (diUnknown in TagInclude) = False then bAllowTag := False else sDescription := s_Unknown; end; sValue := Trim( String( tags.GetTagString(i) )); // ADD TO OUR CONTROL if bAllowTag and (sValue <> '') then begin result := true; {$IFDEF USE_STRINGGRIDS} if ADest is TStringGrid then begin inc(iRows); if TStringGrid(ADest).RowCount < TStringGrid(ADest).FixedRows + iRows then TStringGrid(ADest).RowCount := TStringGrid(ADest).FixedRows + iRows; TStringGrid(ADest).Cells[0, iRows + TStringGrid(ADest).FixedRows - 1] := sDescription; TStringGrid(ADest).Cells[1, iRows + TStringGrid(ADest).FixedRows - 1] := sValue; end else {$endif} {$IFDEF USE_LISTVIEW} if ADest is TListView then begin aListItem := TListView(ADest).Items.Add; aListItem.Caption := sDescription; aListItem.SubItems.Add(sValue); end else {$endif} if ADest is TStrings then begin TStrings(ADest).Add( sDescription + ': ' + sValue ) end else raise EIEException.create('Invalid'); end; // PROCESS ANY CHILDREN if (diChildTags in TagInclude) and assigned(tag.Children) then begin // tag.Children is a TObjectList object, where each item is a TIEDicomTags object to pass recursively into ShowRawTags for j := 0 to tag.Children.Count - 1 do _ParseTags(tag.Children[j] as TIEDicomTags); end; end; end; begin result := False; if ADest is TStrings then TStrings(ADest).Clear; if IOParams.DICOM_HasDicomTags = False then exit; if ADest is TStrings then TStrings(ADest).BeginUpdate; try iRows := 0; _ParseTags(IOParams.DICOM_Tags); finally if ADest is TStrings then TStrings(ADest).EndUpdate; end; end; {$endif} function _ReadFromXMP_Params(ADest: TObject; IOParams : TIOParams) : Boolean; var i: integer; sValue: string; sDescription: string; iRows: Integer; aListItem: TListItem; begin result := false; iRows := 0; if ADest is TStrings then TStrings(ADest).Clear; if IOParams.XMP_HasXMPData = False then exit; // set properties to grid for i := low(XMPTags) to high(XMPTags) do begin sValue := IOParams.XMP_AsStr[ XMPTags[ i ].Field ]; sDescription := XMPTags[ i ].Desc; if sValue = '' then begin { SKIP } end else {$IFDEF USE_STRINGGRIDS} if ADest is TStringGrid then begin inc(iRows); if TStringGrid(ADest).RowCount < TStringGrid(ADest).FixedRows + iRows then TStringGrid(ADest).RowCount := TStringGrid(ADest).FixedRows + iRows; TStringGrid(ADest).Cells[0, iRows + TStringGrid(ADest).FixedRows - 1] := sDescription; TStringGrid(ADest).Cells[1, iRows + TStringGrid(ADest).FixedRows - 1] := sValue; end else {$endif} {$IFDEF USE_LISTVIEW} if ADest is TListView then begin aListItem := TListView(ADest).Items.Add; aListItem.Caption := sDescription; aListItem.SubItems.Add(sValue); end else {$endif} if ADest is TStrings then begin TStrings(ADest).Add( sDescription + ': ' + sValue ) end else raise EIEException.create('Invalid'); if sValue <> '' then result := true; end; end; function _ReadFromMeta_File(ADest: TObject; AMetaType : TIEMetaType; const sFilename : string; DicomTagInclude: TIEDicomInclude = []) : Boolean; var aImageEnIO: TImageEnIO; begin {$IFDEF IEForceVarInitialization} Result := False; {$ENDIF} aImageEnIO := TImageEnIO.create(nil); try aImageEnIO.ParamsFromFile(sFilename); case AMetaType of iemEXIF : Result := _ReadFromEXIF_Params(ADest, aImageEnIO.Params); iemIPTC : Result := _ReadFromIPTC_Params(ADest, aImageEnIO.Params); {$ifdef IEINCLUDEDICOM} iemDicom : Result := _ReadFromDicom_Params(ADest, aImageEnIO.Params, DicomTagInclude); {$endif} iemXMP : Result := _ReadFromXMP_Params(ADest, aImageEnIO.Params); else raise EIEException.create('Invalid'); end; finally aImageEnIO.Free; end; end; function _WriteToExif_Params(ADest: TObject; IOParams : TIOParams) : Boolean; var sNewValue : string; i : integer; bExifHasData : boolean; bExifHasChanged: Boolean; begin bExifHasData := false; bExifHasChanged := False; for i := low(ExifTags) to high(ExifTags) do begin {$IFDEF USE_STRINGGRIDS} if ADest is TStringGrid then sNewValue := TStringGrid(ADest).Cells[1, i + TStringGrid(ADest).FixedRows] else {$endif} {$IFDEF USE_LISTVIEW} if ADest is TListView then sNewValue := TListView(ADest).Items.Item[i].SubItems[0] else {$endif} raise EIEException.create('Invalid'); if sNewValue <> '' then bExifHasData := True; // Has the data for that field changed? if sNewValue <> IOParams.EXIF_AsStr[ i ] then begin bExifHasChanged := True; IOParams.EXIF_AsStr[ i ] := sNewValue; end; end; IOParams.EXIF_HasEXIFData := bExifHasData; Result := bExifHasChanged; end; function _WriteToIPTC_Params(ADest: TObject; IOParams : TIOParams) : Boolean; var i: integer; sOldValue, sNewValue: string; begin Result := False; for i := low(IPTCTags) to high(IPTCTags) do begin {$IFDEF USE_STRINGGRIDS} if ADest is TStringGrid then sNewValue := TStringGrid(ADest).Cells[1, i + TStringGrid(ADest).FixedRows] else {$endif} {$IFDEF USE_LISTVIEW} if ADest is TListView then sNewValue := TListView(ADest).Items.Item[i].SubItems[0] else {$endif} raise EIEException.create('Invalid'); sOldValue := IOParams.ReadIPTCField(IPTCTags[i].Rec, IPTCTags[i].DSet); if sNewValue <> sOldValue then begin Result := True; IOParams.WriteIPTCField(IPTCTags[i].Rec, IPTCTags[i].DSet, sNewValue); end; end; end; function _WriteToMeta_File(ADest: TObject; AMetaType : TIEMetaType; const sFilename : string) : Boolean; var aImageEnIO: TImageEnIO; dFileDate : TDateTime; bHasChanged: Boolean; begin Result := False; aImageEnIO := TImageEnIO.create(nil); try if FileExists(sFilename) = False then raise EIEException.create('Cannot find file to update: ' + sFilename); // Get existing meta data // NOTE: There is no InjectTiffIPTC if (AMetaType = iemIPTC) and (IEFilenameInExtensions(sFilename, '*.jpeg;*.jpg;*.jpe;') = False) then aImageEnIO.LoadFromFile(sFilename) else aImageEnIO.ParamsFromFile(sFilename); case AMetaType of iemEXIF : bHasChanged := _WriteToExif_Params(ADest, aImageEnIO.Params); iemIPTC : bHasChanged := _WriteToIPTC_Params(ADest, aImageEnIO.Params); else raise EIEException.create('Invalid'); end; if bHasChanged then begin Result := True; {$WARNINGS OFF} // FileAge is deprecated dFileDate := 0; if Maintain_File_Dates_On_Meta_Write then dFileDate := FileDateToDateTime(FileAge(sFileName)); {$WARNINGS ON} if aImageEnIO.Params.FileType = ioJPEG then case AMetaType of iemEXIF : aImageEnIO.InjectJpegEXIF(sFileName); iemIPTC : aImageEnIO.InjectJpegIPTC(sFileName); end else if aImageEnIO.Params.FileType = ioTIFF then case AMetaType of iemEXIF : aImageEnIO.InjectTiffEXIF(sFileName); iemIPTC : aImageEnIO.SaveToFile(sFileName); end else raise EIEException.create('File format does not support this meta data type'); if Maintain_File_Dates_On_Meta_Write and (dFileDate <> 0) then IEFileSetDate(sFileName, dFileDate); end; finally aImageEnIO.Free; end; end; {$endif} { TStringGridHelper } {$IFDEF Delphi2005orNewer} {$IFDEF USE_STRINGGRIDS} {!! TStringGridHelper.InitializeGrid Declaration procedure InitializeGrid(bFixLayout : Boolean = True); Description Set up a TStringGrid for display or editing of EXIF, IPTC and Dicom meta data. If bFixLayout is true then it will automatically add columns and a header row to your grid. Example // Display a grid allowing user to add EXIF data procedure TExifForm.FormCreate(Sender: TObject); begin // Fix grid layout MyExifStringGrid.InitializeGrid; // Add fields to grid MyExifStringGrid.NewGridForExif; end; !!} procedure TStringGridHelper.InitializeGrid(bFixLayout : Boolean = True); var c, r: integer; begin if bFixLayout then begin FixedRows := 1; RowCount := FixedRows + 1; FixedCols := 1; ColCount := FixedCols + 1; ColWidths[ 0 ] := Width div 3; // 1/3 the width ColWidths[ 1 ] := MulDiv(Width, 3, 2); // 2/3 the width end; // Clear content for r := 0 to RowCount - 1 do for c := 0 to ColCount - 1 do Cells[c, r] := ''; // header row if FixedRows > 0 then begin Cells[0, 0] := iemsg(IEMSG_NAME); Cells[1, 0] := iemsg(IEMSG_VALUE); end; end; procedure _NewGrid(AStringGrid: TStringGrid; AMetaType : TIEMetaType; bReadOnly : Boolean); var i: integer; sDescription: string; iRowMax: Integer; begin with AStringGrid do begin case AMetaType of iemEXIF : iRowMax := High(ExifTags); iemIPTC : iRowMax := High(IPTCTags); iemDicom, iemXMP : iRowMax := -1; // Filled later else raise EIEException.create('Invalid'); end; // add a row for each EXIF plus the header (if there is a fixed row) if iRowMax > 0 then RowCount := iRowMax + 1 + FixedRows else RowCount := FixedRows + 1; InitializeGrid(False); // fill the fields with the EXIF property names for i := 0 to RowCount - 2 do begin case AMetaType of iemEXIF : sDescription := ExifTags[i].Desc; iemIPTC : sDescription := IPTCTags[i].Desc; iemDicom, iemXMP : sDescription := ''; // Filled later else raise EIEException.create('Invalid'); end; Cells[0, i + FixedRows] := sDescription; Cells[1, i + FixedRows] := ''; end; if bReadOnly then Options := Options - [goEditing] else Options := Options + [goEditing]; end; end; {!! TStringGridHelper.NewGridForExif Declaration procedure NewGridForExif(bReadOnly : Boolean = False); Description Set up a TStringGrid for specifying values for EXIF fields (e.g. to a file without EXIF fields presently). Two columns will be added with the left one containing property descriptions (using
) and the right blank for field entry. If the grid has a fixed row it will be given a heading of "Name" and "Value". If bReadOnly is true the right-column will not be editable. Note: You may wish to call before NewGridForExif to automatically assign the optimal layout to the grid. Example // Display a grid allowing user to add EXIF data procedure TExifForm.FormCreate(Sender: TObject); begin // Fix grid layout MyExifStringGrid.InitializeGrid; // Add fields to grid MyExifStringGrid.NewGridForExif; end; !!} procedure TStringGridHelper.NewGridForExif(bReadOnly : Boolean = False); begin _NewGrid(Self, iemEXIF, bReadOnly); end; {!! TStringGridHelper.NewGridForIPTC Declaration procedure NewGridForIPTC(bReadOnly : Boolean = False); Description Set up a TStringGrid for specifying values for IPTC fields (e.g. to a file without IPTC fields presently). Two columns will be added with the left one containing property descriptions and the right blank for field entry. If the grid has a fixed row it will be given a heading of "Name" and "Value". If bReadOnly is true the right-column will not be editable. Note: You may wish to call before NewGridForIPTC to automatically assign the optimal layout to the grid. Example // Display a grid allowing user to add IPTC data procedure TIPTCForm.FormCreate(Sender: TObject); begin // Fix grid layout MyIPTCStringGrid.InitializeGrid; // Add fields to grid MyIPTCtringGrid.NewGridForIPTC; end; !!} // Formerly InitializeIPTCStringGrid procedure TStringGridHelper.NewGridForIPTC(bReadOnly : Boolean = False); begin _NewGrid(Self, iemIPTC, bReadOnly); end; {!! TStringGridHelper.ReadGridFromExif Declaration function ReadGridFromExif(IOParams : ; bReadOnly : Boolean = False) : Boolean; overload; function ReadGridFromExif(const sFilename : string; bReadOnly : Boolean = False) : Boolean; overload; Description Fill a TStringGrid with the EXIF properties of the current image, or one loaded from file. Two columns will be added with the left one containing property descriptions (using ) and the right one containing properties values (using ). If the grid has a fixed row it will be given a heading of "Name" and "Value". If bReadOnly is true the right-column will not be editable. Result is true if the file has any EXIF fields. Note: You may wish to call before ReadGridFromExif to automatically assign the optimal layout to the grid. Examples // Display the EXIF properties of the current image MyExifStringGrid.ReadGridFromExif( ImageEnView1.IO.Params ); // Read-only display of EXIF properties of a file MyExifStringGrid.ReadGridFromExif( 'C:\MyImage.jpeg', True ); !!} function TStringGridHelper.ReadGridFromExif(IOParams : TIOParams; bReadOnly : Boolean = False) : Boolean; begin NewGridForExif(bReadOnly); Result := _ReadFromEXIF_Params(Self, IOParams); end; function TStringGridHelper.ReadGridFromExif(const sFilename : string; bReadOnly : Boolean = False) : Boolean; begin NewGridForExif(bReadOnly); Result := _ReadFromMeta_File(Self, iemEXIF, sFilename); end; {!! TStringGridHelper.ReadGridFromIPTC Declaration function ReadGridFromIPTC(IOParams : ; bReadOnly : Boolean = False) : Boolean; overload; function ReadGridFromIPTC(const sFilename : string; bReadOnly : Boolean = False) : Boolean; overload; Description Fill a TStringGrid with the IPTC properties of the current image, or one loaded from file. Two columns will be added with the left one containing property descriptions and the right one containing properties values. If the grid has a fixed row it will be given a heading of "Name" and "Value". If bReadOnly is true the right-column will not be editable. Result is true if the file has any IPTC fields. Note: You may wish to call before ReadGridFromIPTC to automatically assign the optimal layout to the grid. Examples // Display the IPTC properties of the current image MyIPTCStringGrid.ReadGridFromIPTC( ImageEnView1.IO.Params ); // Read-only display of IPTC properties of a file MyIPTCStringGrid.ReadGridFromIPTC( 'C:\MyImage.jpeg', True ); !!} // Formerly LoadIPTCFields function TStringGridHelper.ReadGridFromIPTC(IOParams : TIOParams; bReadOnly : Boolean = False) : Boolean; begin NewGridForIPTC(bReadOnly); Result := _ReadFromIPTC_Params(Self, IOParams); end; function TStringGridHelper.ReadGridFromIPTC(const sFilename : string; bReadOnly : Boolean = False) : Boolean; begin NewGridForIPTC(bReadOnly); Result := _ReadFromMeta_File(Self, iemIPTC, sFilename); end; {!! TStringGridHelper.ReadGridFromDicom Declaration function ReadGridFromDicom(IOParams : ; TagInclude: ) : Boolean; overload; function ReadGridFromDicom(const sFilename : string; TagInclude: ) : Boolean; overload; Description Fill a TStringGrid with the Dicom properties of the current image, or one loaded from file. Two columns will be added with the left one containing property descriptions (using ) and the right one containing Dicom values (using ). If the grid has a fixed row it will be given a heading of "Name" and "Value". TagInclude allows you to filter the types of tags returned. Result is true if the file has any Dicom fields. Note: You may wish to call before ReadGridFromDicom to automatically assign the optimal layout to the grid. Examples // Display the Dicom properties of the current image (all types) MyDicomGridView.ReadGridFromDicom( ImageEnView1.IO.Params, [ diProprietary, diDeprecated, diChildTags, diUnknown ] ); // Display of Dicom properties of a file (excluding deprecated and unknown tags) MyDicomGridView.ReadGridFromDicom( 'C:\MyImage.jpeg', [ diProprietary, diChildTags ] ); !!} {$ifdef IEINCLUDEDICOM} function TStringGridHelper.ReadGridFromDicom(IOParams : TIOParams; TagInclude: TIEDicomInclude) : Boolean; begin _NewGrid(Self, iemDicom, True); Result := _ReadFromDicom_Params(Self, IOParams, TagInclude); end; {$endif} {$ifdef IEINCLUDEDICOM} function TStringGridHelper.ReadGridFromDicom(const sFilename : string; TagInclude: TIEDicomInclude) : Boolean; begin _NewGrid(Self, iemDicom, True); Result := _ReadFromMeta_File(Self, iemDicom, sFilename, TagInclude); end; {$endif} {!! TStringGridHelper.ReadGridFromXMP Declaration function ReadGridFromXMP(IOParams : ) : Boolean; overload; function ReadGridFromXMP(const sFilename : string) : Boolean; overload; Description Fill a TStringGrid with XMP properties of the current image, or one loaded from file. Two columns will be added with the left one containing property descriptions and the right one containing XMP values (using ). If the grid has a fixed row it will be given a heading of "Name" and "Value". Result is true if the file has XMP fields. Note: Only common XMP fields are added Demo Demos\InputOutput\XMP\XMP.dpr Examples // Display the XMP properties of the current image MyXMPGridView.ReadGridFromXMP( ImageEnView1.IO.Params ); // Display of XMP properties of a file MyXMPGridView.ReadGridFromXMP( 'C:\MyImage.jpeg' ); !!} function TStringGridHelper.ReadGridFromXMP(IOParams : TIOParams) : Boolean; begin _NewGrid(Self, iemXMP, True); Result := _ReadFromXMP_Params( Self, IOParams ); end; function TStringGridHelper.ReadGridFromXMP(const sFilename : string) : Boolean; begin _NewGrid(Self, iemXMP, True); Result := _ReadFromMeta_File( Self, iemXMP, sFilename ); end; {!! TStringGridHelper.WriteGridToExif Declaration function WriteGridToExif(IOParams : ) : Boolean; overload; function WriteGridToExif(const sFilename : string) : Boolean; overload; Description Write the changes made by a user to EXIF values in a TStringGrid (which was filled using or ) to the current image or an image file. Result is true if any changes were made to the EXIF properties (i.e. a result of false means the TStringGrid EXIF content matches the file). Notes: - For first overload, only the is updated, the changes are not saved to file. - For the second overload, the file must already exist! If no changes were made to the EXIF data then the file is not modified Examples // Write changes to EXIF properties of the current image, and ask if the user wants to save changes if any fields were modified if MyExifStringGrid.WriteGridToExif( ImageEnView1.IO.Params ) then PromptToSaveFile; // write EXIF changes to a file MyExifStringGrid.WriteGridToExif( 'D:\MyImage.jpeg' ); !!} function TStringGridHelper.WriteGridToExif(IOParams : TIOParams) : Boolean; begin Result := _WriteToExif_Params(Self, IOParams); end; function TStringGridHelper.WriteGridToExif(const sFilename : string) : Boolean; begin Result := _WriteToMeta_File(Self, iemEXIF, sFilename); end; {!! TStringGridHelper.WriteGridToIPTC Declaration function WriteGridToIPTC(IOParams : ) : Boolean; overload; function WriteGridToIPTC(const sFilename : string) : Boolean; overload; Description Write the changes made by a user to IPTC values in a TStringGrid (which was filled using or ) to the current image or an image file. Result is true if any changes were made to the IPTC properties (i.e. a result of false means the TStringGrid IPTC content matches the file). Notes: - For first overload, only the is updated, the changes are not saved to file. - For the second overload, the file must already exist! If no changes were made to the IPTC data then the file is not modified Examples // Write changes to IPTC properties of the current image, and ask if the user wants to save changes if any fields were modified if MyIPTCStringGrid.WriteGridToIPTC( ImageEnView1.IO.Params ) then PromptToSaveFile; // write IPTC changes to a file MyIPTCStringGrid.WriteGridToIPTC( 'D:\MyImage.jpeg' ); !!} // Formerly SaveIPTCFields function TStringGridHelper.WriteGridToIPTC(IOParams : TIOParams) : Boolean; begin Result := _WriteToIPTC_Params(Self, IOParams); end; function TStringGridHelper.WriteGridToIPTC(const sFilename : string) : Boolean; begin Result := _WriteToMeta_File(Self, iemIPTC, sFilename); end; {!! TStringGridHelper.ClearGridFields Declaration procedure ClearGridFields; Description Clears all values in a TStringGrid containing EXIF or IPTC properties, which was filled using one of the following: - - - - Note: Only clears the grid, not EXIF or IPTC properties of a file Examples procedure TMainForm.btnResetGridClick(Sender: TObject); begin // Clear all the specified values for our grid MyExifStringGrid.ClearGridFields; end; !!} procedure TStringGridHelper.ClearGridFields; var i: integer; begin for i := FixedRows to RowCount - 1 do Cells[1, i] := ''; end; {$endif} {$endif} { TListViewHelper } {$IFDEF Delphi2005orNewer} {$IFDEF USE_LISTVIEW} {!! TListViewHelper.InitializeList Declaration procedure InitializeList(bFixLayout : Boolean = True); Description Set up a TListView for display or editing of EXIF, IPTC and Dicom meta data. If bFixLayout is true then it will automatically adjust the properties for best display. Example // Display a TListView allowing user to add EXIF data procedure TEXIFForm.FormCreate(Sender: TObject); begin // Fix List layout MyExifListView.InitializeList; // Add fields to List MyExifListView.NewListForExif; end; !!} procedure TListViewHelper.InitializeList(bFixLayout : Boolean = True); const Buffer_px = 4; var aListColumn: TListColumn; begin Clear; if bFixLayout then begin ViewStyle := vsReport; Columns.Clear; end; // Clear content Clear; // Setup the columns if Columns.count < 2 then begin aListColumn := Columns.Add; aListColumn.Caption := iemsg(IEMSG_NAME); aListColumn.Width := Width div 3; // 1/3 width aListColumn := Columns.Add; aListColumn.Caption := iemsg(IEMSG_VALUE); aListColumn.Width := MulDiv(Width, 3, 2) - GetSystemMetrics(SM_CYVSCROLL) - Buffer_px; // 2/3 width less Scrollbar width end; end; procedure _NewList(aListView: TListView; AMetaType : TIEMetaType; bReadOnly : Boolean); var i: integer; aListItem: TListItem; iRowMax: Integer; sDescription: string; begin with aListView do begin InitializeList( False ); case AMetaType of iemEXIF : iRowMax := High(ExifTags); iemIPTC : iRowMax := High(IPTCTags); iemDicom, iemXMP : iRowMax := -1; // Handle at time of fill else raise EIEException.create('Invalid'); end; // fill the fields with the property names for i := 0 to iRowMax do begin case AMetaType of iemEXIF : sDescription := ExifTags[i].Desc; iemIPTC : sDescription := IPTCTags[i].Desc; else raise EIEException.create('Invalid'); end; aListItem := Items.Add; aListItem.Caption := sDescription; aListItem.SubItems.Add('') end; ReadOnly := bReadOnly; end; end; {!! TListViewHelper.NewListForExif Declaration procedure NewListForExif; Description Set up a TListView for specifying values for EXIF fields (e.g. to a file without EXIF fields presently). Two columns will be added with the left one containing property descriptions (using ) and the right blank for field entry. The headings will read "Name" and "Value". Notes: - A standard TListView does not permit editing of subitems, so either download a TListView descendent that allows editing, or search for code snippets for "Edit Subitems TListView" - You may wish to call before NewListForExif to automatically assign the optimal layout to the TListView Example // Display a TListView allowing user to add EXIF data procedure TExifForm.FormCreate(Sender: TObject); begin // Fix List layout MyExifListView.InitializeList; // Add fields to List MyExifListView.NewListForExif; end; !!} procedure TListViewHelper.NewListForExif(); begin _NewList(Self, iemEXIF, True); end; {!! TListViewHelper.NewListForIPTC Declaration procedure NewListForIPTC; Description Set up a TListView for specifying values for IPTC fields (e.g. to a file without IPTC fields presently). Two columns will be added with the left one containing property descriptions and the right blank for field entry. The headings will read "Name" and "Value". Notes: - A standard TListView does not permit editing of subitems, so either download a TListView descendent that allows editing, or search for code snippets for "Edit Subitems TListView" - Call before NewListForIPTC to automatically assign the optimal layout to the TListView Example // Display a TListView allowing user to add IPTC data procedure TIPTCForm.FormCreate(Sender: TObject); begin // Fix List layout MyIPTCListView.InitializeList; // Add fields to List MyIPTCListView.NewListForIPTC; end; !!} // Formerly InitializeIPTCListView procedure TListViewHelper.NewListForIPTC(); begin _NewList(Self, iemIPTC, True); end; {!! TListViewHelper.ReadListFromExif Declaration function ReadListFromExif(IOParams : ) : Boolean; overload; function ReadListFromExif(const sFilename : string) : Boolean; overload; Description Fill a TListView with the EXIF properties of the current image, or one loaded from file. Result is true if the file has any EXIF fields. Note: You may wish to call before ReadListFromExif to automatically assign the optimal layout to the TListView Examples // Display the EXIF properties of the current image MyExifListView.ReadListFromExif( ImageEnView1.IO.Params ); // Read-only display of EXIF properties of a file MyExifListView.ReadListFromExif( 'C:\MyImage.jpeg', True ); !!} function TListViewHelper.ReadListFromExif(IOParams : TIOParams) : Boolean; begin NewListForExif(); Result := _ReadFromEXIF_Params(Self, IOParams); end; function TListViewHelper.ReadListFromExif(const sFilename : string) : Boolean; begin NewListForExif(); Result := _ReadFromMeta_File(Self, iemEXIF, sFilename); end; {!! TListViewHelper.ReadListFromIPTC Declaration function ReadListFromIPTC(IOParams : ) : Boolean; overload; function ReadListFromIPTC(const sFilename : string) : Boolean; overload; Description Fill a TListView with the IPTC properties of the current image, or one loaded from file. Result is true if the file has any IPTC fields specified. Note: You may wish to call before ReadListFromIPTC to automatically assign the optimal layout to the TListView Examples // Display the IPTC properties of the current image MyIPTCListView.ReadListFromIPTC( ImageEnView1.IO.Params ); // Read-only display of IPTC properties of a file MyIPTCListView.ReadListFromIPTC( 'C:\MyImage.jpeg', True ); !!} // Formerly LoadIPTCFields function TListViewHelper.ReadListFromIPTC(IOParams : TIOParams) : Boolean; begin NewListForIPTC(); Result := _ReadFromIPTC_Params(Self, IOParams); end; function TListViewHelper.ReadListFromIPTC(const sFilename : string) : Boolean; begin NewListForIPTC(); Result := _ReadFromMeta_File(Self, iemIPTC, sFilename); end; {!! TListViewHelper.ReadListFromDicom Declaration function ReadListFromDicom(IOParams : ; TagInclude: ) : Boolean; overload; function ReadListFromDicom(const sFilename : string; TagInclude: ) : Boolean; overload; Description Fill a TListView with the Dicom properties of the current image, or one loaded from file. TagInclude allows you to filter the types of tags returned. Result is true if the file has any Dicom fields specified. Note: You may wish to call before ReadListFromDicom to automatically assign the optimal layout to the TListView Examples // Display the Dicom properties of the current image (all types) MyDicomListView.ReadListFromDicom( ImageEnView1.IO.Params, [ diProprietary, diDeprecated, diChildTags, diUnknown ] ); // Display of Dicom properties of a file (excluding deprecated and unknown tags) MyDicomListView.ReadListFromDicom( 'C:\MyImage.jpeg', [ diProprietary, diChildTags ] ); !!} {$ifdef IEINCLUDEDICOM} function TListViewHelper.ReadListFromDicom(IOParams : TIOParams; TagInclude: TIEDicomInclude) : Boolean; begin _NewList(Self, iemDicom, True); Result := _ReadFromDicom_Params(Self, IOParams, TagInclude); end; {$endif} {$ifdef IEINCLUDEDICOM} function TListViewHelper.ReadListFromDicom(const sFilename : string; TagInclude: TIEDicomInclude) : Boolean; begin _NewList(Self, iemDicom, True); Result := _ReadFromMeta_File(Self, iemDicom, sFilename, TagInclude); end; {$endif} {!! TListViewHelper.ReadListFromXMP Declaration function ReadListFromXMP(IOParams : ) : Boolean; overload; function ReadListFromXMP(const sFilename : string) : Boolean; overload; Description Fill a TListView with XMP properties of the current image, or one loaded from file. Result is true if the file has XMP fields specified. Note: Only common XMP fields are added Examples // Display the XMP properties of the current image MyXMPListView.ReadListFromXMP( ImageEnView1.IO.Params ); // Display of XMP properties of a file (excluding deprecated and unknown tags) MyXMPListView.ReadListFromXMP( 'C:\MyImage.jpeg' ); !!} function TListViewHelper.ReadListFromXMP(IOParams : TIOParams) : Boolean; begin _NewList(Self, iemXMP, True); Result := _ReadFromXMP_Params( Self, IOParams ); end; function TListViewHelper.ReadListFromXMP(const sFilename : string) : Boolean; begin _NewList(Self, iemXMP, True); Result := _ReadFromMeta_File( Self, iemXMP, sFilename ); end; {!! TListViewHelper.WriteListToExif Declaration function WriteListToExif(IOParams : ) : Boolean; overload; function WriteListToExif(const sFilename : string) : Boolean; overload; Description Write the changes made by a user to EXIF values in a TListView (which was initialized using or ) to the current image or an image file. Result is true if any changes were made to the EXIF properties (i.e. a result of false means the TListView EXIF content matches the file). NOTE: A standard TListView does not permit editing of subitems, so either download a TListView descendent that allows editing, or search for code snippets for "Edit Subitems TListView" Other Notes: - For first overload, only the is updated, the changes are not saved to file. - For the second overload, the file must already exist! If no changes were made to the EXIF data then the file is not modified Examples // Write changes to EXIF properties of the current image, and ask if the user wants to save changes if any fields were modified if MyExifListView.WriteListToExif( ImageEnView1.IO.Params ) then PromptToSaveFile; // write EXIF changes to a file MyExifListView.WriteListToExif( 'D:\MyImage.jpeg' ); !!} function TListViewHelper.WriteListToExif(IOParams : TIOParams) : Boolean; begin Result := _WriteToEXIF_Params(Self, IOParams); end; function TListViewHelper.WriteListToExif(const sFilename : string) : Boolean; begin Result := _WriteToMeta_File(Self, iemEXIF, sFilename); end; {!! TListViewHelper.WriteListToIPTC Declaration function WriteListToIPTC(IOParams : ) : Boolean; overload; function WriteListToIPTC(const sFilename : string) : Boolean; overload; Description Write the changes made by a user to IPTC values in a TListView (which was initialized using or ) to the current image or an image file. Result is true if any changes were made to the IPTC properties (i.e. a result of false means the TListView IPTC content matches the file). NOTE: A standard TListView does not permit editing of subitems, so either download a TListView descendent that allows editing, or search for code snippets for "Edit Subitems TListView" Other Notes: - For first overload, only the is updated, the changes are not saved to file. - For the second overload, the file must already exist! If no changes were made to the IPTC data then the file is not modified Examples // Write changes to IPTC properties of the current image, and ask if the user wants to save changes if any fields were modified if MyIPTCListView.WriteListToIPTC( ImageEnView1.IO.Params ) then PromptToSaveFile; // write IPTC changes to a file MyIPTCListView.WriteListToIPTC( 'D:\MyImage.jpeg' ); !!} // Formerly SaveIPTCFields function TListViewHelper.WriteListToIPTC(IOParams : TIOParams) : Boolean; begin Result := _WriteToIPTC_Params(Self, IOParams); end; function TListViewHelper.WriteListToIPTC(const sFilename : string) : Boolean; begin Result := _WriteToMeta_File(Self, iemIPTC, sFilename); end; {!! TListViewHelper.ClearListFields Declaration procedure ClearListFields; Description Clears all values in a TListView containing EXIF or IPTC properties, which was initialized using: - - - - Note: Only clears the ListView, not EXIF/IPTC properties of a file Examples procedure TMainForm.btnResetListClick(Sender: TObject); begin // Clear all the specified values for our ListView MyExifListView.ClearEXIFFields; end; !!} procedure TListViewHelper.ClearListFields; var i: integer; begin for i := 0 to Items.Count - 1 do Items.Item[i].SubItems[0] := ''; end; {$endif} {$endif} { TIOParamsHelper } {$IFDEF Delphi2005orNewer} {!! TIOParamsHelper.EXIF_Camera_Str Declaration property EXIF_Camera_Str : string; (read/write) Description Returns a concatenation of and . !!} function TIOParamsHelper.GetEXIF_Camera_Str : AnsiString; var sMake, sModel: string; begin // EXIF_Make and EXIF_Model combined sMake := RemoveNullA(EXIF_Make); sModel := RemoveNullA(EXIF_Model); // sometimes EXIF_Model already includes the make if (sMake <> '') and (pos(sMake, sModel) > 0) then sMake := ''; if ( sMake <> '' ) and ( sModel <> '' ) then Result := AnsiString( sMake + ' ' + sModel ) else Result := AnsiString( sMake + sModel ); end; {!! TIOParamsHelper.EXIF_XResolution_Str Declaration property EXIF_XResolution_Str : string; (read/write) Description A string formatted version of . E.g. if EXIF_XResolution is 72 then EXIF_XResolution_Str returns '1/72' !!} function TIOParamsHelper.GetEXIF_XResolution_Str : AnsiString; begin // Display/Print resolution of image. Default value is 1/72inch, but it has no mean because personal computer doesn't use this value to display/print out result := AnsiString( DoubleToFraction( EXIF_Xresolution )); end; {!! TIOParamsHelper.EXIF_YResolution_Str Declaration property EXIF_YResolution_Str : string; (read/write) Description A string formatted version of . E.g. if EXIF_YResolution is 72 then EXIF_YResolution_Str returns '1/72' !!} function TIOParamsHelper.GetEXIF_YResolution_Str : AnsiString; begin // Display/Print resolution of image. Default value is 1/72inch, but it has no mean because personal computer doesn't use this value to display/print out result := AnsiString( DoubleToFraction( EXIF_Yresolution )); end; {!! TIOParamsHelper.EXIF_SubjectArea_Str Declaration property EXIF_SubjectArea_Str : string; (read-only) Description A string formatted version of . Example results: "Point at 100,200" "Circle of 50 centered at 100,200" "Rectangle of 50,50 centered at 100,200" !!} function TIOParamsHelper.GetEXIF_SubjectArea_Str : string; begin Result := ''; { Subject Area Specifies the location and area of the main subject in the overall scene. EXIF_SubjectArea has either 2, 3, or 4 values, so Index can be 0 to 3. The subject location and area are defined by Count values as follows: Count = 2: Indicates the location of the main subject as coordinates. The first value is the X coordinate and the second is the Y coordinate. Count = 3: The area of the main subject is given as a circle. The circular area is expressed as center coordinates and diameter. The first value is the center X coordinate, the second is the center Y coordinate, and the third is the diameter. Count = 4: The area of the main subject is given as a rectangle. The rectangular area is expressed as center coordinates and area dimensions. The first value is the center X coordinate, the second is the center Y coordinate, the third is the width of the area, and the fourth is the height of the area. } // Can have 2, 3 or 4 values if EXIF_SubjectArea[ 3 ] <> -1 then // The area of the main subject is given as a rectangle. The rectangular area is expressed as center coordinates and area dimensions. The first value is the center X coordinate, the second is the center Y coordinate, the third is the width of the area, and the fourth is the height of the area. // 'Rectangle of %d,%d centered at %d,%d' Result := Format( s_RectangleOfXByXCenteredAtXByX, [ EXIF_SubjectArea[ 2 ], EXIF_SubjectArea[ 3 ], EXIF_SubjectArea[ 0 ], EXIF_SubjectArea[ 1 ] ]) else if EXIF_SubjectArea[ 2 ] <> -1 then // The area of the main subject is given as a circle. The circular area is expressed as center coordinates and diameter. The first value is the center X coordinate, the second is the center Y coordinate, and the third is the diameter. // 'Circle of %d centered at %d,%d' Result := Format( s_CircleOfXCenteredAtAtXByX, [ EXIF_SubjectArea[ 2 ], EXIF_SubjectArea[ 0 ], EXIF_SubjectArea[ 1 ] ]) else if EXIF_SubjectArea[ 1 ] <> -1 then // Location of the main subject as coordinates. The first value is the X coordinate and the second is the Y coordinate. // 'Point at %d,%d' Result := Format( s_PointAtXByX, [ EXIF_SubjectArea[ 0 ], EXIF_SubjectArea[ 1 ] ]); end; {!! TIOParamsHelper.EXIF_SubjectLocation_Str Declaration property EXIF_SubjectLocation_Str : string; (read/write) Description A string formatted version of and , e.g. "150,250" !!} function TIOParamsHelper.GetEXIF_SubjectLocation_Str : string; begin Result := ''; if ( EXIF_SubjectLocationX <> -1 ) and ( EXIF_SubjectLocationY <> -1 ) then Result := IntToStr( EXIF_SubjectLocationX ) + ',' + IntToStr( EXIF_SubjectLocationY ); end; procedure TIOParamsHelper.SetEXIF_SubjectLocation_Str(Value : string); var sLocationX, sLocationY : string; begin sLocationX := GetTextBeforeChar( Value, ',', True ); if sLocationX = '' then EXIF_SubjectLocationX := -1 else EXIF_SubjectLocationX := StrToInt( sLocationX ); sLocationY := GetTextAfterChar ( Value, ',', True ); if sLocationY = '' then EXIF_SubjectLocationY := -1 else EXIF_SubjectLocationY := StrToInt( sLocationY ); end; {!! TIOParamsHelper.EXIF_ExposureTime_Str Declaration property EXIF_ExposureTime_Str : string; (read/write) Description A string formatted version of . E.g. if EXIF_ExposureTime is 4 then EXIF_ExposureTime_Str returns '4' (seconds). If EXIF_ExposureTime is 0.25 then it returns '1/4' (of a second). !!} function TIOParamsHelper.GetEXIF_ExposureTime_Str : string; var iExposureTime: double; begin // Exposure time (reciprocal of shutter speed). Unit is seconds iExposureTime := EXIF_ExposureTime; if iExposureTime > 1 then // then it will be something like 4 i.e. 4 seconds result := inttostr(round(iExposureTime)) else if (iExposureTime > 0) then // then it is an integer second value, e.g. 0.25, which translates to 1/4 second result := DoubleToFraction(round(1 / iExposureTime)); end; {!! TIOParamsHelper.EXIF_FNumber_Str Declaration property EXIF_FNumber_Str : string; (read/write) Description A string formatted version of . EXIF_FNumber_Str simply prefixes an 'F' for valid values, e.g. if EXIF_FNumber is 5.6, this property would return 'F5.6' !!} function TIOParamsHelper.GetEXIF_FNumber_Str : string; begin // The actual F-number(F-stop) of lens when the image was taken result := ''; if (EXIF_Fnumber <> 0) and (EXIF_Fnumber <> -1) then result := 'F' + FloatToStrOrNull( EXIF_FNumber ); end; {!! TIOParamsHelper.EXIF_ShutterSpeedValue_Str Declaration property EXIF_ShutterSpeedValue_Str : string; (read/write) Description A string formatted version of . Returns the value as a formatted fraction or number, e.g. '1/4' of a second or '2' (seconds). !!} function TIOParamsHelper.GetEXIF_ShutterSpeedValue_Str : string; begin // Shutter speed by APEX value. To convert this value to ordinary 'Shutter Speed'; calculate this value's power of 2, then reciprocal. For example, if the ShutterSpeedValue is '4', shutter speed is 1/(24)=1/16 second result := ApexToStr(2, EXIF_ShutterSpeedValue, '1/'); end; {!! TIOParamsHelper.EXIF_ApertureValue_Str Declaration property EXIF_ApertureValue_Str : string; (read/write) Description A string formatted version of . EXIF_ApertureValue is an Apex value which can be difficult to calculate. This property returns a human readible format, e.g. if EXIF_ApertureValue is 5, then 'F5.6' will be returned. !!} function TIOParamsHelper.GetEXIF_ApertureValue_Str : string; begin // The actual aperture value of lens when the image was taken. Unit is APEX. To convert this value to // ordinary F-number (F-stop), calculate this value's power of root 2 (=1.4142). For example, if the // ApertureValue is '5', F-number is 1.41425 = F5.6. result := ApexToStr(Sqrt(2), EXIF_ApertureValue, 'F'); if Result = 'F0' then result := ''; end; {!! TIOParamsHelper.EXIF_MaxApertureValue_Str Declaration property EXIF_MaxApertureValue_Str : string; (read/write) Description A string formatted version of . EXIF_MaxApertureValue is an Apex value which can be difficult to calculate. This property returns a human readible format, e.g. if EXIF_MaxApertureValue is 5, then 'F5.6' will be returned. !!} function TIOParamsHelper.GetEXIF_MaxApertureValue_Str : string; begin // Maximum aperture value of lens. You can convert to F-number by calculating power of root 2 (same process of ApertureValue) result := ApexToStr(Sqrt(2), EXIF_MaxApertureValue, 'F'); if Result = 'F0' then result := ''; end; {!! TIOParamsHelper.EXIF_AsStr Declaration property EXIF_AsStr [index : Integer]: string; (read/write) Description Provides an alternative way to access EXIF properties in batch situations. Each property is available as a human-readible string value, and in most cases write access is also supported. Index is a value between 0 and _EXIF_Tag_Count - 1 and can be referred to by constants. Const Description Writeable? Output _EXIF_UserComment User Comment YES _EXIF_ImageDescription Description YES _EXIF_Make Camera Make YES _EXIF_Model Camera Model YES _EXIF_XResolution Horizontal Resolution YES with unit _EXIF_YResolution Vertical Resolution YES with unit _EXIF_DateTime Date and Time YES DateTimeToStr() _EXIF_DateTimeOriginal Original Date and Time YES DateTimeToStr() _EXIF_DateTimeDigitized Digitized Date and Time YES DateTimeToStr() _EXIF_Copyright Copyright YES _EXIF_Orientation Orientation YES Text description of _EXIF_ExposureTime Exposure Time YES seconds _EXIF_FNumber F-Stop YES _EXIF_ExposureProgram Exposure Program YES Text description of _EXIF_ISOSpeedRatings ISO Speed Rating YES _EXIF_ShutterSpeedValue Shutter Speed YES _EXIF_ApertureValue Aperture Value YES _EXIF_BrightnessValue Brightness YES FloatToStr() _EXIF_ExposureBiasValue Exposure Compensation YES FloatToStr() _EXIF_MaxApertureValue Max Aperture Value YES _EXIF_SubjectDistance Subject Distance YES FloatToStr() m _EXIF_MeteringMode Metering Mode YES Text description of _EXIF_LightSource Lighting YES Text description of _EXIF_Flash Flash YES Text description of _EXIF_FocalLength Focal Length YES FloatToStr() mm _EXIF_FlashPixVersion FlashPix Version YES _EXIF_ColorSpace Color Space YES Text description of _EXIF_ExifImageWidth Image Width YES _EXIF_ExifImageHeight Image Height YES _EXIF_RelatedSoundFile Sound File YES _EXIF_FocalPlaneXResolution Focal Plane Horz. Resolution YES FloatToStr() with unit _EXIF_FocalPlaneYResolution Focal Plane Vert. Resolution YES FloatToStr() with unit _EXIF_ExposureIndex Exposure Index YES FloatToStr() _EXIF_SensingMethod Sensing Method no Text description of _EXIF_FileSource File Source no Text description of _EXIF_SceneType Scene Type no Text description of _EXIF_YCbCrPositioning Data Point YES Text description of _EXIF_ExposureMode Exposure Mode no Text description of _EXIF_WhiteBalance White Balance no Text description of _EXIF_DigitalZoomRatio Digital Zoom Ratio no Text description of _EXIF_FocalLengthIn35mmFilm Focal Length in 35mm Film no IntToStr() mm _EXIF_SceneCaptureType Scene Capture Type no Text description of _EXIF_GainControl Gain Control no Text description of _EXIF_Contrast Contrast no Text description of _EXIF_Saturation Saturation no Text description of _EXIF_Sharpness Sharpness no Text description of _EXIF_SubjectDistanceRange Subject Distance no Text description of _EXIF_GPSLatitude GPS Latitude no _EXIF_GPSLongitude GPS Longitude no _EXIF_GPSAltitude GPS Altitude no Text description of and _EXIF_GPSImageDirection GPS Image Direction no Text description of and _EXIF_GPSTrack GPS Movement Direction no Text description of and _EXIF_GPSSpeed GPS Movement Speed no Text description of and _EXIF_GPSDateAndTime GPS Date and Time no _EXIF_GPSSatellites GPS Satellites YES _EXIF_GPSVersionID GPS Version YES _EXIF_Artist Artist YES _EXIF_XPTitle Title (Windows) YES _EXIF_XPComment Comment (Windows) YES _EXIF_XPAuthor Author (Windows) YES _EXIF_XPKeywords Keywords (Windows) YES _EXIF_XPSubject Subject (Windows) YES _EXIF_XPRating Rating (Windows) YES IntToStr() _EXIF_InteropVersion Interoperability Version YES _EXIF_CameraOwnerName Camera Owner Name YES _EXIF_BodySerialNumber Body Serial Number YES _EXIF_LensMake Lens Make YES _EXIF_LensModel Lens Model YES _EXIF_LensSerialNumber Lens Serial Number YES _EXIF_Gamma Gamma YES FloatToStr() _EXIF_SubjectArea Subject Area no _EXIF_SubjectLocation Subject Location YES
See Also - Examples // Output all fields of current image to a memo (same as ) for i := 0 to _EXIF_Tag_Count - 1 do memo1.Lines.Add( ImageEnView1.IO.Params.EXIF_FieldDescription[ i ] + ': ' + ImageEnView1.IO.Params.EXIF_AsStr[ i ] ); // Set EXIF_ShutterSpeedValue to 1/4 a second ImageEnView1.IO.Params.EXIF_AsStr[ _EXIF_ShutterSpeedValue ] := '1/4'; !!} // get a string representation of the exif data specified by the field index function TIOParamsHelper.GetEXIF_AsStr(Index: Integer): string; function _DateTimeToStrOrNull(aDate : TDateTime): string; begin Result := ''; if aDate <> 0 then result := DateTimeToStr(aDate) end; var sFPUnit: string; // used in retrieval of EXIF data (resolution unit) sResUnit: string; // used in retrieval of EXIF data (resolution unit) begin result := ''; try case Index of _EXIF_UserComment: result := RemoveNull(EXIF_UserComment); _EXIF_ImageDescription: result := RemoveNullA(EXIF_ImageDescription); _EXIF_CameraMake : Result := String( EXIF_Make ); _EXIF_CameraModel: Result := String( EXIF_Model ); { Unit of XResolution/YResolution: 1 means no-unit 2 means inch 3 means centimeter Default value is 2 (inch) } _EXIF_XResolution: { EXIF_XResolution and EXIF_ResolutionUnit } begin case EXIF_ResolutionUnit of 2: sResUnit := s_Inch; 3: sResUnit := s_CM; else sResUnit := ''; end; result := String( EXIF_XResolution_Str ) + ' ' + sResUnit; end; { Unit of XResolution/YResolution: 1 means no-unit 2 means inch 3 means centimeter Default value is 2 (inch) } _EXIF_YResolution: { EXIF_YResolution and EXIF_ResolutionUnit } begin case EXIF_ResolutionUnit of 2: sResUnit := s_Inch; 3: sResUnit := s_CM; else sResUnit := ''; end; result := String( EXIF_YResolution_Str ) + ' ' + sResUnit; end; _EXIF_DateTime: result := _DateTimeToStrOrNull(EXIF_DateTime2); _EXIF_DateTimeOriginal: result := _DateTimeToStrOrNull(EXIF_DateTimeOriginal2); _EXIF_DateTimeDigitized: result := _DateTimeToStrOrNull(EXIF_DateTimeDigitized2); _EXIF_Copyright: result := RemoveNullA(EXIF_Copyright); _EXIF_Orientation: case EXIF_Orientation of 1: result := s_EXIFOrientation1; 2: result := s_EXIFOrientation2; 3: result := s_EXIFOrientation3; 4: result := s_EXIFOrientation4; 5: result := s_EXIFOrientation5; 6: result := s_EXIFOrientation6; 7: result := s_EXIFOrientation7; 8: result := s_EXIFOrientation8; end; _EXIF_ExposureTime: begin result := EXIF_ExposureTime_Str; if result <> '' then begin if Pos('1/', result) > 0 then result := result + ' ' + s_Second else result := result + ' ' + s_Seconds end; end; _EXIF_FNumber: Result := EXIF_FNumber_Str; { EXIF_ExposureProgram: 1 means manual control 2 program normal 3 aperture priority 4 shutter priority 5 program creative (slow program) 6 program action(high-speed program) 7 portrait mode 8 landscape mode. } _EXIF_ExposureProgram: case EXIF_ExposureProgram of 1: result := s_ManualControl; 2: result := s_ProgramNormal; 3: result := s_AperturePriority; 4: result := s_ShutterPriority; 5: result := s_CreativeProgram; 6: result := s_ActionProgram; 7: result := s_Portraitmode; 8: result := s_LandscapeMode; end; // CCD sensitivity equivalent to Ag-Hr film speedrate. _EXIF_ISOSpeedRatings: if (EXIF_ISOSpeedRatings[0] <> 0) and (EXIF_ISOSpeedRatings[0] <> -1) then result := inttostr(EXIF_ISOSpeedRatings[0]); _EXIF_ShutterSpeedValue: result := EXIF_ShutterSpeedValue_Str; _EXIF_ApertureValue: result := EXIF_ApertureValue_Str; { Brightness of taken subject, unit is APEX. To calculate Exposure(Ev) from BrigtnessValue(Bv), you must add SensitivityValue(Sv). Ev=Bv+Sv Sv=log2(ISOSpeedRating/3.125) ISO100 : Sv=5, ISO200 : Sv=6, ISO400 : Sv=7, ISO125 : Sv=5.32. } _EXIF_BrightnessValue: Result := FloatToStrOrNull( EXIF_BrightnessValue ); _EXIF_ExposureBiasValue: result := FloatToStrOrNull( EXIF_ExposureBiasValue ); _EXIF_MaxApertureValue: result := EXIF_MaxApertureValue_Str; // Distance to focus point, unit is meter. _EXIF_SubjectDistance: if EXIF_SubjectDistance > 0 then result := FloatToStrOrNull( EXIF_SubjectDistance, ' m' ); { Exposure metering method: 0 means unknown 1 average 2 center weighted average 3 spot 4 multi-spot 5 multi-segment 6 partial 255 other. } _EXIF_MeteringMode: case EXIF_MeteringMode of 1: result := s_average; 2: result := s_CenterWeightedAverage; 3: result := s_Spot; 4: result := s_MultiSpot; 5: result := s_MultiSegment; 6: result := s_partial; end; { Light source, actually this means white balance setting: 0 means unknown 1 daylight 2 fluorescent 3 tungsten 10 flash 17 standard light A 18 standard light B 19 standard light C 20 D55 21 D65 22 D75 255 other. } _EXIF_LightSource: case EXIF_LightSource of 1: result := s_daylight; 2: result := s_fluorescent; 3: result := s_tungsten; 10: result := s_flash; 17: result := s_standardLightA; 18: result := s_standardLightB; 19: result := s_standardLightC; 20: result := s_D55; 21: result := s_D65; 22: result := s_D75; end; { EXIF_Flash: 0 means flash did not fire 1 flash fired 5 flash fired but strobe return light not detected 7 flash fired and strobe return light detected } _EXIF_Flash: result := FlashModeToString(EXIF_Flash); // Focal length of lens used to take image. Unit is millimeter. _EXIF_FocalLength: if EXIF_FocalLength > 0 then result := FloatToStrOrNull( EXIF_FocalLength, ' mm' ); // Stores FlashPix version. If the image data is based on FlashPix formar Ver.1.0, value is "0100". _EXIF_FlashPixVersion: result := RemoveNullA(EXIF_FlashPixVersion); // Defines Color Space. DCF image must use sRGB color space so value is always '1'. If the picture uses the other color space, value is '65535' : Uncalibrated. _EXIF_ColorSpace: case EXIF_ColorSpace of 1: result := s_RGB; 65535: result := s_Uncalibrated; end; _EXIF_ExifImageWidth : if EXIF_ExifImageWidth > 0 then result := IntToStr(EXIF_ExifImageWidth); _EXIF_ExifImageHeight : if EXIF_ExifImageHeight > 0 then result := IntToStr(EXIF_ExifImageHeight); // If this digicam can record audio data with image, shows name of audio data. _EXIF_RelatedSoundFile: result := RemoveNullA(EXIF_RelatedSoundFile); { Unit of FocalPlaneXResoluton/FocalPlaneYResolution: 1 means no-unit 2 inch 3 centimeter. Note : Some of Fujifilm's digicam(e.g.FX2700, FX2900, Finepix4700Z/40i etc) uses value '3' so it must be 'centimeter', but it seems that they use a '8.3mm?'(1/3in.?) to their ResolutionUnit. Fuji's BUG? Finepix4900Z has been changed to use value '2' but it doesn't match to actual value also. } _EXIF_FocalPlaneXResolution: begin case EXIF_FocalPlaneResolutionUnit of 2: sFPUnit := s_PerInch; 3: sFPUnit := s_PerCM; else sFPUnit := ''; end; // Pixel density at CCD's position. If you have MegaPixel digicam and take a picture by lower resolution(e.g.VGA mode), this value is re-sampled by picture resolution. In such case, FocalPlaneResolution is not same as CCD's actual resolution. if EXIF_FocalPlaneXResolution > 50 then result := IntToStr(Trunc(EXIF_FocalPlaneXResolution)) + sFPUnit else if EXIF_FocalPlaneXResolution > 0 then result := IEFloatToFormatString(EXIF_FocalPlaneXResolution, 2, true) + sFPUnit; end; _EXIF_FocalPlaneYResolution: begin case EXIF_FocalPlaneResolutionUnit of 2: sFPUnit := s_PerInch; 3: sFPUnit := s_PerCM; else sFPUnit := ''; end; // Pixel density at CCD's position. If you have MegaPixel digicam and take a picture by lower resolution(e.g.VGA mode), this value is re-sampled by picture resolution. In such case, FocalPlaneResolution is not same as CCD's actual resolution. if EXIF_FocalPlaneYResolution > 50 then result := IntToStr(Trunc(EXIF_FocalPlaneYResolution)) + sFPUnit else if EXIF_FocalPlaneYResolution > 0 then result := IEFloatToFormatString(EXIF_FocalPlaneYResolution, 2, true) + sFPUnit; end; // EXIF_ExposureIndex: Same as ISOSpeedRatings(0x8827) but data type is unsigned rational. Only Kodak's digicam uses this tag instead of ISOSpeedRating. _EXIF_ExposureIndex: result := FloatToStrOrNull( EXIF_ExposureIndex ); // Image sensor unit: '2' means 1 chip color area sensor, most of all digicam use this type. _EXIF_SensingMethod: if EXIF_SensingMethod = 2 then result := s_OneChipColorAreaSensor; // Image source: Value '0x03' means the image source is digital still camera. _EXIF_FileSource: if EXIF_FileSource = $03 then result := s_DigitalStillCamera; // Type of scene: Value '0x01' means that the image was directly photographed. _EXIF_SceneType: if EXIF_SceneType = $01 then result := s_DirectlyPhotographed; { When image format is YCbCr and uses 'Subsampling' (cropping of chroma data, all the digicam do that), defines the chroma sample point of subsampling pixel array. 1 means the center of pixel array 2 means the datum point. } _EXIF_YCbCrPositioning: case EXIF_YcbCrPositioning of 1: result := s_Centered; 2: result := s_DataPoint; end; { The exposure mode set when the image was shot. In auto-bracketing mode, the camera shoots a series of frames of the same scene at different exposure settings. 0 = Auto exposure 1 = Manual exposure 2 = Auto bracket } _EXIF_ExposureMode: case EXIF_ExposureMode of 0: s_Autoexposure; 1: s_Manualexposure; 2: s_Autobracket; end; { The white balance mode set when the image was shot. 0 = Auto white balance 1 = Manual white balance } _EXIF_WhiteBalance: case EXIF_WhiteBalance of 0: s_Autowhitebalance; 1: s_Manualwhitebalance; end; // The digital zoom ratio when the image was shot. If the numerator of the recorded value is 0, this indicates that digital zoom was not used. _EXIF_DigitalZoomRatio: if (EXIF_DigitalZoomRatio = 0) or (EXIF_DigitalZoomRatio = -1) then result := s_None else result := FloatToStrOrNull( EXIF_DigitalZoomRatio ); // The equivalent focal length assuming a 35mm film camera, in mm. A value of 0 means the focal length is unknown. Note that this tag differs from the FocalLength tag. _EXIF_FocalLengthIn35mmFilm: if EXIF_FocalLengthIn35mmFilm > 0 then result := IntToStr(EXIF_FocalLengthIn35mmFilm) + ' mm'; { The type of scene that was shot. It can also be used to record the mode in which the image was shot. Note that this differs from the scene type (SceneType) tag. 0 = Standard 1 = Landscape 2 = Portrait 3 = Night scene } _EXIF_SceneCaptureType: case EXIF_SceneCaptureType of 0: s_Standard; 1: s_Landscape; 2: s_Portrait; 3: s_Nightscene; end; { The degree of overall image gain adjustment. 0 = None 1 = Low gain up 2 = High gain up 3 = Low gain down 4 = High gain down } _EXIF_GainControl: case EXIF_GainControl of 0: s_None; 1: s_LowGainup; 2: s_HighGainup; 3: s_LowGaindown; 4: s_HighGaindown; end; { The direction of contrast processing applied by the camera when the image was shot. 0 = Normal 1 = Soft 2 = Hard } _EXIF_Contrast: case EXIF_Contrast of 0: s_Normal; 1: s_Soft; 2: s_Hard; end; { The direction of saturation processing applied by the camera when the image was shot. 0 = Normal 1 = Low saturation 2 = High saturation } _EXIF_Saturation: case EXIF_Saturation of 0: s_Normal; 1: s_Lowsaturation; 2: s_Highsaturation; end; { The direction of sharpness processing applied by the camera when the image was shot. 0 = Normal 1 = Soft 2 = Hard } _EXIF_Sharpness: case EXIF_Sharpness of 0: s_Normal; 1: s_Soft; 2: s_Hard; end; { The distance to the subject: 0 = unknown 1 = Macro 2 = Close view 3 = Distant view } _EXIF_SubjectDistanceRange: case EXIF_SubjectDistanceRange of 1: s_Macro; 2: s_Closeview; 3: s_Distantview; end; _EXIF_GPSLatitude : Result := EXIF_GPSLatitude_Str; _EXIF_GPSLongitude : Result := EXIF_GPSLongitude_Str; // The altitude based on the reference in Ref. The reference unit is meters. _EXIF_GPSAltitude: if (EXIF_GPSAltitude <> 0) or (EXIF_GPSAltitudeRef <> '') then begin result := FloatToStrOrNull( EXIF_GPSAltitude ); if RemoveNullA(EXIF_GPSAltitudeRef) = '1' then Result := Result + ' (Below sea-level)'; end; _EXIF_GPSDateAndTime: if (EXIF_GPSDateStamp <> '') then begin result := Format('%s %s : %s.%s', [RemoveNullA(EXIF_GPSDateStamp), FloatToStr(EXIF_GPSTimeStampHour), FloatToStr(EXIF_GPSTimeStampMinute), FloatToStr(EXIF_GPSTimeStampSecond)]); end; _EXIF_GPSImageDirection: { EXIF_GPSImgDirection : The direction of the image when it was captured. The range of values is from 0.00 to 359.99. EXIF_GPSImgDirectionRef : The reference for giving the direction of the image when it is captured. 'T' denotes true direction and 'M' is magnetic direction. } if (EXIF_GPSImgDirection <> 0) or (RemoveNullA(EXIF_GPSImgDirectionRef) <> '') then begin result := FloatToStrOrNull( EXIF_GPSImgDirection, ' degrees' ); if uppercase(RemoveNullA(EXIF_GPSImgDirectionRef)) = 'T' then Result := Result + ' (True)' else if uppercase(RemoveNullA(EXIF_GPSImgDirectionRef)) = 'M' then Result := Result + ' (Magnetic)'; end; _EXIF_GPSSpeed: { EXIF_GPSSpeed : speed of GPS receiver movement EXIF_GPSSpeedRef : unit used to express the GPS receiver speed of movement. 'K' 'M' and 'N' represents kilometers per hour, miles per hour, and knots. } if (EXIF_GPSSpeed <> 0) or (RemoveNullA(EXIF_GPSSpeedRef) <> '') then begin if uppercase(RemoveNullA(EXIF_GPSSpeedRef)) = 'K' then Result := FloatToStr(EXIF_GPSSpeed) + ' km/h' else if uppercase(RemoveNullA(EXIF_GPSSpeedRef)) = 'M' then Result := FloatToStr(EXIF_GPSSpeed) + ' mph' else if uppercase(RemoveNullA(EXIF_GPSSpeedRef)) = 'N' then Result := FloatToStr(EXIF_GPSSpeed) + ' knots' else Result := FloatToStr(EXIF_GPSSpeed) + ' ' + RemoveNullA(EXIF_GPSSpeedRef); end; _EXIF_GPSTrack: { EXIF_GPSTrack : direction of GPS receiver movement. The range of values is from 0.00 to 359.99. EXIF_GPSTrackRef : The reference for giving the direction of the direction of GPS receiver movement. 'T' denotes true direction and 'M' is magnetic direction. } if (EXIF_GPSTrack <> 0) or (RemoveNullA(EXIF_GPSTrackRef) <> '') then begin result := FloatToStrOrNull( EXIF_GPSTrack, ' degrees' ); if uppercase(RemoveNullA(EXIF_GPSTrackRef)) = 'T' then Result := Result + ' (True)' else if uppercase(RemoveNullA(EXIF_GPSTrackRef)) = 'M' then Result := Result + ' (Magnetic)'; end; _EXIF_GPSSatellites: result := RemoveNullA(EXIF_GPSSatellites); _EXIF_GPSVersionID: result := RemoveNullA(EXIF_GPSVersionID); _EXIF_Artist: result := RemoveNullA(EXIF_Artist); _EXIF_XPTitle: result := WideCharToString(PWideChar(EXIF_XPTitle)); _EXIF_XPComment: result := WideCharToString(PWideChar(EXIF_XPComment)); _EXIF_XPAuthor: result := WideCharToString(PWideChar(EXIF_XPAuthor)); _EXIF_XPKeywords: result := WideCharToString(PWideChar(EXIF_XPKeywords)); _EXIF_XPSubject: result := WideCharToString(PWideChar(EXIF_XPSubject)); _EXIF_XPRating: begin { Windows XP Rating Allowed values from 0 up to 5. -1 means not available. } if EXIF_XPRating < 0 then Result := '' else Result := IntToStr(EXIF_XPRating); end; _EXIF_InteropVersion : result := RemoveNullA( EXIF_InteropVersion ); _EXIF_CameraOwnerName : result := RemoveNullA( EXIF_CameraOwnerName ); _EXIF_BodySerialNumber : result := RemoveNullA( EXIF_BodySerialNumber ); _EXIF_LensMake : result := RemoveNullA( EXIF_LensMake ); _EXIF_LensModel : result := RemoveNullA( EXIF_LensModel ); _EXIF_LensSerialNumber : result := RemoveNullA( EXIF_LensSerialNumber ); _EXIF_Gamma : result := FloatToStrOrNull( EXIF_Gamma ); _EXIF_SubjectArea : result := EXIF_SubjectArea_Str; _EXIF_SubjectLocation : result := EXIF_SubjectLocation_Str; end; except // ERROR end; end; {!! TIOParamsHelper.EXIF_FieldDescription Declaration property EXIF_FieldDescription [index : Integer]: string; (read-only) Description Returns a description of an EXIF field specified by the constants used by . Index is a value between 0 and _EXIF_Tag_Count - 1. Const Description _EXIF_UserComment User Comment _EXIF_ImageDescription Description _EXIF_Make Camera Make _EXIF_Model Camera Model _EXIF_XResolution Horizontal Resolution _EXIF_YResolution Vertical Resolution _EXIF_DateTime Date and Time _EXIF_DateTimeOriginal Original Date and Time _EXIF_DateTimeDigitized Digitized Date and Time _EXIF_Copyright Copyright _EXIF_Orientation Orientation _EXIF_ExposureTime Exposure Time _EXIF_FNumber F-Stop _EXIF_ExposureProgram Exposure Program _EXIF_ISOSpeedRatings ISO Speed Rating _EXIF_ShutterSpeedValue Shutter Speed _EXIF_ApertureValue Aperture Value _EXIF_BrightnessValue Brightness _EXIF_ExposureBiasValue Exposure Compensation _EXIF_MaxApertureValue Max Aperture Value _EXIF_SubjectDistance Subject Distance _EXIF_MeteringMode Metering Mode _EXIF_LightSource Lighting _EXIF_Flash Flash _EXIF_FocalLength Focal Length _EXIF_FlashPixVersion FlashPix Version _EXIF_ColorSpace Color Space _EXIF_ExifImageWidth Image Width _EXIF_ExifImageHeight Image Height _EXIF_RelatedSoundFile Sound File _EXIF_FocalPlaneXResolution Focal Plane Horz. Resolution _EXIF_FocalPlaneYResolution Focal Plane Vert. Resolution _EXIF_ExposureIndex Exposure Index _EXIF_SensingMethod Sensing Method _EXIF_FileSource File Source _EXIF_SceneType Scene Type _EXIF_YCbCrPositioning Data Point _EXIF_ExposureMode Exposure Mode _EXIF_WhiteBalance White Balance _EXIF_DigitalZoomRatio Digital Zoom Ratio _EXIF_FocalLengthIn35mmFilm Focal Length in 35mm Film _EXIF_SceneCaptureType Scene Capture Type _EXIF_GainControl Gain Control _EXIF_Contrast Contrast _EXIF_Saturation Saturation _EXIF_Sharpness Sharpness _EXIF_SubjectDistanceRange Subject Distance _EXIF_GPSLatitude GPS Latitude _EXIF_GPSLongitude GPS Longitude _EXIF_GPSAltitude GPS Altitude _EXIF_GPSImageDirection GPS Image Direction _EXIF_GPSTrack GPS Movement Direction _EXIF_GPSSpeed GPS Movement Speed _EXIF_GPSDateAndTime GPS Date and Time _EXIF_GPSSatellites GPS Satellites _EXIF_GPSVersionID GPS Version _EXIF_Artist Artist _EXIF_XPTitle Title (Windows) _EXIF_XPComment Comment (Windows) _EXIF_XPAuthor Author (Windows) _EXIF_XPKeywords Keywords (Windows) _EXIF_XPSubject Subject (Windows) _EXIF_XPRating Rating (Windows) _EXIF_InteropVersion Interoperability Version _EXIF_CameraOwnerName Camera Owner Name _EXIF_BodySerialNumber Body Serial Number _EXIF_LensMake Lens Make _EXIF_LensModel Lens Model _EXIF_LensSerialNumber Lens Serial Number _EXIF_Gamma Gamma _EXIF_SubjectArea Subject Area _EXIF_SubjectLocation Subject Location
See Also -
Example // Output all fields of current image to a memo (same as ) for i := 0 to _EXIF_Tag_Count - 1 do memo1.Lines.Add( ImageEnView1.IO.Params.EXIF_FieldDescription[ i ] + ': ' + ImageEnView1.IO.Params.EXIF_AsStr[ i ] ); !!} function TIOParamsHelper.GetEXIF_FieldDescription(Index: Integer): string; begin Result := ExifTags[ Index ].Desc; end; {!! TIOParamsHelper.EXIF_CanWriteEXIFData Declaration property EXIF_CanWriteEXIFData : Boolean; (read-only) Description Returns true if the current image is of a type that supports EXIF writing, i.e. TIFF or JPEG Note: This is only based on the current format. Naturally you could add EXIF data to an image that was loaded as a Bitmap and then save it to JPEG. !!} function TIOParamsHelper.GetEXIF_CanWriteEXIFData : Boolean; begin Result := FileType in [ioJPEG, ioTIFF]; end; procedure TIOParamsHelper.SetEXIF_Camera_Str(const value: AnsiString); begin // EXIF_Make and EXIF_Model combined if GetEXIF_Camera_Str <> Value then begin EXIF_Make := AnsiString( GetTextBeforeChar( String( Value ), ' ', False )); EXIF_Model := AnsiString( GetTextAfterChar( String( Value ), ' ', True )); end; end; procedure TIOParamsHelper.SetEXIF_XResolution_Str(value: AnsiString); begin // Display/Print resolution of image. Default value is 1/72inch, but it has no mean because personal computer doesn't use this value to display/print out. Value := AnsiString( StripSuffix( String( value ), ' ' + s_Inch )); Value := AnsiString( StripSuffix( String( value ), ' ' + s_CM )); EXIF_XResolution := FractionToDouble( String( value )); end; procedure TIOParamsHelper.SetEXIF_YResolution_Str(value: AnsiString); begin // Display/Print resolution of image. Default value is 1/72inch, but it has no mean because personal computer doesn't use this value to display/print out. Value := AnsiString( StripSuffix( String( value ), ' ' + s_Inch )); Value := AnsiString( StripSuffix( String( value ), ' ' + s_CM )); EXIF_YResolution := FractionToDouble( String( value )); end; procedure TIOParamsHelper.SetEXIF_ExposureTime_Str(value: string); begin // Exposure time (reciprocal of shutter speed). Unit is seconds Value := StripSuffix(value, ' ' + s_Seconds); Value := StripSuffix(value, ' ' + s_Second); if pos('1/', value) > 0 then EXIF_ExposureTime := 1 / FractionToDouble(value) else EXIF_ExposureTime := StrToInt(value); end; procedure TIOParamsHelper.SetEXIF_FNumber_Str(value: string); begin // The actual F-number(F-stop) of lens when the image was taken if uppercase(value)[1] = 'F' then delete(value, 1, 1); EXIF_FNumber := StrToFloat(value); end; procedure TIOParamsHelper.SetEXIF_ShutterSpeedValue_Str(const value: string); begin // Shutter speed by APEX value. To convert this value to ordinary 'Shutter Speed'; calculate this value's power of 2, then reciprocal. For example, if the ShutterSpeedValue is '4', shutter speed is 1/(24)=1/16 second EXIF_ShutterSpeedValue := StrToApex(2, value, '1/'); end; procedure TIOParamsHelper.SetEXIF_ApertureValue_Str(const value: string); begin // The actual aperture value of lens when the image was taken. Unit is APEX. To convert this value to // ordinary F-number (F-stop), calculate this value's power of root 2 (=1.4142). For example, if the // ApertureValue is '5', F-number is 1.41425 = F5.6. EXIF_ApertureValue := StrToApex(Sqrt(2), value, 'F'); end; procedure TIOParamsHelper.SetEXIF_MaxApertureValue_Str(const value: string); begin // Maximum aperture value of lens. You can convert to F-number by calculating power of root 2 (same process of ApertureValue) EXIF_MaxApertureValue := StrToApex(Sqrt(2), value, 'F'); end; // exif data specified by the field index with the value in the specified string procedure TIOParamsHelper.SetEXIF_AsStr(Index: Integer; value : string); begin value := Trim(value); try case Index of _EXIF_UserComment: EXIF_UserComment := value; _EXIF_ImageDescription: EXIF_ImageDescription := AnsiString( value ); _EXIF_CameraMake : EXIF_Make := AnsiString( Value ); _EXIF_CameraModel : EXIF_Model := AnsiString( Value ); { Unit of XResolution/YResolution: 1 means no-unit 2 means inch 3 means centimeter Default value is 2 (inch) } _EXIF_XResolution: begin if pos(uppercase(s_Inch), uppercase(value)) > 0 then EXIF_ResolutionUnit := 2 else if pos(uppercase(s_CM), uppercase(value)) > 0 then EXIF_ResolutionUnit := 3; EXIF_XResolution_Str := AnsiString( value ); end; { Unit of XResolution/YResolution: 1 means no-unit 2 means inch 3 means centimeter Default value is 2 (inch) } _EXIF_YResolution: begin if pos(uppercase(s_Inch), uppercase(value)) > 0 then EXIF_ResolutionUnit := 2 else if pos(uppercase(s_CM), uppercase(value)) > 0 then EXIF_ResolutionUnit := 3; Value := StripSuffix(value, s_Inch); Value := StripSuffix(value, s_CM); EXIF_YResolution_Str := AnsiString( value ); end; _EXIF_DateTime: EXIF_DateTime2 := StrToDateTime(value); _EXIF_DateTimeOriginal: EXIF_DateTimeOriginal2 := StrToDateTime(value); _EXIF_DateTimeDigitized: EXIF_DateTimeDigitized2 := StrToDateTime(value); _EXIF_Copyright: EXIF_Copyright := AnsiString( value ); // The orientation of the camera relative to the scene, when the image was captured _EXIF_Orientation: begin if SameText(value, s_EXIFOrientation1) then EXIF_Orientation := 1 else if SameText(value, s_EXIFOrientation2) then EXIF_Orientation := 2 else if SameText(value, s_EXIFOrientation3) then EXIF_Orientation := 3 else if SameText(value, s_EXIFOrientation4) then EXIF_Orientation := 4 else if SameText(value, s_EXIFOrientation5) then EXIF_Orientation := 5 else if SameText(value, s_EXIFOrientation6) then EXIF_Orientation := 6 else if SameText(value, s_EXIFOrientation7) then EXIF_Orientation := 7 else if SameText(value, s_EXIFOrientation8) then EXIF_Orientation := 8; end; _EXIF_ExposureTime: EXIF_ExposureTime_Str := Value; _EXIF_FNumber: EXIF_FNumber_Str := value; { Exposure program that the camera used when image was taken: 1 means manual control 2 program normal 3 aperture priority 4 shutter priority 5 program creative (slow program) 6 program action(high-speed program) 7 portrait mode 8 landscape mode. } _EXIF_ExposureProgram: begin if SameText(value, s_ManualControl) then EXIF_ExposureProgram := 1 else if SameText(value, s_ProgramNormal) then EXIF_ExposureProgram := 2 else if SameText(value, s_AperturePriority) then EXIF_ExposureProgram := 3 else if SameText(value, s_ShutterPriority) then EXIF_ExposureProgram := 4 else if SameText(value, s_CreativeProgram) then EXIF_ExposureProgram := 5 else if SameText(value, s_ActionProgram) then EXIF_ExposureProgram := 6 else if SameText(value, s_Portraitmode) then EXIF_ExposureProgram := 7 else if SameText(value, s_LandscapeMode) then EXIF_ExposureProgram := 8; end; // EXIF_ISOSpeedRatings: CCD sensitivity equivalent to Ag-Hr film speedrate. _EXIF_ISOSpeedRatings: EXIF_ISOSpeedRatings[0] := StrToInt(value); _EXIF_ShutterSpeedValue: EXIF_ShutterSpeedValue_Str := value; _EXIF_ApertureValue: EXIF_ApertureValue_Str := value; { Brightness of taken subject, unit is APEX. To calculate Exposure(Ev) from BrigtnessValue(Bv), you must add SensitivityValue(Sv): Ev=Bv+Sv Sv=log2(ISOSpeedRating/3.125) ISO100 : Sv=5, ISO200 : Sv=6, ISO400 : Sv=7, ISO125 : Sv=5.32. } _EXIF_BrightnessValue: if Value <> '' then EXIF_BrightnessValue := StrToFloat(value); _EXIF_ExposureBiasValue: EXIF_ExposureBiasValue := StrToFloat(value); _EXIF_MaxApertureValue: EXIF_MaxApertureValue_Str := value; // Distance to focus point, unit is meter. _EXIF_SubjectDistance: begin value := StripSuffix(value, ' m'); EXIF_SubjectDistance := StrToFloat(value); end; { Exposure metering method: 0 means unknown 1 average 2 center weighted average 3 spot 4 multi-spot 5 multi-segment 6 partial 255 other. } _EXIF_MeteringMode: begin if SameText(value, s_average) then EXIF_MeteringMode := 1 else if SameText(value, s_CenterWeightedAverage) then EXIF_MeteringMode := 2 else if SameText(value, s_Spot) then EXIF_MeteringMode := 3 else if SameText(value, s_MultiSpot) then EXIF_MeteringMode := 4 else if SameText(value, s_MultiSegment) then EXIF_MeteringMode := 5 else if SameText(value, s_partial) then EXIF_MeteringMode := 6; end; { Light source, actually this means white balance setting: 0 means unknown 1 daylight 2 fluorescent 3 tungsten 10 flash 17 standard light A 18 standard light B 19 standard light C 20 D55 21 D65 22 D75 255 other. } _EXIF_LightSource: begin if SameText(value, s_daylight) then EXIF_LightSource := 1 else if SameText(value, s_fluorescent) then EXIF_LightSource := 2 else if SameText(value, s_tungsten) then EXIF_LightSource := 3 else if SameText(value, s_flash) then EXIF_LightSource := 10 else if SameText(value, s_standardLightA) then EXIF_LightSource := 17 else if SameText(value, s_standardLightB) then EXIF_LightSource := 18 else if SameText(value, s_standardLightC) then EXIF_LightSource := 19 else if SameText(value, s_D55) then EXIF_LightSource := 20 else if SameText(value, s_D65) then EXIF_LightSource := 21 else if SameText(value, s_D75) then EXIF_LightSource := 22; end; { EXIF_Flash: 0 means flash did not fire 1 flash fired 5 flash fired but strobe return light not detected 7 flash fired and strobe return light detected } _EXIF_Flash: begin if SameText(value, s_FlashDidNotFire) then EXIF_Flash := 0 else if SameText(value, s_flashFired) then EXIF_Flash := 1 else if SameText(value, s_flashFiredNoStrobeLight) then EXIF_Flash := 5 else if SameText(value, s_flashFiredStrobeLight) then EXIF_Flash := 7; end; // Focal length of lens used to take image. Unit is millimeter. _EXIF_FocalLength: begin value := StripSuffix(value, ' mm'); EXIF_FocalLength := StrToFloat(value); end; _EXIF_FlashPixVersion: EXIF_FlashPixVersion := AnsiString( Value ); // Defines Color Space: DCF image must use sRGB color space so value is always '1'. If the picture uses the other color space, value is '65535' : Uncalibrated. _EXIF_ColorSpace: begin if SameText(value, s_RGB) then EXIF_ColorSpace := 1 else if SameText(value, s_Uncalibrated) then EXIF_ColorSpace := 65535; end; _EXIF_ExifImageWidth : EXIF_ExifImageWidth := StrToInt(value); _EXIF_ExifImageHeight: EXIF_ExifImageHeight := StrToInt(value); // If this digicam can record audio data with image, shows name of audio data. _EXIF_RelatedSoundFile: EXIF_RelatedSoundFile := AnsiString( value ); { Unit of FocalPlaneXResoluton/FocalPlaneYResolution: 1 means no-unit 2 inch 3 centimeter. Note : Some of Fujifilm's digicam(e.g.FX2700, FX2900, Finepix4700Z/40i etc) uses value '3' so it must be 'centimeter', but it seems that they use a '8.3mm?'(1/3in.?) to their ResolutionUnit. Fuji's BUG? Finepix4900Z has been changed to use value '2' but it doesn't match to actual value also. } _EXIF_FocalPlaneXResolution: begin if pos(uppercase(s_Inch), uppercase(value)) > 0 then EXIF_FocalPlaneResolutionUnit := 2 else if pos(uppercase(s_CM), uppercase(value)) > 0 then EXIF_FocalPlaneResolutionUnit := 3; Value := StripSuffix(value, s_PerInch); Value := StripSuffix(value, s_PerCM); EXIF_FocalPlaneXResolution := StrToFloat(value); end; _EXIF_FocalPlaneYResolution: begin if pos(uppercase(s_Inch), uppercase(value)) > 0 then EXIF_FocalPlaneResolutionUnit := 2 else if pos(uppercase(s_CM), uppercase(value)) > 0 then EXIF_FocalPlaneResolutionUnit := 3; Value := StripSuffix(value, s_PerInch); Value := StripSuffix(value, s_PerCM); EXIF_FocalPlaneYResolution := StrToFloat(value); end; // EXIF_ExposureIndex: Same as ISOSpeedRatings(0x8827) but data type is unsigned rational. Only Kodak's digicam uses this tag instead of ISOSpeedRating. _EXIF_ExposureIndex: EXIF_ExposureIndex := StrToFloat(value); { When image format is YCbCr and uses 'Subsampling' (cropping of chroma data, all the digicam do that), defines the chroma sample point of subsampling pixel array. 1 means the center of pixel array 2 means the datum point. } _EXIF_YCbCrPositioning: begin if SameText(value, s_Centered) then EXIF_YcbCrPositioning := 1 else if SameText(value, s_DataPoint) then EXIF_YcbCrPositioning := 2; end; _EXIF_GPSSatellites: EXIF_GPSSatellites := AnsiString( Value ); _EXIF_GPSVersionID: EXIF_GPSVersionID := AnsiString( Value ); _EXIF_Artist: EXIF_Artist := AnsiString( Value ); _EXIF_XPTitle: EXIF_XPTitle := Value; _EXIF_XPComment: EXIF_XPComment := Value; _EXIF_XPAuthor: EXIF_XPAuthor := Value; _EXIF_XPKeywords: EXIF_XPKeywords := Value; _EXIF_XPSubject: EXIF_XPSubject := Value; _EXIF_XPRating: EXIF_XPRating := StrToIntDef(Value, -1); _EXIF_InteropVersion : EXIF_InteropVersion := AnsiString(Value); _EXIF_CameraOwnerName : EXIF_CameraOwnerName := AnsiString( Value ); _EXIF_BodySerialNumber : EXIF_BodySerialNumber := AnsiString( Value ); _EXIF_LensMake : EXIF_LensMake := AnsiString( Value ); _EXIF_LensModel : EXIF_LensModel := AnsiString( Value ); _EXIF_LensSerialNumber : EXIF_LensSerialNumber := AnsiString( Value ); _EXIF_Gamma : EXIF_Gamma := StrToFloat( Value ); _EXIF_SubjectLocation : EXIF_SubjectLocation_Str := Value; { TO-DO: ADD WRITE SUPPORT : _EXIF_SensingMethod _EXIF_FileSource _EXIF_SceneType _EXIF_ExposureMode _EXIF_WhiteBalance _EXIF_DigitalZoomRatio _EXIF_FocalLengthIn35mmFilm _EXIF_SceneCaptureType _EXIF_GainControl _EXIF_Contrast _EXIF_Saturation _EXIF_Sharpness _EXIF_SubjectDistanceRange _EXIF_GPSLatitude _EXIF_GPSLongitude _EXIF_GPSAltitude _EXIF_GPSImageDirection _EXIF_GPSTrack _EXIF_GPSSpeed _EXIF_GPSDateAndTime _EXIF_SubjectArea } end; except // ERROR end; end; {!! TIOParamsHelper.EXIF_WriteToStrings Declaration function TIOParamsHelper.EXIF_WriteToStrings(Dest : TStrings) : Boolean; Description Fills a TStrings object with the EXIF properties of the current image in the format: Description: Value Result is true if the image has any EXIF fields. Example // Output the EXIF properties of the current image to a TMemo ImageEnView1.IO.Params.EXIF_WriteToStrings( memo1.Lines ); !!} function TIOParamsHelper.EXIF_WriteToStrings(Dest : TStrings) : Boolean; begin Result := _ReadFromEXIF_Params(Dest, Self); end; {!! TIOParamsHelper.IPTC_WriteToStrings Declaration function TIOParamsHelper.IPTC_WriteToStrings(Dest : TStrings) : Boolean; Description Fills a TStrings object with the IPTC properties of the current image in the format: Description: Value Result is true if the image has any IPTC fields. Example // Output the IPTC properties of the current image to a TMemo ImageEnView1.IO.Params.IPTC_WriteToStrings( memo1.Lines ); !!} function TIOParamsHelper.IPTC_WriteToStrings(Dest : TStrings) : Boolean; begin Result := _ReadFromIPTC_Params(Dest, Self); end; {!! TIOParamsHelper.DICOM_WriteToStrings Declaration function TIOParamsHelper.DICOM_WriteToStrings(Dest : TStrings; TagInclude: ) : Boolean; Description Fills a TStrings object with the Dicom properties of the current image in the format: Description: Value TagInclude allows you to filter the types of tags returned. Result is true if the image has any Dicom fields. Examples // Output the Dicom properties of the current image to a TMemo (all types) ImageEnView1.IO.DICOM_WriteToStrings( memo1.Lines, [ diProprietary, diDeprecated, diChildTags, diUnknown ] ); // Export the dicom list of the current image to a file (exclude deprecated and unknown tags) aStringList := TStringList.create; ImageEnView1.IO.Params.DICOM_WriteToStrings( aStringList, [ diProprietary, diChildTags ] ); aStringList.SaveToFile('D:\DicomList.txt'); aStringList.Free; !!} {$ifdef IEINCLUDEDICOM} function TIOParamsHelper.DICOM_WriteToStrings(Dest : TStrings; TagInclude: TIEDicomInclude) : Boolean; begin Result := _ReadFromDicom_Params(Dest, Self, TagInclude); end; {$endif} {!! TIOParamsHelper.XMP_WriteToStrings Declaration function TIOParamsHelper.XMP_WriteToStrings(Dest : TStrings) : Boolean; Description Fills a TStrings object with the XMP properties of the current image in the format: Description: Value Result is true if the image has any XMP fields. Note: Only common XMP fields are added. Unknown XMP tags are skipped. Examples // Output the XMP properties of the current image to a TMemo ImageEnView1.IO.Params.XMP_WriteToStrings( memo1.Lines ); // Export the XMP list of the current image to a file (exclude deprecated and unknown tags) aStringList := TStringList.create; ImageEnView1.IO.Params.XMP_WriteToStrings( aStringList ); aStringList.SaveToFile('D:\XMPList.txt'); aStringList.Free; !!} function TIOParamsHelper.XMP_WriteToStrings(Dest : TStrings) : Boolean; begin Result := _ReadFromXMP_Params(Dest, Self); end; {!! TIOParamsHelper.XMP_AsStr Declaration property XMP_AsStr [Field : Integer]: String; (read-only) Description A shortcut function that calls: Result := Dict.GetDictionary( 'XMP' ).GetString( Field, True ) Any XMP field, such as dc:subject, can be specified. Result is '' if the field is not found. Consts are available common XMP fields Examples // Return the photo description sDescription := ImageEnView1.IO.Params.XMP_AsStr[ XMP_DC_Description ]; // Which is the same as calling (except that exceptions are raised on failure) sDescription := ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'dc:Description', True ); // Return the creator or author of the asset sCreator := ImageEnView1.IO.Params.XMP_AsStr[ XMP_DC_Creator ]; // Return location information about the content being shown in the image sLocation := ImageEnView1.IO.Params.XMP_AsStr[ XMP_Photoshop_City ] + ', ' + ImageEnView1.IO.Params.XMP_AsStr[ XMP_Photoshop_State ] + ', ' + ImageEnView1.IO.Params.XMP_AsStr[ XMP_Photoshop_Country ]; // Return the document title sTitle := ImageEnView1.IO.Params.XMP_AsStr[ XMP_DC_Title ]; // Return the document keywords sKeywords := ImageEnView1.IO.Params.XMP_AsStr[ XMP_DC_Subject ]; // Return the document copyright information sCopyright := ImageEnView1.IO.Params.XMP_AsStr[ XMP_DC_Rights ]; // Return the Photoshop Headline sHeadline := ImageEnView1.IO.Params.XMP_AsStr[ XMP_Photoshop_Headline ]; // Return the Windows Rating (0 to 5) sRating := ImageEnView1.IO.Params.XMP_AsStr[ XMP_Rating ]; // Return the creation date (XMP date strings are formatted the same EXIF date strings) dtCreateDate := EXIFDateToDateTime( ImageEnView1.IO.Params.XMP_AsStr[ XMP_CreateDate ] ); See Also - - - - !!} function TIOParamsHelper.GetXMP_AsStr(const Field: String): string; begin try Result := Dict.GetDictionary( 'XMP' ).GetString( Field, True ); except Result := ''; end; end; {!! TIOParamsHelper.XMP_AsInt Declaration property XMP_AsInt [Field : Integer]: Integer; (read-only) Description A shortcut function that calls: Result := Dict.GetDictionary( 'XMP' ).GetInteger( Field, True ) Any XMP field, such as photoshop:ColorMode, can be specified. Result is 0 if the field is not found or not an integer field. Consts are available common XMP fields Examples // Return the Photoshop Color Mode from the XMP metadata iColorMode := ImageEnView1.IO.Params.XMP_AsInt[ 'photoshop:ColorMode' ]; See Also - - - - !!} function TIOParamsHelper.GetXMP_AsInt(const Field: String): Integer; begin try Result := Dict.GetDictionary( 'XMP' ).GetInteger( Field, True ); except Result := 0; end; end; {!! TIOParamsHelper.XMP_AsDateTime Declaration property XMP_AsDateTime [Field : Integer]: TDateTime; (read-only) Description A shortcut function that calls: Result := Dict.GetDictionary( 'XMP' ).GetString( Field, True ) And then uses to convert the value to a TDateTime (as XMP date strings are the same as EXIF). Any XMP field, such as xmp:CreateDate, can be specified. Result is 0 if the field is not found or not a valid date field. Consts are available common XMP fields Examples // Return the creation date dtCreateDate := ImageEnView1.IO.Params.XMP_AsDateTime[ XMP_CreateDate ]; See Also - - - - !!} function TIOParamsHelper.GetXMP_AsDateTime(const Field: String): TDateTime; begin try Result := EXIFDateToDateTime( Dict.GetDictionary( 'XMP' ).GetString( Field, True )); except Result := 0; end; end; {!! TIOParamsHelper.DICOM_FindTag Declaration function TIOParamsHelper.DICOM_FindTag(Group: Word; Element: Word): ; Description Parses all the tags of to find the first tag matching the specified group and element (even if it is a child tag). Examples // Find the "Pixel Data" tag aTag := ImageEnMView1.MIO.Params[0].DICOM_FindTag( $7FE0, $0010 ); if assigned( aTag ) then begin aMemStream := TMemoryStream.Create(); aMemStream.Write( atag^.Data, atag^.DataLen ); aMemStream.Position := 0; // Do something with aMemStream aMemStream.Free; end; See Also - - - !!} {$ifdef IEINCLUDEDICOM} function TIOParamsHelper.DICOM_FindTag(Group: Word; Element: Word): PIEDicomTag; {} procedure _ParseTags(tags: TIEDicomTags); var i, j: integer; tag: PIEDicomTag; begin for i := 0 to tags.Count - 1 do begin // GET DATA tag := tags.GetTag(i); if ( tag^.Group = Group ) and ( tag^.Element = Element ) then begin Result := tag; Exit; end; // PARSE ANY CHILDREN if assigned( tag.Children ) then begin // tag.Children is a TObjectList object, where each item is a TIEDicomTags object to pass recursively into ShowRawTags for j := 0 to tag.Children.Count - 1 do begin _ParseTags( tag.Children[j] as TIEDicomTags ); // Found tag? if Result <> nil then Exit; end; end; end; end; {} begin result := nil; _ParseTags( DICOM_Tags ); end; {$endif} {!! TIOParamsHelper.IPTC_HasIPTCData Declaration function IPTC_HasIPTCData : Boolean; (read-only) Description Returns true if there are any IPTC tags in the current image. This is a shortcut function that calls: Result := IPTC_Info.Count > 0; Examples btnShowIPTC.Enabled := ImageEnView1.IO.Params.IPTC_HasIPTCData; !!} function TIOParamsHelper.IPTC_HasIPTCData : Boolean; begin Result := IPTC_Info.Count > 0; end; {!! TIOParamsHelper.DICOM_HasDicomTags Declaration function DICOM_HasDicomTags : Boolean; (read-only) Description Returns true if there are any Dicom tags in the current image. This is a shortcut function that calls: Result := DICOM_Info.Count > 0; Examples btnShowDicom.Enabled := ImageEnView1.IO.Params.DICOM_HasDicomTags; !!} function TIOParamsHelper.DICOM_HasDicomTags : Boolean; begin {$ifdef IEINCLUDEDICOM} Result := DICOM_Tags.Count > 0; {$ELSE} Result := False; {$endif} end; {!! TIOParamsHelper.XMP_HasXMPData Declaration function XMP_HasXMPData : Boolean; (read-only) Description Returns true if there are any XMP tags in the current image. This is a shortcut function that calls: Result := XMP_Info <> ''; Examples btnShowXMP.Enabled := ImageEnView1.IO.Params.XMP_HasXMPData; !!} function TIOParamsHelper.XMP_HasXMPData : Boolean; begin Result := XMP_Info <> ''; end; {$endif} // GENERAL EXIF METHODS {!! ExifCompatibleFile Declaration function ExifCompatibleFile(const sFilename: string): boolean; Description Returns true if the specified filename has an extension of a file type that supports EXIF reading (JPEG, TIFF or Camera Raw). Examples // Enable button if the selected file may contain exif fields btnShowExif.Enabled := ExifCompatibleFile( MyFileListBox.Filename ); !!} // return true if the specified filename can support writing of EXIF Fields function ExifCompatibleFile(const sFilename: string): boolean; begin Result := IEFilenameInExtensions(sFilename, EXIF_COMPATIBLE_EXTENSIONS); end; {!! ReadExifCameraFieldsFromFile Declaration function ReadExifCameraFieldsFromFile(const sFilename : string; out sCameraModel : string; out sExposureTime : string; out sFlashMode : string ) : boolean; Description Retrieves camera related EXIF data from a file. The following properties are returned: - - - Returns false if sFilename is not a file type that supports EXIF. Examples // Show Camera data for selected file if ReadExifCameraFieldsFromFile( MyFileListBox.Filename, sCameraModel, sExposureTime, sFlashMode ) then begin lblCameraModel .Caption := sCameraModel; lblExposureTime.Caption := sExposureTime; lblFlashMode .Caption := sFlashMode; end else begin lblCameraModel .Caption := ''; lblExposureTime.Caption := ''; lblFlashMode .Caption := ''; end; !!} // Formerly GetUsefulExifFields {$IFDEF Delphi2005orNewer} function ReadExifCameraFieldsFromFile(const sFilename : string; out sCameraModel : string; out sExposureTime : string; out sFlashMode : string ) : boolean; var aImageEnIO: TImageEnIO; begin result := false; if ExifCompatibleFile(sFilename) then try aImageEnIO := TImageEnIO.create(nil); try aImageEnIO.ParamsFromFile(sFilename); if aImageEnIO.Params.EXIF_HasEXIFData then begin sCameraModel := String( aImageEnIO.Params.EXIF_Camera_Str ); sExposureTime := String( aImageEnIO.Params.EXIF_ExposureTime_Str ); sFlashMode := FlashModeToString(aImageEnIO.Params.EXIF_Flash); result := (sCameraModel <> '') or (sExposureTime <> ''); end; finally aImageEnIO.Free; end; except // ERROR end; end; {$ENDIF} function _ReadExifGPSFieldsFromFile(const sFilename : string; out GPSLatitude: Double; out GPSLongitude: Double; out sGPSLatitude: string; out sGPSLongitude: string ) : boolean; var aImageEnIO: TImageEnIO; begin result := false; GPSLatitude := 0; GPSLongitude := 0; sGPSLatitude := ''; sGPSLongitude := ''; if ExifCompatibleFile(sFilename) then try aImageEnIO := TImageEnIO.create(nil); try aImageEnIO.ParamsFromFile(sFilename); if aImageEnIO.Params.EXIF_HasEXIFData then begin GPSLatitude := aImageEnIO.Params.EXIF_GPSLatitude; GPSLongitude := aImageEnIO.Params.EXIF_GPSLongitude; Result := (GPSLatitude <> 0) or (GPSLongitude <> 0); if Result then begin sGPSLatitude := aImageEnIO.Params.EXIF_GPSLatitude_Str; sGPSLongitude := aImageEnIO.Params.EXIF_GPSLongitude_Str; end; end; finally aImageEnIO.Free; end; except // ERROR end; end; {!! ReadExifGPSFieldsFromFile Declaration function ReadExifGPSFieldsFromFile(const sFilename : string; out GPSLatitude: Double; out GPSLongitude: Double ) : boolean; overload; function ReadExifGPSFieldsFromFile(const sFilename : string; out sGPSLatitude: string; out sGPSLongitude: string ) : boolean; overload; Description Retrieves GPS location data from a file. The following properties are returned: - - Returns false if sFilename does not contain any GPS data. Examples // Show location on map for selected file if ReadExifGPSFieldsFromFile( MyFileListBox.Filename, GPSLatitude, GPSLongitude ) then Map.NavigateTo( GPSLatitude, GPSLongitude ); // Show GPS location for selected file if ReadExifGPSFieldsFromFile( MyFileListBox.Filename, sGPSLatitude, sGPSLongitude ) then begin lblGPSLatitude .Caption := sGPSLatitude; lblGPSLongitude.Caption := sGPSLongitude; end else begin lblGPSLatitude .Caption := ''; lblGPSLongitude.Caption := ''; end; !!} // Formerly ExifGPSData function ReadExifGPSFieldsFromFile(const sFilename : string; out GPSLatitude: Double; out GPSLongitude: Double ) : boolean; var sGPSLatitude: string; sGPSLongitude: string; begin Result := _ReadExifGPSFieldsFromFile( sFilename, GPSLatitude, GPSLongitude, sGPSLatitude, sGPSLongitude); end; function ReadExifGPSFieldsFromFile(const sFilename : string; out sGPSLatitude: string; out sGPSLongitude: string ) : boolean; var GPSLatitude: Double; GPSLongitude: Double; begin Result := _ReadExifGPSFieldsFromFile( sFilename, GPSLatitude, GPSLongitude, sGPSLatitude, sGPSLongitude); end; // EXIF TAG ROUTINES function ExifFieldToTag(const sExifField : string) : string; begin Result := Exif_Tag_Prefix + StringReplace(sExifField, ' ', '-', [rfReplaceAll]) + Exif_Tag_Suffix; end; {!! ContainsExifTag Declaration function ContainsExifTag(const Text: string): Boolean; Description Returns true if Text contains an exif tag, such as %EXIF-User-Comment% Exif Tags Exif tags allow creation of generic text blocks where the data within the text is replaced with EXIF data (in a similar way to a mail merge). For example, a user may insert the exif tag, %EXIF-User-Comment%, you can then call to replace the tag with the actually value of the field. BEFORE: Description: %EXIF-User-Comment% Camera: %EXIF-Camera-Make% Shutter Speed: %EXIF-Shutter-Speed% AFTER (Example): Description: Eiffel Tower Camera: Nikon Shutter Speed: 1/200 second Examples // Replace the exif tags in memo with the actual values of the current image if ContainsExifTag( Memo1.Text ) then Memo1.Text := ReplaceExifTags( Memo1.Text, ImageEnView1.IO.Params ); !!} function ContainsExifTag(const Text: string): Boolean; begin Result := Pos(uppercase(Exif_Tag_Prefix), uppercase(Text)) > 0; end; {!! GetExifTagList Declaration procedure GetExifTagList(ssDest: TStrings); Description Fill ssDest with all available exif tags, such as %EXIF-User-Comment% Exif Tags Exif tags allow creation of generic text blocks where the data within the text is replaced with EXIF data (in a similar way to a mail merge). For example, a user may insert the exif tag, %EXIF-User-Comment%, you can then call to replace the tag with the actually value of the field. BEFORE: Description: %EXIF-User-Comment% Camera: %EXIF-Camera-Make% Shutter Speed: %EXIF-Shutter-Speed% AFTER (Example): Description: Eiffel Tower Camera: Nikon Shutter Speed: 1/200 second Examples // Fill our tag selector with all available Exif tags GetExifTagList( lbxExifTagList.Items ); !!} procedure GetExifTagList(ssDest: TStrings); var i: integer; begin // fill the strings with the EXIF tag names for i := Low(ExifTags) to High(ExifTags) do ssDest.Add( ExifFieldToTag(ExifTags[ i ].Desc) ); end; {$IFDEF Delphi2005orNewer} function _ReplaceExifTags(const Text: string; EXIFSource : TIOParams; bValid, bSample : Boolean): string; var i: Integer; sValue: string; begin // NOTE: May be slow with large text blocks! for i := Low(ExifTags) to high(ExifTags) do begin if bSample then sValue := 'Sample ' + ExifTags[ i ].Desc else if bValid then sValue := EXIFSource.EXIF_AsStr[ i ] else sValue := ''; Result := StringReplace(result, ExifFieldToTag(ExifTags[ i ].Desc), sValue, [rfReplaceAll, rfIgnoreCase]); end; end; {$ENDIF} {!! ReplaceExifTags Declaration function ReplaceExifTags(const Text: string; EXIFSource : TIOParams): string; overload; function ReplaceExifTags(const Text: string; const sEXIFSourceFilename : string): string; overload; Description Replace all Exif tags found in Text with the actual EXIF properties of the current image, or an image loaded from file. Note: Specify sEXIFSourceFilename as Example_File_Only to show example properties to the user (e.g. instead of reading the field from file, it will insert 'Sample User Comment') Exif Tags Exif tags allow creation of generic text blocks where the data within the text is replaced with EXIF data (in a similar way to a mail merge). For example, a user may insert the exif tag, %EXIF-User-Comment%, you can then call to replace the tag with the actually value of the field. BEFORE: Description: %EXIF-User-Comment% Camera: %EXIF-Camera-Make% Shutter Speed: %EXIF-Shutter-Speed% AFTER (Example): Description: Eiffel Tower Camera: Nikon Shutter Speed: 1/200 second Examples // Replace the exif tags in memo with the actual values of the current image if ContainsExifTag( Memo1.Text ) then Memo1.Text := ReplaceExifTags( Memo1.Text, ImageEnView1.IO.Params ); // Show sample output memSample.Text := ReplaceExifTags( 'Camera: %EXIF-Camera-Make%'#13#10'Shutter Speed: %EXIF-Shutter-Speed%', Example_File_Only ); (* Which outputs: Camera: Sample Camera Make Shutter Speed: Sample Shutter Speed *) !!} {$IFDEF Delphi2005orNewer} function ReplaceExifTags(const Text: string; EXIFSource : TIOParams): string; var bValid: Boolean; begin Result := Text; // Anything to do? if ContainsExifTag(Text) then begin bValid := EXIFSource.EXIF_HasEXIFData; Result := _ReplaceExifTags(Text, EXIFSource, bValid, False); end; end; {$ENDIF} {$IFDEF Delphi2005orNewer} function ReplaceExifTags(const Text: string; const sEXIFSourceFilename : string): string; var bValid: Boolean; aImageEnIO: TImageEnIO; bSampleOnly: Boolean; begin Result := Text; // Anything to do? if ContainsExifTag(Text) = False then Exit; bSampleOnly := SameText(sEXIFSourceFilename, Example_File_Only); aImageEnIO := TImageEnIO.create(nil); try aImageEnIO.ParamsFromFile(sEXIFSourceFilename); bValid := False; if EXIFCompatibleFile(sEXIFSourceFilename) then try AImageEnIO.ParamsFromFile(sEXIFSourceFilename); bValid := AImageEnIO.Params.EXIF_HasEXIFData; except // ERROR end; Result := _ReplaceExifTags(Text, AImageEnIO.Params, bValid, bSampleOnly); finally aImageEnIO.Free; end; end; {$ENDIF} // GENERAL IPTC METHODS {!! IPTCCompatibleFile Declaration function IPTCCompatibleFile(const sFilename: string): boolean; Description Returns true if the specified filename has an extension of a file type that supports IPTC (i.e. JPEG or TIFF). Examples // Enable button if the selected file may contain IPTC btnShowIPTC.Enabled := IPTCCompatibleFile( MyFileListBox.Filename ); !!} function IPTCCompatibleFile(const sFilename : string) : boolean; begin result := IEFilenameInExtensions(sFilename, IPTC_COMPATIBLE_EXTENSIONS); end; {!! ReadIPTCDescriptionAndKeywordsFromFile Declaration function ReadIPTCDescriptionAndKeywordsFromFile(const sFilename: string; out sDescription: string; ssKeywords: TStrings = nil) : Boolean; Description Retrieves the description and keywords from the IPTC data of a file. The following records are returned: - PhotoShop_IPTC_Records/IPTC_PS_Caption - PhotoShop_IPTC_Records/IPTC_PS_Keywords Returns false if the file does not contain an IPTC description or keywords. Note: ssKeywords can be nil Example // Show keyword and description of selected file if ReadIPTCCameraFieldsFromFile( MyFileListBox.Filename, sDescription, ssKeywords ) then begin lblDescription .Caption := sDescription; lblKeywords .Caption := ssKeywords.CommaText; end else begin lblDescription .Caption := ''; lblKeywords .Caption := ''; end; !!} function ReadIPTCDescriptionAndKeywordsFromFile(const sFilename: string; out sDescription: string; ssKeywords: TStrings = nil) : Boolean; var aImageEnIO: TImageEnIO; begin result := false; sDescription := ''; if IPTCCompatibleFile(sFilename) then try aImageEnIO := TImageEnIO.create(nil); try aImageEnIO.ParamsFromFile(sFilename); // DESCRIPTION FIELD sDescription := aImageEnIO.Params.ReadIPTCField(PhotoShop_IPTC_Records, IPTC_PS_Caption); if sDescription <> '' then Result := True; // KEYWORD FIELD (ssKeywords can be nil) if assigned(ssKeywords) then begin // get the keywords aImageEnIO.Params.ReadIPTCField(PhotoShop_IPTC_Records, IPTC_PS_Caption, ssKeywords); if ssKeywords.Text <> '' then Result := True; end; finally aImageEnIO.Free; end; except // ERROR end; end; {!! WriteIPTCDescriptionAndKeywordsToFile Declaration procedure WriteIPTCDescriptionAndKeywordsToFile(const sFilename: string; sDescription: string; ssKeywords: TStrings = nil); Description Saves a description and keywords to the IPTC data of a file. The following records are used: - PhotoShop_IPTC_Records/IPTC_PS_Caption - PhotoShop_IPTC_Records/IPTC_PS_Keywords Notes: - Specify the SKIP_DESCRIPTION const to avoid updating the description - Pass ssKeywords as nil to avoid updating the keywords Examples // Save description and keywords to a file WriteIPTCDescriptionAndKeywordsToFile( 'D:\MyImage.jpeg', edtDescription.Text, lbxKeywords.Items ); // Save description to a file WriteIPTCDescriptionAndKeywordsToFile( 'D:\MyImage.jpeg', edtDescription.Text, nil ); // Save keywords to a file WriteIPTCDescriptionAndKeywordsToFile( 'D:\MyImage.jpeg', SKIP_DESCRIPTION, lbxKeywords.Items ); !!} // Formerly WriteIPTCDescriptionAndKeywords procedure WriteIPTCDescriptionAndKeywordsToFile(const sFilename: string; sDescription: string; ssKeywords: TStrings = nil); var aImageEnIO: TImageEnIO; dFileDate : TDateTime; bCanUpdateJPEG: Boolean; begin aImageEnIO := TImageEnIO.create(nil); try if FileExists(sFilename) = False then raise EIEException.create('Cannot find file to update: ' + sFilename); bCanUpdateJPEG := IEFilenameInExtensions(sFilename, '*.jpeg;*.jpg;*.jpe;'); if bCanUpdateJPEG then aImageEnIO.ParamsFromFile(sFilename) else aImageEnIO.LoadFromFile(sFilename); // DESCRIPTION if sDescription <> SKIP_DESCRIPTION then aImageEnIO.Params.WriteIPTCField(PhotoShop_IPTC_Records, IPTC_PS_Caption, sDescription); // KEYWORDS if Assigned(ssKeywords) then aImageEnIO.Params.WriteIPTCField(PhotoShop_IPTC_Records, IPTC_PS_Keywords, ssKeywords); {$WARNINGS OFF} // FileAge is deprecated dFileDate := 0; if Maintain_File_Dates_On_Meta_Write then dFileDate := FileDateToDateTime(FileAge(sFileName)); {$WARNINGS ON} // Can write IPTC data? if (aImageEnIO.Params.FileType in [ioJPEG, ioTIFF]) = False then raise EIEException.create('File format does not support IPTC'); if bCanUpdateJPEG then aImageEnIO.InjectJpegIPTC(sFileName) else aImageEnIO.SaveToFile(sFilename); if Maintain_File_Dates_On_Meta_Write and (dFileDate <> 0) then IEFileSetDate(sFileName, dFileDate); finally aImageEnIO.Free; end; end; // OTHER METHODS {!! DicomCompatibleFile Declaration function DicomCompatibleFile(const sFilename: string): boolean; Description Returns true if the specified filename has a DICOM extension (i.e. *.DICOM, *.DCM, *.DIC or *.V2). Examples // Enable button if the selected file is Dicom format btnShowDicom.Enabled := DicomCompatibleFile( MyFileListBox.Filename ); !!} function DicomCompatibleFile(const sFilename: string): boolean; begin {$ifdef IEINCLUDEDICOM} result := IEFilenameToInternalFileType( sFileName ) = ioDicom; {$ELSE} result := False; {$endif} end; {!! XMPCompatibleFile Declaration function XMPCompatibleFile(const sFilename: string): boolean; Description Returns true if the specified filename has an extension of a file type that supports XMP meta-data (i.e. JPEG, TIFF or PSD). Examples // Enable button if the selected file may contain XMP meta-data btnShowXMP.Enabled := XMPCompatibleFile( MyFileListBox.Filename ); !!} function XMPCompatibleFile(const sFilename: string): boolean; begin result := IEFilenameInExtensions( sFilename, XMP_COMPATIBLE_EXTENSIONS ); end; {!! iexMetaHelpers iexMetaHelpers.pas provides helper functions for working with the EXIF and IPTC meta data in compatible files (e.g. JPEG and TIFF files). It includes an array of all common EXIF fields and provides methods for reading and writing fields by ID, as well as displaying and saving data in a TStringGrid or TListView. Also supports DICOM meta data. Simply add iexMetaHelpers to your uses clause to access the new methods IOPARAMS EXIF HELPER FUNCTIONS Provide string formatted access (human-readable) to some EXIF properties (that are complex to interpret): IOPARAMS XMP HELPER FUNCTIONS Helper functions for XMP meta-data: IOPARAMS METADATA OUTPUT FUNCTIONS Helper functions to output EXIF, IPTC, Dicom and XMP fields to a TStrings Object: OTHER IOPARAMS HELPER FUNCTIONS General Helper functions for working with meta-data: STRINGGRID HELPER FUNCTIONS Helper functions to output EXIF, IPTC and Dicom fields to a TStringGrid: LISTVIEW HELPER FUNCTIONS Helper functions to output EXIF and IPTC fields to a TListView: GENERAL EXIF METHODS GENERAL IPTC METHODS EXIF TAG METHODS OTHER METHODS * Note: Delphi/C++ 2005 or newer is required to use helper classes !!} end.