BSOne.SFC/EM.Lib/ImageEn_SRC/Source/Legacy/iexEXIFRoutines.pas

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.