2081 lines
78 KiB
Plaintext
2081 lines
78 KiB
Plaintext
{------------------------------------------------------------------------------}
|
|
{ }
|
|
{ Helper functions for working with EXIF fields with ImageEn }
|
|
{ }
|
|
{ Nigel Cross }
|
|
{ Xequte Software }
|
|
{ nigel@xequte.com }
|
|
{ http://www.xequte.com }
|
|
{ }
|
|
{ © Xequte Software 2009-2014 }
|
|
{ }
|
|
{ Modified 16/4/13 }
|
|
{ TListView support added by William Miller, Adirondack Software & Graphics }
|
|
{------------------------------------------------------------------------------}
|
|
|
|
(*
|
|
Copyright (c) 1998-2014 by Carlotta Calandra. All rights reserved.
|
|
Copyright (c) 2011-2014 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.
|
|
*)
|
|
|
|
(*
|
|
File version 1007
|
|
*)
|
|
|
|
// 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 iexEXIFRoutines;
|
|
|
|
{$I ie.inc}
|
|
|
|
interface
|
|
|
|
{$ifdef IEHASRECORDASCLASSES}
|
|
|
|
{$ifdef IEHASUNICODEWARNS}
|
|
{$WARN IMPLICIT_STRING_CAST OFF}
|
|
{$WARN IMPLICIT_STRING_CAST_LOSS OFF}
|
|
{$endif}
|
|
|
|
|
|
uses
|
|
{$IFDEF USE_STRINGGRIDS}
|
|
grids,
|
|
{$ENDIF}
|
|
{$IFDEF USE_LISTVIEW}
|
|
ComCtrls,
|
|
{$ENDIF}
|
|
ImageEnIO, dialogs, Sysutils, math, Graphics, Classes;
|
|
|
|
// returns true if the specified filename can support writing of EXIF Fields
|
|
function EXIFCompatibleFile(const sFilename: string): boolean;
|
|
|
|
{$IFDEF USE_STRINGGRIDS}
|
|
// sets up a string grid for EXIF editing/display, by adding all property names
|
|
// also adds a header row if FixedRow >= 1
|
|
// if sFilename is specified then it sets the read/write ability of the grid based on whether the format supports EXIF writign (RAW does not)
|
|
procedure InitializeEXIFStringGrid(AStringGrid: TStringGrid; sFilename: string = '');
|
|
{$ENDIF}
|
|
|
|
{$IFDEF USE_LISTVIEW}
|
|
// sets up a listview for EXIF editing/display, by adding all property names
|
|
// also adds a header row if FixedRow >= 1
|
|
// if sFilename is specified then it sets the read/write ability of the grid based on whether the format supports EXIF writign (RAW does not)
|
|
procedure InitializeEXIFListView(AListview: TListView; sFilename: string = '');
|
|
{$ENDIF}
|
|
|
|
{$IFDEF USE_STRINGGRIDS}
|
|
// loads the EXIF fields for the specified file into the String Grid
|
|
// if bLoadParams=false then it is assumed that AnImageEnIO has already loaded the file
|
|
// result is whether the file has any fields specified
|
|
function LoadEXIFFields(AStringGrid: TStringGrid;
|
|
sFilename: string;
|
|
AnImageEnIO: TImageEnIO;
|
|
bLoadParams: boolean = true): boolean; overload;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF USE_LISTVIEW}
|
|
// loads the EXIF fields for the specified file into the ListView
|
|
// if bLoadParams=false then it is assumed that AnImageEnIO has already loaded the file
|
|
// result is whether the file has any fields specified
|
|
function LoadEXIFFields(AListView: TListView;
|
|
sFilename: string;
|
|
AImageEnIO: TImageEnIO;
|
|
bLoadParams: boolean = true): boolean; overload;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF USE_STRINGGRIDS}
|
|
// Clears the EXIF fields from the specified ImageEnIO object and in the specified stringgrid
|
|
procedure ClearEXIFFields(AStringGrid: TStringGrid; AnImageEnIO: TImageEnIO); overload;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF USE_LISTVIEW}
|
|
// Clears the EXIF fields from the specified ImageEnIO object and in the specified listview
|
|
procedure ClearEXIFFields(AListView: TListView; AImageEnIO: TImageEnIO); overload;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF USE_STRINGGRIDS}
|
|
// saves the EXIF fields in the specified stringgrid to the file
|
|
procedure SaveEXIFFields(AStringGrid: TStringGrid;
|
|
sFilename: string;
|
|
AnImageEnIO: TImageEnIO;
|
|
const bMaintainFileDates: boolean); // if true the file date is not modified when saving the file
|
|
{$ENDIF}
|
|
|
|
// gets a string representation of the exif data specified by the field index
|
|
function GetEXIFField(AnImageEnIO: TImageEnIO; iFieldIndex: Integer): string;
|
|
|
|
// exif data specified by the field index with the value in the specified string
|
|
procedure SetEXIFField(AnImageEnIO: TImageEnIO; iFieldIndex: Integer; value: string);
|
|
|
|
// returns some common EXIF fields : EXIF_Model, EXIF_ExposureTime, EXIF_Flash
|
|
function GetUsefulEXIFFields(sFilename: string;
|
|
AnImageEnIO: TImageEnIO;
|
|
var sCameraModel: string;
|
|
var sExposureTime: string;
|
|
var sFlashMode: string
|
|
): boolean;
|
|
|
|
// return the GPS fields from the exif fields
|
|
function ExifGPSData(sFilename: string;
|
|
AnImageEnIO: TImageEnIO;
|
|
out GPSLatitudeDegrees: Double;
|
|
out GPSLongitudeDegrees: Double
|
|
): Boolean;
|
|
|
|
// reformats an EXIF date string using the localized date settings (shortdate)
|
|
function ReformatEXIFDateTime(sEXIFDateTime: string): string;
|
|
|
|
// EXIF CONST ROUTINES
|
|
// Allow user to specify exif consts, such as %EXIF-User-Comment%, in their text
|
|
// then can use this routine to convert all consts to their actual EXIF value
|
|
|
|
// Get a list of all EXIF consts
|
|
procedure GetAllExifFields(ssDest: TStrings; bClearList: Boolean);
|
|
|
|
// Reurns true is sText cotnains an exif const such as %EXIF-User-Comment%
|
|
function ContainsExifField(const sText: string): Boolean;
|
|
|
|
// Replaces any exif consts in sText with the actual values
|
|
// bSampleOnly : if we are just showing the kind of text we might output, returns example text rather than ''
|
|
function ReplaceExifFields(const sText: string; AnImageEnIO: TImageEnIO; sFilename: string; bSampleOnly: Boolean = False): string;
|
|
|
|
const
|
|
_EXIF_UserComment = 0;
|
|
_EXIF_ImageDescription = 1;
|
|
_EXIF_Camera = 2;
|
|
_EXIF_XResolution = 3;
|
|
_EXIF_YResolution = 4;
|
|
_EXIF_DateTime = 5;
|
|
_EXIF_DateTimeOriginal = 6;
|
|
_EXIF_DateTimeDigitized = 7;
|
|
_EXIF_Copyright = 8;
|
|
_EXIF_Orientation = 9;
|
|
_EXIF_ExposureTime = 10;
|
|
_EXIF_FNumber = 11;
|
|
_EXIF_ExposureProgram = 12;
|
|
_EXIF_ISOSpeedRatings = 13;
|
|
_EXIF_ShutterSpeedValue = 14;
|
|
_EXIF_ApertureValue = 15;
|
|
_EXIF_BrightnessValue = 16;
|
|
_EXIF_ExposureBiasValue = 17;
|
|
_EXIF_MaxApertureValue = 18;
|
|
_EXIF_SubjectDistance = 19;
|
|
_EXIF_MeteringMode = 20;
|
|
_EXIF_LightSource = 21;
|
|
_EXIF_Flash = 22;
|
|
_EXIF_FocalLength = 23;
|
|
_EXIF_FlashPixVersion = 24;
|
|
_EXIF_ColorSpace = 25;
|
|
_EXIF_ExifImageWidth = 26;
|
|
_EXIF_ExifImageHeight = 27;
|
|
_EXIF_RelatedSoundFile = 28;
|
|
_EXIF_FocalPlaneXResolution = 29;
|
|
_EXIF_FocalPlaneYResolution = 30;
|
|
_EXIF_ExposureIndex = 31;
|
|
_EXIF_SensingMethod = 32;
|
|
_EXIF_FileSource = 33;
|
|
_EXIF_SceneType = 34;
|
|
_EXIF_YCbCrPositioning = 35;
|
|
_EXIF_ExposureMode = 36;
|
|
_EXIF_WhiteBalance = 37;
|
|
_EXIF_DigitalZoomRatio = 38;
|
|
_EXIF_FocalLengthIn35mmFilm = 39;
|
|
_EXIF_SceneCaptureType = 40;
|
|
_EXIF_GainControl = 41;
|
|
_EXIF_Contrast = 42;
|
|
_EXIF_Saturation = 43;
|
|
_EXIF_Sharpness = 44;
|
|
_EXIF_SubjectDistanceRange = 45;
|
|
_EXIF_GPSLatitude = 46;
|
|
_EXIF_GPSLongitude = 47;
|
|
_EXIF_GPSAltitude = 48;
|
|
_EXIF_GPSImageDirection = 49;
|
|
_EXIF_GPSTrack = 50;
|
|
_EXIF_GPSSpeed = 51;
|
|
_EXIF_GPSDateAndTime = 52;
|
|
_EXIF_GPSSatellites = 53;
|
|
_EXIF_GPSVersionID = 54;
|
|
_EXIF_Artist = 55;
|
|
_EXIF_XPTitle = 56;
|
|
_EXIF_XPComment = 57;
|
|
_EXIF_XPAuthor = 58;
|
|
_EXIF_XPKeywords = 59;
|
|
_EXIF_XPSubject = 60;
|
|
_EXIF_XPRating = 61;
|
|
|
|
_EXIF_Tag_Count = 62;
|
|
|
|
{ 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
|
|
}
|
|
|
|
{$endif}
|
|
|
|
implementation
|
|
|
|
uses
|
|
Windows, hyieutils;
|
|
|
|
{$ifdef IEHASRECORDASCLASSES}
|
|
|
|
type
|
|
EXIF_Item = record
|
|
private
|
|
function GetFieldAsTextName: string;
|
|
public
|
|
Description: string;
|
|
VarType: Integer;
|
|
Editable: boolean;
|
|
|
|
property FieldAsTextName: string read GetFieldAsTextName;
|
|
end;
|
|
|
|
resourcestring
|
|
|
|
// EXIF Data
|
|
s_UserComment = 'User Comment';
|
|
s_Description = 'Description';
|
|
s_Camera = 'Camera';
|
|
s_Orientation = 'Camera Orientation';
|
|
s_Inch = 'Inch';
|
|
s_CM = '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_WhiteBalance = '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_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'; // Degrees
|
|
s_GPSLongitude = 'GPS Longitude'; // Degrees
|
|
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)';
|
|
|
|
const
|
|
|
|
_vString = 1;
|
|
_vInteger = 2;
|
|
_vDouble = 3;
|
|
|
|
Support_Complex = false;
|
|
|
|
Digital_Raw_Camera_Formats = '*.ARW;*.CRW;*.CR2;*.DNG;*.NEF;*.RAW;*.PEF;*.RAF;*.X3F;*.BAY;*.ORF;*.MRW;*.SRF;*.DCR;';
|
|
EXIF_COMPATIBLE_EXTENSIONS = '*.TIF;*.TIFF;*.JPE;*.JPG;*.JPEG;' + Digital_Raw_Camera_Formats;
|
|
|
|
EXIF : array [0.._EXIF_Tag_Count-1] of EXIF_Item=(
|
|
(Description : s_UserComment ; VarType : _vString; Editable : TRUE ), // _EXIF_UserComment
|
|
(Description : s_Description ; VarType : _vString; Editable : TRUE ), // _EXIF_ImageDescription
|
|
(Description : s_Camera ; VarType : _vString; Editable : TRUE ), // _EXIF_Camera
|
|
(Description : s_XResolution ; VarType : _vDouble; Editable : FALSE ), // _EXIF_XResolution
|
|
(Description : s_YResolution ; VarType : _vDouble; Editable : FALSE ), // _EXIF_YResolution
|
|
(Description : s_DateTime ; VarType : _vString; Editable : TRUE ), // _EXIF_DateTime
|
|
(Description : s_DateTimeOriginal ; VarType : _vString; Editable : TRUE ), // _EXIF_DateTimeOriginal
|
|
(Description : s_DateTimeDigitized ; VarType : _vString; Editable : TRUE ), // _EXIF_DateTimeDigitized
|
|
(Description : s_Copyright ; VarType : _vString; Editable : TRUE ), // _EXIF_Copyright
|
|
(Description : s_Orientation ; VarType : _vInteger; Editable : FALSE ), // _EXIF_Orientation
|
|
(Description : s_ExposureTime ; VarType : _vDouble; Editable : Support_Complex ), // _EXIF_ExposureTime
|
|
(Description : s_FNumber ; VarType : _vDouble; Editable : Support_Complex ), // _EXIF_FNumber
|
|
(Description : s_ExposureProgram ; VarType : _vInteger; Editable : Support_Complex ), // _EXIF_ExposureProgram
|
|
(Description : s_ISOSpeedRatings ; VarType : _vInteger; Editable : Support_Complex ), // _EXIF_ISOSpeedRatings
|
|
(Description : s_ShutterSpeedValue ; VarType : _vDouble; Editable : Support_Complex ), // _EXIF_ShutterSpeedValue
|
|
(Description : s_ApertureValue ; VarType : _vDouble; Editable : Support_Complex ), // _EXIF_ApertureValue
|
|
(Description : s_BrightnessValue ; VarType : _vDouble; Editable : Support_Complex ), // _EXIF_BrightnessValue
|
|
(Description : s_ExposureBiasValue ; VarType : _vDouble; Editable : Support_Complex ), // _EXIF_ExposureBiasValue
|
|
(Description : s_MaxApertureValue ; VarType : _vDouble; Editable : Support_Complex ), // _EXIF_MaxApertureValue
|
|
(Description : s_SubjectDistance ; VarType : _vDouble; Editable : Support_Complex ), // _EXIF_SubjectDistance
|
|
(Description : s_MeteringMode ; VarType : _vInteger; Editable : FALSE ), // _EXIF_MeteringMode
|
|
(Description : s_WhiteBalance ; VarType : _vInteger; Editable : FALSE ), // _EXIF_LightSource
|
|
(Description : s_Flash ; VarType : _vInteger; Editable : FALSE ), // _EXIF_Flash
|
|
(Description : s_FocalLength ; VarType : _vDouble; Editable : TRUE ), // _EXIF_FocalLength
|
|
(Description : s_FlashPixVersion ; VarType : _vString; Editable : TRUE ), // _EXIF_FlashPixVersion
|
|
(Description : s_ColorSpace ; VarType : _vInteger; Editable : FALSE ), // _EXIF_ColorSpace
|
|
(Description : s_ExifImageWidth ; VarType : _vInteger; Editable : TRUE ), // _EXIF_ExifImageWidth
|
|
(Description : s_ExifImageHeight ; VarType : _vInteger; Editable : TRUE ), // _EXIF_ExifImageHeight
|
|
(Description : s_RelatedSoundFile ; VarType : _vString; Editable : TRUE ), // _EXIF_RelatedSoundFile
|
|
(Description : s_FocalPlaneXResolution ; VarType : _vDouble; Editable : FALSE ), // _EXIF_FocalPlaneXResolution
|
|
(Description : s_FocalPlaneYResolution ; VarType : _vDouble; Editable : FALSE ), // _EXIF_FocalPlaneYResolution
|
|
(Description : s_ExposureIndex ; VarType : _vDouble; Editable : TRUE ), // _EXIF_ExposureIndex
|
|
(Description : s_SensingMethod ; VarType : _vInteger; Editable : FALSE ), // _EXIF_SensingMethod
|
|
(Description : s_FileSource ; VarType : _vInteger; Editable : FALSE ), // _EXIF_FileSource
|
|
(Description : s_SceneType ; VarType : _vInteger; Editable : FALSE ), // _EXIF_SceneType
|
|
(Description : s_YCbCrPositioning ; VarType : _vInteger; Editable : FALSE ), // _EXIF_YCbCrPositioning
|
|
(Description : s_ExposureMode ; VarType : _vInteger; Editable : FALSE ), // _EXIF_ExposureMode
|
|
(Description : s_WhiteBalance ; VarType : _vInteger; Editable : FALSE ), // _EXIF_WhiteBalance
|
|
(Description : s_DigitalZoomRatio ; VarType : _vDouble; Editable : Support_Complex ), // _EXIF_DigitalZoomRatio
|
|
(Description : s_FocalLengthIn35mmFilm ; VarType : _vInteger; Editable : Support_Complex ), // _EXIF_FocalLengthIn35mmFilm
|
|
(Description : s_SceneCaptureType ; VarType : _vInteger; Editable : FALSE ), // _EXIF_SceneCaptureType
|
|
(Description : s_GainControl ; VarType : _vInteger; Editable : FALSE ), // _EXIF_GainControl
|
|
(Description : s_Contrast ; VarType : _vInteger; Editable : FALSE ), // _EXIF_Contrast
|
|
(Description : s_Saturation ; VarType : _vInteger; Editable : FALSE ), // _EXIF_Saturation
|
|
(Description : s_Sharpness ; VarType : _vInteger; Editable : FALSE ), // _EXIF_Sharpness
|
|
(Description : s_SubjectDistanceRange ; VarType : _vInteger; Editable : FALSE ), // _EXIF_SubjectDistanceRange
|
|
(Description : s_GPSLatitude ; VarType : _vDouble; Editable : FALSE ), // _EXIF_GPSLatitudeDegrees
|
|
(Description : s_GPSLongitude ; VarType : _vDouble; Editable : FALSE ), // _EXIF_GPSLongitudeDegrees
|
|
(Description : s_GPSAltitude ; VarType : _vDouble; Editable : FALSE ), // _EXIF_GPSAltitude
|
|
(Description : s_GPSImageDirection ; VarType : _vDouble; Editable : FALSE ), // _EXIF_GPSImageDirection
|
|
(Description : s_GPSTrack ; VarType : _vDouble; Editable : FALSE ), // _EXIF_GPSTrack
|
|
(Description : s_GPSSpeed ; VarType : _vDouble; Editable : FALSE ), // _EXIF_GPSSpeed
|
|
(Description : s_GPSDateAndTime ; VarType : _vDouble; Editable : FALSE ), // _EXIF_GPSDateAndTime
|
|
(Description : s_GPSSatellites ; VarType : _vString; Editable : TRUE ), // _EXIF_GPSSatellites
|
|
(Description : s_GPSVersionID ; VarType : _vString; Editable : TRUE ), // _EXIF_GPSVersionID
|
|
(Description : s_Artist ; VarType : _vString; Editable : TRUE ), // _EXIF_Artist
|
|
(Description : s_XPTitle ; VarType : _vString; Editable : TRUE ), // _EXIF_XPTitle
|
|
(Description : s_XPComment ; VarType : _vString; Editable : TRUE ), // _EXIF_XPComment
|
|
(Description : s_XPAuthor ; VarType : _vString; Editable : TRUE ), // _EXIF_XPAuthor
|
|
(Description : s_XPKeywords ; VarType : _vString; Editable : TRUE ), // _EXIF_XPKeywords
|
|
(Description : s_XPSubject ; VarType : _vString; Editable : TRUE ), // _EXIF_XPSubject
|
|
(Description : s_XPRating ; VarType : _vInteger; Editable : TRUE ) // _EXIF_XPRating
|
|
);
|
|
|
|
// FieldAsText is 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_Field_As_Text_Prefix = '%EXIF-';
|
|
Exif_Field_As_Text_Suffix = '%';
|
|
|
|
// return a double value as a fraction
|
|
function DoubleToFraction(dValue: double): string;
|
|
begin
|
|
if (dValue = 0) or (dValue = -1) then
|
|
result := ''
|
|
else
|
|
result := '1/' + floattostr(dValue);
|
|
end;
|
|
|
|
// return a double value as a fraction
|
|
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;
|
|
|
|
function IntToStrOrNull(iValue: Integer): string;
|
|
begin
|
|
if (iValue = 0) or (iValue = -1) then
|
|
Result := ''
|
|
else
|
|
result := inttostr(iValue);
|
|
end;
|
|
|
|
function FloatToStrOrNull(dValue: double; sAppend: string): string;
|
|
begin
|
|
if (dValue = 0) or (dValue = -1) then
|
|
result := ''
|
|
else
|
|
result := floattostr(dValue) + sAppend;
|
|
end;
|
|
|
|
// convert an apex value to a string
|
|
function ApexToStr(dBase: double;
|
|
dValue: double;
|
|
sPrepend: string): string;
|
|
begin
|
|
try
|
|
if (dValue = 0) or (dValue = -1) then
|
|
raise EConvertError.create('Invalid value');
|
|
|
|
dValue := Power(dBase, dValue);
|
|
|
|
if (sPrepend = '1/') and
|
|
(dValue > 0) and
|
|
(dvalue <= 1) then
|
|
// cope with values such as 0.17
|
|
result := format('%0.1g', [1 / dValue])
|
|
else
|
|
result := sPrepend + format('%0.1g', [dValue]);
|
|
except
|
|
result := '';
|
|
end;
|
|
end;
|
|
|
|
// convert a string to an apex value
|
|
function FStrToApex(Value: string;
|
|
sPrepended: string;
|
|
dBase: double): double;
|
|
begin
|
|
// NOT YET SUPPORTED
|
|
raise EConvertError.create('Apex value');
|
|
end;
|
|
|
|
// remove sStrip from the end of the string value
|
|
function StripSuffix(Value: string; sStrip: string): string;
|
|
begin
|
|
result := value;
|
|
if pos(uppercase(sStrip), uppercase(result)) = (length(result) - length(sStrip)) + 1 then
|
|
setlength(result, length(result) - length(sStrip));
|
|
end;
|
|
|
|
// remove the null terminator from a string
|
|
function RemoveNull(sValue: string): string;
|
|
begin
|
|
result := trim(svalue);
|
|
if (result <> '') and
|
|
(result[length(result)] = #0) then
|
|
SetLength(result, length(result) - 1);
|
|
result := trim(result);
|
|
end;
|
|
|
|
// 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;
|
|
|
|
// return true if the specified filename is a digital camera raw file
|
|
function IsRawFile(const sFilename: string): boolean;
|
|
begin
|
|
result := IEFilenameInExtensions(sFilename, Digital_Raw_Camera_Formats);
|
|
end;
|
|
|
|
{$IFDEF USE_STRINGGRIDS}
|
|
// sets up a string grid for EXIF editing/display, by adding all property names
|
|
// also adds a header row if FixedRow >= 1
|
|
procedure InitializeEXIFStringGrid(AStringGrid: TStringGrid; sFilename: string = '');
|
|
var
|
|
i: integer;
|
|
begin
|
|
with AStringGrid do
|
|
begin
|
|
// add a row for each EXIF plus the header (if tjhere is a fixed row)
|
|
RowCount := high(EXIF) + 1 + AStringGrid.FixedRows;
|
|
|
|
// header row
|
|
Cells[0, 0] := 'Property';
|
|
Cells[1, 0] := 'Value';
|
|
|
|
// fill the fields with the EXIF property names
|
|
for i := 0 to high(EXIF) do
|
|
begin
|
|
Cells[0, i + AStringGrid.FixedRows] := EXIF[i].Description;
|
|
Cells[1, i + AStringGrid.FixedRows] := '';
|
|
end;
|
|
|
|
if (sFilename <> '') and IsRawFile(sFilename) then
|
|
begin
|
|
Color := clBtnFace;
|
|
Options := Options - [goEditing];
|
|
end
|
|
else
|
|
begin
|
|
Color := clWindow;
|
|
Options := Options + [goEditing];
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF USE_LISTVIEW}
|
|
// sets up a listview for EXIF editing/display, by adding all property names
|
|
procedure InitializeEXIFListView(AListView: TListView; sFilename: string = '');
|
|
var
|
|
i: integer;
|
|
iListColumn: TListColumn;
|
|
iListItem: TListItem;
|
|
begin
|
|
with AListView do
|
|
begin
|
|
{ setup the columns }
|
|
iListColumn := Columns.Add;
|
|
iListColumn.Caption := 'Parameter';
|
|
iListColumn.Width := 150;
|
|
iListColumn := Columns.Add;
|
|
iListColumn.Caption := 'Value';
|
|
iListColumn.Width := 450;
|
|
|
|
// fill the fields with the EXIF property names
|
|
for i := 0 to high(EXIF) do
|
|
begin
|
|
iListItem := AListView.Items.Add;
|
|
iListItem.Caption := EXIF[i].Description;
|
|
iListItem.SubItems.Add('')
|
|
end;
|
|
|
|
if (sFilename <> '') and IsRawFile(sFilename) then
|
|
begin
|
|
Color := clBtnFace;
|
|
end
|
|
else
|
|
begin
|
|
Color := clWindow;
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function ExposureToString(iExposureTime: double): string;
|
|
begin
|
|
if iExposureTime > 1 then
|
|
// then it will be something like 4 i.e. 4 seconds
|
|
result := inttostr(round(iExposureTime)) + ' ' + s_Seconds
|
|
else if (iExposureTime > 0) then
|
|
// then it is an integer second value, e.g. 0.14.. which transslated to 7 seconds
|
|
result := DoubleToFraction(round(1 / iExposureTime)) + ' ' + s_Second;
|
|
end;
|
|
|
|
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;
|
|
|
|
{$IFDEF USE_STRINGGRIDS}
|
|
// loads the EXIF fields for the specified file into the String Grid
|
|
// if bLoadParams=false then it is assumed that AnImageEnIO has already loaded the file
|
|
// result is whether the file has any fields specified
|
|
function LoadEXIFFields(AStringGrid: TStringGrid;
|
|
sFilename: string;
|
|
AnImageEnIO: TImageEnIO;
|
|
bLoadParams: boolean = true): boolean;
|
|
var
|
|
i: integer;
|
|
begin
|
|
result := True;
|
|
|
|
InitializeEXIFStringGrid(AStringGrid, sFilename);
|
|
|
|
if bLoadParams then
|
|
AnImageEnIO.paramsfromfile(sFilename);
|
|
|
|
if (AnImageEnIO.params.EXIF_HasEXIFData = false) and
|
|
(IsRawFile(sFilename) = false) then
|
|
begin
|
|
result := False;
|
|
exit;
|
|
end;
|
|
|
|
for i := low(EXIF) to high(EXIF) do
|
|
AStringGrid.cells[1, i + AStringGrid.FixedRows] := GetEXIFField(AnImageEnIO, i);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF USE_LISTVIEW}
|
|
// loads the EXIF fields for the specified file into the ListView
|
|
// if bLoadParams=false then it is assumed that AnImageEnIO has already loaded the file
|
|
// result is whether the file has any fields specified
|
|
function LoadEXIFFields(AListView: TListView;
|
|
sFilename: string;
|
|
AImageEnIO: TImageEnIO;
|
|
bLoadParams: boolean = true): boolean;
|
|
var
|
|
i: integer;
|
|
begin
|
|
result := True;
|
|
|
|
InitializeEXIFListView(AListview, sFilename);
|
|
|
|
if bLoadParams then
|
|
AImageEnIO.ParamsFromFile(sFilename);
|
|
|
|
if (AImageEnIO.Params.EXIF_HasEXIFData = false) and
|
|
(IsRawFile(sFilename) = false) then
|
|
begin
|
|
result := False;
|
|
exit;
|
|
end;
|
|
|
|
for i := low(EXIF) to high(EXIF) do
|
|
AListView.Items.Item[i].SubItems[0] := GetEXIFField(AImageEnIO, i);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
// get a string representation of the exif data specified by the field index
|
|
function GetEXIFField(AnImageEnIO: TImageEnIO; iFieldIndex: Integer): string;
|
|
var
|
|
sFPUnit: string; // used in retrieval of EXIF data (resolution unit)
|
|
sResUnit: string; // used in retrieval of EXIF data (resolution unit)
|
|
begin
|
|
result := '';
|
|
|
|
with AnImageEnIO.params do
|
|
try
|
|
case iFieldIndex of
|
|
|
|
_EXIF_UserComment: result := RemoveNull(EXIF_UserComment);
|
|
|
|
// EXIF_ImageDescription
|
|
// Describes the image
|
|
_EXIF_ImageDescription: result := RemoveNull(EXIF_ImageDescription);
|
|
|
|
//_EXIF_Make : result := RemoveNull(EXIF_Make);
|
|
|
|
// EXIF_Model
|
|
// Shows model number of digicam
|
|
//_EXIF_Model : result := RemoveNull(EXIF_Model);
|
|
|
|
_EXIF_Camera:
|
|
begin
|
|
result := RemoveNull(EXIF_Make) + ' ' + RemoveNull(EXIF_Model);
|
|
if (Result <> '') and (Result[1] = ' ') then
|
|
Delete(Result, 1, 1);
|
|
if (Result <> '') and (Result[Length(Result)] = ' ') then
|
|
SetLength(Result, Length(Result) - 1);
|
|
end;
|
|
|
|
// EXIF_XResolution
|
|
// 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.
|
|
// EXIF_ResolutionUnit
|
|
// Unit of XResolution/YResolution.
|
|
{
|
|
1 means no-unit
|
|
2 means inch
|
|
3 means centimeter
|
|
Default value is 2 (inch)
|
|
}
|
|
_EXIF_XResolution:
|
|
begin
|
|
case EXIF_ResolutionUnit of
|
|
2: sResUnit := s_Inch;
|
|
3: sResUnit := s_CM;
|
|
else
|
|
sResUnit := '';
|
|
end;
|
|
result := DoubleToFraction(EXIF_Xresolution) + ' ' + sResUnit;
|
|
end;
|
|
|
|
// EXIF_YResolution
|
|
// 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.
|
|
// EXIF_ResolutionUnit
|
|
// Unit of XResolution/YResolution.
|
|
{
|
|
1 means no-unit
|
|
2 means inch
|
|
3 means centimeter
|
|
Default value is 2 (inch)
|
|
}
|
|
_EXIF_YResolution:
|
|
begin
|
|
case EXIF_ResolutionUnit of
|
|
2: sResUnit := s_Inch;
|
|
3: sResUnit := s_CM;
|
|
else
|
|
sResUnit := '';
|
|
end;
|
|
|
|
result := DoubleToFraction(EXIF_Yresolution) + ' ' + sResUnit;
|
|
end;
|
|
|
|
// EXIF_Software
|
|
// Shows firmware(internal software of digicam) version number
|
|
// _EXIF_Software : result := RemoveNull(EXIF_Software);
|
|
|
|
// EXIF_DateTime
|
|
// Date/Time of image was last modified. Data format is "YYYY : MM : DD HH : MM : SS"+0x00, total 20bytes. If clock has not set or digicam doesn't have clock, the field may be filled with spaces. In usual, it has the same value of DateTimeOriginal
|
|
_EXIF_DateTime: result := ReformatEXIFDateTime(RemoveNull(EXIF_DateTime)) {+sSubsecTime};
|
|
|
|
// EXIF_DateTimeOriginal
|
|
// Date/Time of original image taken. This value should not be modified by user program. Data format is "YYYY : MM : DD HH : MM : SS"+0x00, total 20bytes. If clock has not set or digicam doesn't have clock, the field may be filled with spaces. In the Exif standard, this tag is optional, but it is mandatory for DCF.
|
|
_EXIF_DateTimeOriginal: result := ReformatEXIFDateTime(RemoveNull(EXIF_DateTimeOriginal))
|
|
{+ sSubsecTimeOriginal};
|
|
|
|
// EXIF_DateTimeDigitized
|
|
// Date/Time of image digitized. Usually, it contains the same value of DateTimeOriginal(0x9003). Data format is "YYYY : MM : DD HH : MM : SS"+0x00, total 20bytes. If clock has not set or digicam doesn't have clock, the field may be filled with spaces. In the Exif standard, this tag is optional, but it is mandatory for DCF.
|
|
_EXIF_DateTimeDigitized: result := ReformatEXIFDateTime(RemoveNull(EXIF_DateTimeDigitized))
|
|
{+ sSubsecTimeDigitized};
|
|
|
|
// EXIF_Copyright
|
|
// Shows copyright information
|
|
_EXIF_Copyright: result := RemoveNull(EXIF_Copyright);
|
|
|
|
// EXIF_Orientation
|
|
// The orientation of the camera relative to the scene, when the image was captured
|
|
_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
|
|
// Exposure time (reciprocal of shutter speed). Unit is second.
|
|
_EXIF_ExposureTime: result := ExposureToString(EXIF_ExposureTime);
|
|
|
|
// EXIF_FNumber
|
|
// The actual F-number(F-stop) of lens when the image was taken.
|
|
_EXIF_FNumber:
|
|
if (EXIF_Fnumber <> 0) and (EXIF_Fnumber <> -1) then
|
|
result := 'F' + FloatToStrOrNull(EXIF_Fnumber, '');
|
|
|
|
// EXIF_ExposureProgram
|
|
// 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:
|
|
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;
|
|
|
|
// EXIF_ISOSpeedRatings
|
|
// 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
|
|
// 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: result := ApexToStr(2, EXIF_ShutterSpeedValue, '1/');
|
|
|
|
// EXIF_ApertureValue
|
|
// 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: result := ApexToStr(Sqrt(2), EXIF_ApertureValue, 'F');
|
|
|
|
// EXIF_BrightnessValue
|
|
// 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, '');
|
|
//???DoubleToFraction(EXIF_BrightnessValue); ddd
|
|
|
|
// EXIF_ExposureBiasValue
|
|
// Exposure bias(compensation) value of taking picture. Unit is APEX (EV).
|
|
_EXIF_ExposureBiasValue: result := DoubleToFraction(EXIF_ExposureBiasValue);
|
|
|
|
// EXIF_MaxApertureValue
|
|
// Maximum aperture value of lens. You can convert to F-number by calculating power of root 2 (same process of ApertureValue).
|
|
_EXIF_MaxApertureValue: result := ApexToStr(Sqrt(2), EXIF_MaxApertureValue, 'F');
|
|
|
|
// EXIF_SubjectDistance
|
|
// Distance to focus point, unit is meter.
|
|
_EXIF_SubjectDistance:
|
|
if EXIF_SubjectDistance > 0 then
|
|
result := FloatToStrOrNull(EXIF_SubjectDistance, ' m');
|
|
|
|
// EXIF_MeteringMode
|
|
// 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;
|
|
|
|
// EXIF_LightSource
|
|
// 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);
|
|
|
|
// EXIF_FocalLength
|
|
// Focal length of lens used to take image. Unit is millimeter.
|
|
_EXIF_FocalLength:
|
|
if EXIF_FocalLength > 0 then
|
|
result := FloatToStrOrNull(EXIF_FocalLength, ' mm');
|
|
|
|
// EXIF_FlashPixVersion
|
|
// Stores FlashPix version. If the image data is based on FlashPix formar Ver.1.0, value is "0100".
|
|
_EXIF_FlashPixVersion: result := RemoveNull(EXIF_FlashPixVersion);
|
|
|
|
// EXIF_ColorSpace
|
|
// 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, EXIF,_EXIFImageHeight
|
|
// Size of main image.
|
|
_EXIF_ExifImageWidth: result := IntToStrOrNull(EXIF_ExifImageWidth);
|
|
|
|
// EXIF,_EXIFImageWidth, EXIF,_EXIFImageHeight
|
|
// Size of main image.
|
|
_EXIF_ExifImageHeight: result := IntToStrOrNull(EXIF_ExifImageHeight);
|
|
|
|
// EXIF_RelatedSoundFile
|
|
// If this digicam can record audio data with image, shows name of audio data.
|
|
_EXIF_RelatedSoundFile: result := RemoveNull(EXIF_RelatedSoundFile);
|
|
|
|
// EXIF_FocalPlaneResolutionUnit
|
|
// 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_inch;
|
|
3: sFPUnit := s_CM;
|
|
else
|
|
sFPUnit := '';
|
|
end;
|
|
|
|
// EXIF_FocalPlaneXResolution, EXIF_FocalPlaneYResolution
|
|
// 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 > 0 then
|
|
result := IEFloatToFormatString(EXIF_FocalPlaneXResolution, 2, true) + ' ' + sFPUnit;
|
|
end;
|
|
|
|
_EXIF_FocalPlaneYResolution:
|
|
begin
|
|
case EXIF_FocalPlaneResolutionUnit of
|
|
2: sFPUnit := s_inch;
|
|
3: sFPUnit := s_CM;
|
|
else
|
|
sFPUnit := '';
|
|
end;
|
|
|
|
// EXIF_FocalPlaneXResolution, EXIF_FocalPlaneYResolution
|
|
// 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 > 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, '');
|
|
|
|
// EXIF_SensingMethod
|
|
// Shows type of 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
|
|
{ELSE
|
|
result := s_UnknownMethod)};
|
|
|
|
// EXIF_FileSource
|
|
// Indicates the image source. Value '0x03' means the image source is digital still camera.
|
|
_EXIF_FileSource:
|
|
if EXIF_FileSource = $03 then
|
|
result := s_DigitalStillCamera
|
|
{ELSE
|
|
result := s_UnknownDevice)};
|
|
|
|
// EXIF_SceneType
|
|
// Indicates the type of scene. Value '0x01' means that the image was directly photographed.
|
|
_EXIF_SceneType:
|
|
if EXIF_SceneType = $01 then
|
|
result := s_DirectlyPhotographed
|
|
{ELSE
|
|
result := s_UnknownMethod)};
|
|
|
|
// EXIF_YCbCrPositioning
|
|
// 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;
|
|
|
|
{ EXIF_ExposureMode
|
|
This tag indicates 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; // 'Auto exposure';
|
|
1: s_Manualexposure; // 'Manual exposure';
|
|
2: s_Autobracket; // 'Auto bracket';
|
|
end;
|
|
|
|
{ EXIF_WhiteBalance
|
|
This tag indicates 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; // 'Auto white balance';
|
|
1: s_Manualwhitebalance; // 'Manual white balance';
|
|
end;
|
|
|
|
{ EXIF_DigitalZoomRatio
|
|
This tag indicates 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, '');
|
|
|
|
{ EXIF_FocalLengthIn35mmFilm
|
|
This tag indicates 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';
|
|
|
|
{ EXIF_SceneCaptureType
|
|
This tag indicates 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; // 'Standard';
|
|
1: s_Landscape; // 'Landscape';
|
|
2: s_Portrait; // 'Portrait';
|
|
3: s_Nightscene; // 'Night scene';
|
|
end;
|
|
|
|
{ EXIF_GainControl
|
|
This tag indicates 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; // 'None';
|
|
1: s_LowGainup; // 'Low gain up';
|
|
2: s_HighGainup; // 'High gain up';
|
|
3: s_LowGaindown; // 'Low gain down';
|
|
4: s_HighGaindown; // 'High gain down';
|
|
end;
|
|
|
|
{ EXIF_Contrast
|
|
This tag indicates 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; // 'Normal';
|
|
1: s_Soft; // 'Soft';
|
|
2: s_Hard; // 'Hard';
|
|
end;
|
|
|
|
{ EXIF_Saturation
|
|
This tag indicates 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; // 'Normal';
|
|
1: s_Lowsaturation; // 'Low saturation';
|
|
2: s_Highsaturation; // 'High saturation';
|
|
end;
|
|
|
|
{ EXIF_Sharpness
|
|
This tag indicates 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; // 'Normal';
|
|
1: s_Soft; // 'Soft';
|
|
2: s_Hard; // 'Hard';
|
|
end;
|
|
|
|
{ EXIF_SubjectDistanceRange
|
|
This tag indicates the distance to the subject.
|
|
0 = unknown
|
|
1 = Macro
|
|
2 = Close view
|
|
3 = Distant view
|
|
}
|
|
_EXIF_SubjectDistanceRange:
|
|
case EXIF_SubjectDistanceRange of
|
|
// 0 : s_unknown ; // 'unknown';
|
|
1: s_Macro; // 'Macro';
|
|
2: s_Closeview; // 'Close view';
|
|
3: s_Distantview; // 'Distant view';
|
|
end;
|
|
|
|
{ Indicates the latitude degrees }
|
|
|
|
_EXIF_GPSLatitude: Result := EXIF_GPSLatitude_Str;
|
|
|
|
{
|
|
Indicates the longitude degrees.
|
|
}
|
|
|
|
_EXIF_GPSLongitude: Result := EXIF_GPSLongitude_Str;
|
|
|
|
_EXIF_GPSAltitude:
|
|
{
|
|
Indicates the altitude based on the reference in Ref. The reference unit is meters.
|
|
}
|
|
if (EXIF_GPSAltitude <> 0) or (EXIF_GPSAltitudeRef <> '') then
|
|
begin
|
|
result := FloatToStrOrNull(EXIF_GPSAltitude, ' m');
|
|
|
|
if RemoveNull(EXIF_GPSAltitudeRef) = '1' then
|
|
Result := Result + ' (Below sea-level)';
|
|
end;
|
|
|
|
_EXIF_GPSDateAndTime:
|
|
{
|
|
Indicates the altitude based on the reference in Ref. The reference unit is meters.
|
|
}
|
|
if (EXIF_GPSDateStamp <> '') then
|
|
begin
|
|
result := Format('%s %s : %s.%s', [RemoveNull(EXIF_GPSDateStamp),
|
|
FloatToStr(EXIF_GPSTimeStampHour),
|
|
FloatToStr(EXIF_GPSTimeStampMinute),
|
|
FloatToStr(EXIF_GPSTimeStampSecond)]);
|
|
end;
|
|
|
|
_EXIF_GPSImageDirection:
|
|
{
|
|
EXIF_GPSImgDirection : Indicates the direction of the image when it was captured. The range of values is from 0.00 to 359.99.
|
|
EXIF_GPSImgDirectionRef : Indicates 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 (RemoveNull(EXIF_GPSImgDirectionRef) <> '') then
|
|
begin
|
|
result := FloatToStrOrNull(EXIF_GPSImgDirection, ' degrees');
|
|
if uppercase(RemoveNull(EXIF_GPSImgDirectionRef)) = 'T' then
|
|
Result := Result + ' (True)'
|
|
else if uppercase(RemoveNull(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 (RemoveNull(EXIF_GPSSpeedRef) <> '') then
|
|
begin
|
|
if uppercase(RemoveNull(EXIF_GPSSpeedRef)) = 'K' then
|
|
Result := FloatToStr(EXIF_GPSSpeed) + ' km/h'
|
|
else if uppercase(RemoveNull(EXIF_GPSSpeedRef)) = 'M' then
|
|
Result := FloatToStr(EXIF_GPSSpeed) + ' mph'
|
|
else if uppercase(RemoveNull(EXIF_GPSSpeedRef)) = 'N' then
|
|
Result := FloatToStr(EXIF_GPSSpeed) + ' knots'
|
|
else
|
|
Result := FloatToStr(EXIF_GPSSpeed) + ' ' + RemoveNull(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 : Indicates 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 (RemoveNull(EXIF_GPSTrackRef) <> '') then
|
|
begin
|
|
result := FloatToStrOrNull(EXIF_GPSTrack, ' degrees');
|
|
if uppercase(RemoveNull(EXIF_GPSTrackRef)) = 'T' then
|
|
Result := Result + ' (True)'
|
|
else if uppercase(RemoveNull(EXIF_GPSTrackRef)) = 'M' then
|
|
Result := Result + ' (Magnetic)';
|
|
end;
|
|
|
|
_EXIF_GPSSatellites: result := RemoveNull(EXIF_GPSSatellites);
|
|
_EXIF_GPSVersionID: result := RemoveNull(EXIF_GPSVersionID);
|
|
|
|
_EXIF_Artist: result := RemoveNull(EXIF_Artist);
|
|
|
|
_EXIF_XPTitle: result := RemoveNull(EXIF_XPTitle);
|
|
_EXIF_XPComment: result := RemoveNull(EXIF_XPComment);
|
|
_EXIF_XPAuthor: result := RemoveNull(EXIF_XPAuthor);
|
|
_EXIF_XPKeywords: result := RemoveNull(EXIF_XPKeywords);
|
|
_EXIF_XPSubject: result := RemoveNull(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;
|
|
|
|
end;
|
|
|
|
except
|
|
// ERROR
|
|
end;
|
|
end;
|
|
|
|
// modifies the date/time stamp of a file
|
|
// Result is true, unless there is a file load error
|
|
function SetFileDate(const sFilename: string; DateTime: TDateTime): boolean;
|
|
var
|
|
liHandle: INTEGER;
|
|
begin
|
|
result := False;
|
|
|
|
if DateTime <> 0 then
|
|
try
|
|
liHandle := FileOpen(sFileName, fmOpenReadWrite or fmShareDenyNone);
|
|
if liHandle > 0 then
|
|
begin
|
|
result := FileSetDate(liHandle, DateTimeToFileDate(DateTime)) <> 0;
|
|
FileClose(liHandle);
|
|
end;
|
|
|
|
except
|
|
// ERROR
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF USE_STRINGGRIDS}
|
|
// saves the EXIF fields in the specified stringgrid to the file
|
|
procedure SaveEXIFFields(AStringGrid: TStringGrid;
|
|
sFilename: string;
|
|
AnImageEnIO: TImageEnIO;
|
|
const bMaintainFileDates: boolean); // if true the file date is not modified when saving the file
|
|
var
|
|
sCurrentField : string;
|
|
i : integer;
|
|
dFileDate : TDateTime;
|
|
bSomeFieldHasData : boolean;
|
|
begin
|
|
|
|
// need to know if any field has data assinged
|
|
bSomeFieldHasData := false;
|
|
|
|
dFileDate := 0; // to avoid compiler warniongs
|
|
|
|
// load values from the properties grid
|
|
for i := low(EXIF) to high(EXIF) do
|
|
begin
|
|
sCurrentField := AStringGrid.Cells[1, i + AStringGrid.FixedRows];
|
|
|
|
if sCurrentField <> '' then
|
|
bSomeFieldHasData := True;
|
|
|
|
// Has the data for that field changed?
|
|
if sCurrentField <> GetEXIFField(AnImageEnIO, i) then
|
|
SetEXIFField(AnImageEnIO, i, sCurrentField);
|
|
end;
|
|
|
|
AnImageEnIO.params.EXIF_HasEXIFData := bSomeFieldHasData;
|
|
|
|
{$WARNINGS OFF} // FileAge is deprecated
|
|
if bMaintainFileDates then
|
|
dFileDate := FileDateToDateTime(FileAge(sFileName));
|
|
{$WARNINGS ON}
|
|
|
|
case AnImageEnIO.Params.FileType of
|
|
ioJPEG: // inject EXIF in jpeg
|
|
AnImageEnIO.InjectJpegEXIF(sFileName);
|
|
ioTIFF: // save EXIF in TIFF
|
|
AnImageEnIO.SaveToFile(sFilename);
|
|
else
|
|
messagedlg('The format of the specified file does not support EXIF storage.', mtError, [mbok],
|
|
0);
|
|
end;
|
|
|
|
if bMaintainFileDates and (dFileDate <> 0) then
|
|
SetFileDate(sFilename, dFileDate);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
// exif data specified by the field index with the value in the specified string
|
|
procedure SetEXIFField(AnImageEnIO: TImageEnIO; iFieldIndex: Integer; value: string);
|
|
begin
|
|
value := trim(value);
|
|
|
|
with AnImageEnIO.params do
|
|
try
|
|
case iFieldIndex of
|
|
|
|
_EXIF_UserComment: EXIF_UserComment := value;
|
|
|
|
// EXIF_ImageDescription
|
|
// Describes the image
|
|
_EXIF_ImageDescription: EXIF_ImageDescription := value;
|
|
|
|
//_EXIF_Make : EXIF_Make :=value;
|
|
|
|
// EXIF_Model
|
|
// Shows model number of digicam
|
|
//_EXIF_Model : EXIF_Model :=value;
|
|
|
|
_Exif_Camera:
|
|
begin
|
|
EXIF_Make := GetTextBeforeChar(Value, ' ', False);
|
|
EXIF_Model := GetTextAfterChar(Value, ' ', True);
|
|
end;
|
|
|
|
// EXIF_XResolution
|
|
// 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.
|
|
// EXIF_ResolutionUnit
|
|
// 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;
|
|
|
|
Value := StripSuffix(value, ' ' + s_Inch);
|
|
Value := StripSuffix(value, ' ' + s_CM);
|
|
|
|
EXIF_Xresolution := FractionToDouble(value);
|
|
end;
|
|
|
|
// EXIF_YResolution
|
|
// 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.
|
|
// EXIF_ResolutionUnit
|
|
// 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 := FractionToDouble(value);
|
|
end;
|
|
|
|
// EXIF_Software
|
|
// Shows firmware(internal software of digicam) version number
|
|
//_EXIF_Software : EXIF_Software :=value;
|
|
|
|
// EXIF_DateTime
|
|
// Date/Time of image was last modified. Data format is "YYYY : MM : DD HH : MM : SS"+0x00, total 20bytes. If clock has not set or digicam doesn't have clock, the field may be filled with spaces. In usual, it has the same value of DateTimeOriginal
|
|
_EXIF_DateTime: EXIF_DateTime := DateTimeToEXIFDate(StrToDateTime(value));
|
|
|
|
// EXIF_DateTimeOriginal
|
|
// Date/Time of original image taken. This value should not be modified by user program. Data format is "YYYY : MM : DD HH : MM : SS"+0x00, total 20bytes. If clock has not set or digicam doesn't have clock, the field may be filled with spaces. In the Exif standard, this tag is optional, but it is mandatory for DCF.
|
|
_EXIF_DateTimeOriginal: EXIF_DateTimeOriginal := DateTimeToEXIFDate(StrToDateTime(value));
|
|
|
|
// EXIF_DateTimeDigitized
|
|
// Date/Time of image digitized. Usually, it contains the same value of DateTimeOriginal(0x9003). Data format is "YYYY : MM : DD HH : MM : SS"+0x00, total 20bytes. If clock has not set or digicam doesn't have clock, the field may be filled with spaces. In the Exif standard, this tag is optional, but it is mandatory for DCF.
|
|
_EXIF_DateTimeDigitized: EXIF_DateTimeDigitized :=
|
|
DateTimeToEXIFDate(StrToDateTime(value));
|
|
|
|
// EXIF_Copyright
|
|
// Shows copyright information
|
|
_EXIF_Copyright: EXIF_Copyright := value;
|
|
|
|
// EXIF_Orientation
|
|
// The orientation of the camera relative to the scene, when the image was captured
|
|
_EXIF_Orientation:
|
|
begin
|
|
{ADDWRITE
|
|
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;
|
|
}
|
|
end;
|
|
|
|
// EXIF_ExposureTime
|
|
// Exposure time (reciprocal of shutter speed). Unit is second.
|
|
_EXIF_ExposureTime:
|
|
begin
|
|
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;
|
|
|
|
// EXIF_FNumber
|
|
// The actual F-number(F-stop) of lens when the image was taken.
|
|
_EXIF_FNumber:
|
|
begin
|
|
if uppercase(value)[1] = 'F' then
|
|
delete(value, 1, 1);
|
|
|
|
EXIF_Fnumber := StrToFloat(value);
|
|
end;
|
|
|
|
// EXIF_ExposureProgram
|
|
// 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
|
|
{ADDWRITE
|
|
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;
|
|
}
|
|
end;
|
|
|
|
// EXIF_ISOSpeedRatings
|
|
// CCD sensitivity equivalent to Ag-Hr film speedrate.
|
|
_EXIF_ISOSpeedRatings: EXIF_ISOSpeedRatings[0] := StrToInt(value);
|
|
|
|
// EXIF_ExifVersion
|
|
// Exif version number. Stored as 4bytes of ASCII character. If the picture is based on Exif V2.1, value is "0210". Since the type is 'undefined', there is no NULL(0x00) for termination.
|
|
//_EXIF_ExifVersion : EXIF_ExifVersion :=value;
|
|
|
|
// EXIF_ShutterSpeedValue
|
|
// 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: EXIF_ShutterSpeedValue := FStrToApex(value, '1/', 2);
|
|
|
|
// EXIF_ApertureValue
|
|
// 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: EXIF_ApertureValue := FStrToApex(value, 'F', Sqrt(2));
|
|
|
|
// EXIF_BrightnessValue
|
|
// 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
|
|
// Exposure bias(compensation) value of taking picture. Unit is APEX(EV).
|
|
_EXIF_ExposureBiasValue: EXIF_ExposureBiasValue := FractionToDouble(value);
|
|
|
|
// EXIF_MaxApertureValue
|
|
// Maximum aperture value of lens. You can convert to F-number by calculating power of root 2 (same process of ApertureValue).
|
|
_EXIF_MaxApertureValue: EXIF_MaxApertureValue := FStrToApex(value, 'F', Sqrt(2));
|
|
|
|
// EXIF_SubjectDistance
|
|
// Distance to focus point, unit is meter.
|
|
_EXIF_SubjectDistance:
|
|
begin
|
|
value := StripSuffix(value, ' m');
|
|
EXIF_SubjectDistance := StrToFloat(value);
|
|
end;
|
|
|
|
// EXIF_MeteringMode
|
|
// 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
|
|
{ADDWRITE
|
|
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;
|
|
}
|
|
end;
|
|
|
|
// EXIF_LightSource
|
|
// 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
|
|
{ADDWRITE
|
|
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;
|
|
}
|
|
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
|
|
{ADDWRITE
|
|
Case EXIF_Flash of
|
|
0 : result := s_FlashDidNotFire;
|
|
1 : result := s_flashFired;
|
|
5 : result := s_flashFiredNoStrobeLight;
|
|
7 : result := s_flashFiredStrobeLight;
|
|
end;
|
|
}
|
|
end;
|
|
|
|
// EXIF_FocalLength
|
|
// 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
|
|
// Stores FlashPix version. If the image data is based on FlashPix formar Ver.1.0, value is "0100".
|
|
_EXIF_FlashPixVersion: EXIF_FlashPixVersion := Value;
|
|
|
|
// EXIF_ColorSpace
|
|
// 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
|
|
{ADDWRITE
|
|
Case EXIF_ColorSpace of
|
|
1 : result := s_RGB;
|
|
65535 : result := s_Uncalibrated;
|
|
end;
|
|
}
|
|
end;
|
|
|
|
// EXIF,_EXIFImageWidth, EXIF,_EXIFImageHeight
|
|
// Size of main image.
|
|
_EXIF_ExifImageWidth: EXIF_ExifImageWidth := StrToInt(value);
|
|
|
|
// EXIF,_EXIFImageWidth, EXIF,_EXIFImageHeight
|
|
// Size of main image.
|
|
_EXIF_ExifImageHeight: EXIF_ExifImageHeight := StrToInt(value);
|
|
|
|
// EXIF_RelatedSoundFile
|
|
// If this digicam can record audio data with image, shows name of audio data.
|
|
_EXIF_RelatedSoundFile: EXIF_RelatedSoundFile := value;
|
|
|
|
// EXIF_FocalPlaneResolutionUnit
|
|
// 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_Inch);
|
|
Value := StripSuffix(value, ' ' + s_CM);
|
|
|
|
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_Inch);
|
|
Value := StripSuffix(value, ' ' + s_CM);
|
|
|
|
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);
|
|
|
|
// EXIF_SensingMethod
|
|
// Shows type of image sensor unit. '2' means 1 chip color area sensor, most of all digicam use this type.
|
|
_EXIF_SensingMethod:
|
|
begin
|
|
{ADDWRITE
|
|
If EXIF_SensingMethod=2 then
|
|
result := s_OneChipColorAreaSensor
|
|
//ELSE
|
|
// result := s_UnknownMethod)
|
|
}
|
|
end;
|
|
|
|
// EXIF_FileSource
|
|
// Indicates the image source. Value '0x03' means the image source is digital still camera.
|
|
_EXIF_FileSource:
|
|
begin
|
|
{ADDWRITE
|
|
If EXIF_FileSource=$03 then
|
|
result := s_DigitalStillCamera
|
|
//ELSE
|
|
// result := s_UnknownDevice)
|
|
}
|
|
end;
|
|
|
|
// EXIF_SceneType
|
|
// Indicates the type of scene. Value '0x01' means that the image was directly photographed.
|
|
_EXIF_SceneType:
|
|
begin
|
|
{ADDWRITE
|
|
If EXIF_SceneType=$01 then
|
|
result := s_DirectlyPhotographed
|
|
//ELSE
|
|
// result := s_UnknownMethod)
|
|
}
|
|
end;
|
|
|
|
// EXIF_YCbCrPositioning
|
|
// 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
|
|
{ADDWRITE
|
|
case EXIF_YcbCrPositioning of
|
|
1 : result := s_Centered;
|
|
2 : result := s_DataPoint;
|
|
end;
|
|
}
|
|
end;
|
|
|
|
_EXIF_GPSSatellites: EXIF_GPSSatellites := Value;
|
|
_EXIF_GPSVersionID: EXIF_GPSVersionID := Value;
|
|
|
|
_EXIF_Artist: EXIF_Artist := 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);
|
|
|
|
{
|
|
TO-DO ADD WRITE SUPPORT :
|
|
|
|
_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
|
|
|
|
}
|
|
|
|
end;
|
|
|
|
except
|
|
// ERROR
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF USE_STRINGGRIDS}
|
|
// Clear the EXIF fields from the specified ImageEnIO object and in the specified stringgrid
|
|
procedure ClearEXIFFields(AStringGrid: TStringGrid;
|
|
AnImageEnIO: TImageEnIO);
|
|
var
|
|
i: integer;
|
|
begin
|
|
AnImageEnIO.params.EXIF_HasEXIFData := False;
|
|
for i := low(EXIF) to high(EXIF) do
|
|
AStringGrid.Cells[1, i + AStringGrid.FixedRows] := '';
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF USE_LISTVIEW}
|
|
// Clear the EXIF fields from the specified ImageEnIO object and in the specified listview
|
|
procedure ClearEXIFFields(AListView: TListview;
|
|
AImageEnIO: TImageEnIO);
|
|
var
|
|
i: integer;
|
|
begin
|
|
AImageEnIO.Params.EXIF_HasEXIFData := False;
|
|
for i := low(EXIF) to high(EXIF) do
|
|
AListView.Items.Item[i].SubItems[0] := '';
|
|
end;
|
|
{$ENDIF}
|
|
|
|
// returns some common EXIF fields: EXIF_Model, EXIF_ExposureTime, EXIF_Flash
|
|
function GetUsefulEXIFFields(sFilename : string;
|
|
AnImageEnIO : TImageENIO;
|
|
var sCameraModel : string;
|
|
var sExposureTime : string;
|
|
var sFlashMode : string
|
|
) : boolean;
|
|
var
|
|
sModel: string;
|
|
sMake: string;
|
|
begin
|
|
result := false;
|
|
if EXIFCompatibleFile(sFilename) then
|
|
try
|
|
AnImageEnIO.paramsfromfile(sFilename);
|
|
|
|
if AnImageEnIO.params.EXIF_HasEXIFData = false then exit;
|
|
|
|
sMake := RemoveNull(AnImageEnIO.params.EXIF_Make);
|
|
sModel := RemoveNull(AnImageEnIO.params.EXIF_Model);
|
|
|
|
// sometimes EXIF_Model already includes the make
|
|
if (pos(' ', sMake) = 0) and
|
|
(pos(uppercase(sMake), uppercase(sModel)) = 0) then
|
|
sCameraModel := TrimLeft(TrimRight(sMake + ' ' + sModel))
|
|
else
|
|
sCameraModel := sModel;
|
|
|
|
sExposureTime := ExposureToString(AnImageEnIO.params.EXIF_ExposureTime);
|
|
|
|
sFlashMode := FlashModeToString(AnImageEnIO.params.EXIF_Flash);
|
|
|
|
result := (sCameraModel <> '') or (sExposureTime <> '');
|
|
except
|
|
// ERROR
|
|
end;
|
|
end;
|
|
|
|
// Returns true is sText contains an exif const such as %EXIF-User-Comment%
|
|
function ContainsExifField(const sText: string): Boolean;
|
|
begin
|
|
Result := Pos(uppercase(Exif_Field_As_Text_Prefix), uppercase(sText)) > 0;
|
|
end;
|
|
|
|
// Replace any exif consts in sText with the actual values
|
|
// bSampleOnly : if we are just showing the kind of text we might output, returns example text rather than ''
|
|
function ReplaceExifFields(const sText: string; AnImageEnIO: TImageEnIO; sFilename: string; bSampleOnly: Boolean = False): string;
|
|
var
|
|
i: Integer;
|
|
bValid: Boolean;
|
|
sValue: string;
|
|
begin
|
|
Result := sText;
|
|
if ContainsExifField(sText) = False then Exit;
|
|
|
|
bValid := False;
|
|
if EXIFCompatibleFile(sFilename) then
|
|
try
|
|
AnImageEnIO.paramsfromfile(sFilename);
|
|
bValid := AnImageEnIO.params.EXIF_HasEXIFData;
|
|
except
|
|
// ERROR
|
|
end;
|
|
|
|
// NOTE : THIS WILL BE SLOW!!!
|
|
for i := 0 to high(EXIF) do
|
|
begin
|
|
if bValid then
|
|
sValue := GetEXIFField(AnImageEnIO, I)
|
|
else
|
|
sValue := '';
|
|
|
|
if bSampleOnly and (sValue = '') then
|
|
sValue := 'Sample ' + Exif[I].Description;
|
|
|
|
Result := StringReplace(result, Exif[i].FieldAsTextName, sValue, [rfReplaceAll, rfIgnoreCase]);
|
|
end;
|
|
end;
|
|
|
|
// Get a list of all EXIF consts
|
|
procedure GetAllExifFields(ssDest: TStrings; bClearList: Boolean);
|
|
var
|
|
i: integer;
|
|
begin
|
|
if bClearList then ssDest.Clear;
|
|
|
|
// fill the fields with the EXIF property names
|
|
for i := 0 to high(EXIF) do
|
|
ssDest.Add(Exif[i].FieldAsTextName);
|
|
end;
|
|
|
|
{ EXIF_Item }
|
|
function EXIF_Item.GetFieldAsTextName: string;
|
|
begin
|
|
Result := Exif_Field_As_Text_Prefix + StringReplace(Description, ' ', '-', [rfReplaceAll]) +
|
|
Exif_Field_As_Text_Suffix;
|
|
end;
|
|
|
|
// return the GPS fields from the exif fields
|
|
function ExifGPSData(sFilename: string;
|
|
AnImageEnIO: TImageEnIO;
|
|
out GPSLatitudeDegrees: Double;
|
|
out GPSLongitudeDegrees: Double
|
|
): Boolean;
|
|
begin
|
|
result := False;
|
|
GPSLatitudeDegrees := 0;
|
|
GPSLongitudeDegrees := 0;
|
|
|
|
if EXIFCompatibleFile(sFilename) then
|
|
try
|
|
// use get params from file to fill the _ImageEnIO with the EXIF data
|
|
AnImageEnIO.paramsfromfile(sFilename);
|
|
|
|
if AnImageEnIO.params.EXIF_HasEXIFData then
|
|
begin
|
|
GPSLatitudeDegrees := AnImageEnIO.Params.EXIF_GPSLatitude;
|
|
GPSLongitudeDegrees := AnImageEnIO.Params.EXIF_GPSLongitude;
|
|
end;
|
|
|
|
Result := (GPSLatitudeDegrees <> 0) or (GPSLongitudeDegrees <> 0);
|
|
except
|
|
// ERROR
|
|
end;
|
|
end;
|
|
|
|
// reformat an EXIF date string using the localized date settings (shortdate)
|
|
function ReformatEXIFDateTime(sEXIFDateTime: string): string;
|
|
var
|
|
ADateTime: TDateTime;
|
|
begin
|
|
result := '';
|
|
ADateTime := EXIFDateToDateTime(sEXIFDateTime);
|
|
if ADateTime > 0 then
|
|
result := DateTimeToStr(ADateTime);
|
|
end;
|
|
|
|
{$endif}
|
|
|
|
{!!
|
|
<FS>iexEXIFRoutines
|
|
|
|
<FN>iexEXIFRoutines.pas provides helper functions for working with the EXIF data held 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.
|
|
|
|
!!}
|
|
|
|
end. |