(*
' *************************************************************************
' * Script name:
' * Edit Lens Info
' * Version: 1.2
' *
' * Description:
' * Allows the user to update the lens metadata for selected thumbnails
' *
' * Version History:
' * IDimager;
' * 1.0 Initial version
' * 1.1 The script now also write Edif Tag 0xA434 (LensModel)
' * 1.2 Added progress
' *
' *************************************************************************/
*)
var
AFNumberBox: TvxTextBox;
AFocalLengthBox: TvxTextBox;
ALensInfoBox: TvxTextBox;
var
gFNumber: Double;
gFocalLength: Double;
gLensInfo: WideString;
function IsRational(AVal: WideString): Boolean;
var
ALen, i: Integer;
begin
// a rational exists of numbers or a single slash (e.g. 2800/1000)...
// NOTE: we'll also accept spaces because some tools write it (falsely) as 2800 / 1000
ALen := Length(AVal);
result := False;
if ALen = 0 then exit;
for i := 1 to ALen do
begin
if (AVal[i] <> '0') and
(AVal[i] <> '1') and
(AVal[i] <> '2') and
(AVal[i] <> '3') and
(AVal[i] <> '4') and
(AVal[i] <> '5') and
(AVal[i] <> '6') and
(AVal[i] <> '7') and
(AVal[i] <> '8') and
(AVal[i] <> '9') and
(AVal[i] <> '-') and
(AVal[i] <> '/') and
(AVal[i] <> ' ')
then
exit;
end;
result := True;
end;
function XMPRationalStringToDouble(AVal: WideString): Double;
var
ANumStr: WideString;
begin
if IsRational(Trim(AVal)) then
begin
ANumStr := FormatRationalToDecimal(AVal, '%d' + WideString(DecimalSeparator) + '%s', 10000000);
try
result := StrToFloat(ANumStr);
except
result := 0
end;
end
else
result := 0;
end;
function DoubleToXMPRationalString(AVal: Double): WideString;
const
cFactor = 1000000;
begin
result := IntToStr(Trunc(AVal * cFactor)) + '/' + IntToStr(cFactor);
end;
procedure HandleImage(AImage: TImageItem);
var
ATif: TTif;
ATag: TTifTag;
AXmp: TXMP;
AFNumber: TMacroParam;
AFLength: TMacroParam;
ALensModel: TMacroParam;
ACanUpdateExif, ASaveTif: Boolean;
begin
ASaveTif := False;
ACanUpdateExif := AImage.CanUpdateExif;
AXmp := TXMP.Create(False);
ATif := TTif.Create(nil);
try
if ACanUpdateExif then
begin
// load the exif
ATif.FileName := AImage.ExifFileName;
ATif.Load(True, False);
end;
PublicCatalog.LoadXMPForImage(AImage, AXmp, PublicOptions.CachedXMP);
AFNumber := AXmp.QuickSetProperty('http://ns.adobe.com/exif/1.0/', 'exif:FNumber', DoubleToXMPRationalString(gFNumber));
if Assigned(AFNumber) then
begin
if ACanUpdateExif then
begin
ATag := ATif.ExifIFD.FindTag($829D); // FNumber
if Assigned(ATag) then
begin
ATag.Value := AFNumber.StrContent;
ASaveTif := True;
end;
end;
end;
AFLength := AXmp.QuickSetProperty('http://ns.adobe.com/exif/1.0/', 'exif:FocalLength', DoubleToXMPRationalString(gFocalLength));
if Assigned(AFLength) then
begin
if ACanUpdateExif then
begin
ATag := ATif.ExifIFD.FindTag($920A); // FocalLength
if Assigned(ATag) then
begin
ATag.Value := AFLength.StrContent;
ASaveTif := True;
end;
end;
end;
ALensmodel := AXmp.QuickSetProperty('http://ns.adobe.com/exif/1.0/aux/', 'aux:Lens', gLensInfo);
AXmp.QuickSetProperty('http://cipa.jp/exif/1.0/', 'exifEX:LensModel', gLensInfo);
if Assigned(ALensModel) then
begin
if ACanUpdateExif then
begin
ATag := ATif.ExifIFD.FindTag($A434); // LensModel
if Assigned(ATag) then
begin
ATag.Value := ALensModel.StrContent;
ASaveTif := True;
end;
end;
end;
PublicCatalog.SaveXMPForImage(AImage, AXmp, PublicOptions.CachedXMP);
if ASaveTif then
ATif.Save;
except
ATif.Free;
AXmp.Free;
end;
end;
function CreateForm: TvxSceneForm;
const
cSpacing = 20;
var
ARoot: TvxVisualObject;
ALabel: TvxLabel;
ATextBox: TvxTextBox;
begin
result := TvxSceneForm.Create(nil);
result.Caption := UTF8Encode('Edit Lens Info');
result.Position := poScreenCenter;
result.Height := 200 * result.DPIFactor;
ARoot := result.Root;
ALabel := TvxLabel.Create(ARoot);
ALabel.Text := 'F-Number';
ALabel.TextAlign := vgTextAlignNear;
ALabel.Padding.Left := 10;
ALabel.Padding.Top := cSpacing;
ALabel.Align := vaTop;
ARoot.AddObject(ALabel);
ATextBox := TvxTextBox.Create(ARoot)
ATextBox.Padding.Left := 13;
ATextBox.Padding.Right := 240;
ATextBox.Padding.Top := 3;
ATextBox.Align := vaTop;
ATextBox.Text := '';
ARoot.AddObject(ATextBox);
AFNumberBox := ATextBox;
ALabel := TvxLabel.Create(ARoot);
ALabel.Text := 'Focal Length (mm)';
ALabel.TextAlign := vgTextAlignNear;
ALabel.Padding.Left := 10;
ALabel.Padding.Top := cSpacing;
ALabel.Align := vaTop;
ARoot.AddObject(ALabel);
ATextBox := TvxTextBox.Create(ARoot)
ATextBox.Padding.Left := 13;
ATextBox.Padding.Right := 240;
ATextBox.Padding.Top := 3;
ATextBox.Align := vaTop;
ATextBox.Text := '';
ARoot.AddObject(ATextBox);
AFocalLengthBox := ATextBox;
ALabel := TvxLabel.Create(ARoot);
ALabel.Text := 'Lens Information';
ALabel.TextAlign := vgTextAlignNear;
ALabel.Padding.Left := 10;
ALabel.Padding.Top := cSpacing;
ALabel.Align := vaTop;
ARoot.AddObject(ALabel);
ATextBox := TvxTextBox.Create(ARoot)
ATextBox.Padding.Left := 13;
ATextBox.Padding.Right := 13;
ATextBox.Padding.Top := 3;
ATextBox.Align := vaTop;
ATextBox.Text := '';
ARoot.AddObject(ATextBox);
ALensInfoBox := ATextBox;
end;
procedure ReadDefaults;
var
AImage: TImageItem;
AXmp: TXMP;
begin
AImage := selected.Items[0];
AXmp := TXMP.Create(False);
try
PublicCatalog.LoadXMPForImage(AImage, AXmp, PublicOptions.CachedXMP);
AParam := AXmp.FindDesignProperty('http://ns.adobe.com/exif/1.0/', 'exif:FNumber');
if Assigned(AParam) then
AFNumberBox.Text := FloatToStr(XMPRationalStringToDouble(AParam.StrContent));
AParam := AXmp.FindDesignProperty('http://ns.adobe.com/exif/1.0/', 'exif:FocalLength');
if Assigned(AParam) then
AFocalLengthBox.Text := FloatToStr(XMPRationalStringToDouble(AParam.StrContent));
AParam := AXmp.FindDesignProperty('http://ns.adobe.com/exif/1.0/aux/', 'aux:Lens');
if Assigned(AParam) then
ALensInfoBox.Text := AParam.StrContent
else
begin
AParam := AXmp.FindDesignProperty('http://cipa.jp/exif/1.0/', 'exifEX:LensModel');
if Assigned(AParam) then
ALensInfoBox.Text := AParam.StrContent;
end;
finally
AXmp.Free;
end;
end;
var
AForm: TvxSceneForm;
AGo: Boolean;
i: Integer;
APro: TxomProgress;
AImg: TImageItem;
begin
if Selected.Count = 0 then
begin
Say('Please select at least one thumbnail');
exit;
end;
AForm := CreateForm;
try
ReadDefaults;
AForm.PrepareModal([mbOK, mbCancel]);
AForm.ShowModal;
if AForm.ModalResult = mrOk then
begin
AGo := True;
if not IsValidNumberString(AFNumberBox.Text, False, DecimalSeparator) then
begin
Say('No valid "F-Number" value entered');
AGo := False;
end;
if not IsValidNumberString(AFocalLengthBox.Text, False, DecimalSeparator) then
begin
Say('No valid "Focal Length" value entered');
AGo := False;
end;
if AGo then
begin
gFNumber := StrToFloat(AFNumberBox.Text);
gFocalLength := StrToFloat(AFocalLengthBox.Text);
gLensInfo := ALensInfoBox.Text;
if AskYN(
'Are you sure you want to change the lens metadata for the ' + IntToStr(Selected.Count) + ' selected file(s)?' + CrLf +
'' + CrLf +
'F-Number: F' + FloatToStr(gFNumber) + CrLf +
'Focal Length: ' + FloatToStr(gFocalLength) + 'mm' + CrLf +
'Lens Information: ' + gLensInfo
)
then
begin
APro := TxomProgress.Create(nil);
try
APro.Max := Selected.Count;
APro.Pos := 0;
APro.Caption := 'Edit Lens Info';
for i := 0 to Selected.Count - 1 do
begin
AImg := Selected.Items[i];
APro.Pos := i + 1;
APro.ProgressText := AImg.FileNameOnScreen(50, True);
HandleImage(AImg);
end;
finally
APro.Free;
end;
end;
end;
end;
finally
AForm.Free;
end;
end;
|