const
cShowAll = 0;
cShowInter = 1;
cShowDiff = 2;
var
AGrid: TvxStringGrid;
row: Integer;
ATabList: TStringList;
tabcount: Integer;
activetab: Integer;
show: Integer;
showAllButton: TvxRectangle;
showInterButton: TvxRectangle;
showDiffButton: TvxRectangle;
function TabButtonAtIndex(AIndex: Integer): TvxRectangle;
begin
result := ATabList.Objects[AIndex];
end;
function IndexedDataPointerFromString(AStr: WideString; AIndex: Integer): TTntStringList;
var
ASl: TTntStringList;
begin
ASl := TTntStringList.Create;
try
ASl.CommaText := AStr;
result := StrToPtrInt(ASl.Strings[AIndex])
finally
ASl.Free;
end;
end;
function FileDataPointerFromString(AStr: WideString): TTntStringList;
begin
result := IndexedDataPointerFromString(AStr, 0);
end;
function CatDataPointerFromString(AStr: WideString): TTntStringList;
begin
result := IndexedDataPointerFromString(AStr, 1);
end;
function InterDataPointerFromString(AStr: WideString): TTntStringList;
begin
result := IndexedDataPointerFromString(AStr, 2);
end;
function DiffDataPointerFromString(AStr: WideString): TTntStringList;
begin
result := IndexedDataPointerFromString(AStr, 3);
end;
function TabFileDataAtIndex(AIndex: Integer): TTntStringList;
begin
result := StrToPtrInt(FileDataPointerFromString(TvxRectangle(TabButtonAtIndex(AIndex)).TagString));
end;
function TabCatDataAtIndex(AIndex: Integer): TTntStringList;
begin
result := StrToPtrInt(CatDataPointerFromString(TvxRectangle(TabButtonAtIndex(AIndex)).TagString));
end;
function TabInterDataAtIndex(AIndex: Integer): TTntStringList;
begin
result := StrToPtrInt(InterDataPointerFromString(TvxRectangle(TabButtonAtIndex(AIndex)).TagString));
end;
function TabDiffDataAtIndex(AIndex: Integer): TTntStringList;
begin
result := StrToPtrInt(DiffDataPointerFromString(TvxRectangle(TabButtonAtIndex(AIndex)).TagString));
end;
function TabImageAtIndex(AIndex: Integer): TImageItem;
begin
result := TImageItem(TvxRectangle(TabButtonAtIndex(AIndex)).TagObject);
end;
function ActiveTabButton: TvxRectangle;
begin
result := TabButtonAtIndex(activetab);
end;
function ActiveTabFileData: TTntStringList;
begin
result := TabFileDataAtIndex(activetab);
end;
function ActiveTabCatData: TTntStringList;
begin
result := TabCatDataAtIndex(activetab);
end;
function ActiveTabInterData: TTntStringList;
begin
result := TabInterDataAtIndex(activetab);
end;
function ActiveTabDiffData: TTntStringList;
begin
result := TabDiffDataAtIndex(activetab);
end;
function ActiveTabImage: TImageItem;
begin
result := TabImageAtIndex(activetab);
end;
procedure DumpXmp(AImg: TImageItem; AGrid: TvxStringGrid; AFileSl, ACatSl, AInterSl, ADiffSl: TTntStrings);
var
i, AIdx: Integer;
AFileXmp, ACatXmp, ATempXmp: TXMP;
ASize: Int64;
ALeadSl: TTntStringList;
ACatItem: TCatalogItem;
begin
ACatItem := TCatalogItem.Create(nil);
ACatXmp := TXMP.Create(False);
AFileXmp := TXMP.Create(False);
ATempXmp := TXMP.Create(False);
try
PublicCatalog.FindItemCombinedByGUID(AImg.GUID, ACatItem);
AFileSl.Clear;
ACatSl.Clear;
AInterSl.Clear;
ADiffSl.Clear;
AFileXmp.Load(AImg.XMPFileName, AImg.ExifFileName, False);
AFileXmp.DumpToStrings(AFileSl);
PublicCatalog.LoadXMPForImage(AImg, ACatXmp, PublicOptions.CachedXMP);
ACatXmp.DumpToStrings(ACatSl);
ATempXmp.AppendXMP(AFileXmp);
ATempXmp.IntersectWithXMP(ACatXmp);
ATempXmp.DumpToStrings(AInterSl);
ACatXmp.DifferenceWithXMP(AFileXmp);
ACatXmp.DumpToStrings(ADiffSl);
finally
ATempXmp.Free;
AFileXmp.Free;
ACatXmp.Free;
end;
AGrid.Cells[0, row] := 'FileName';
AGrid.Cells[1, row] := WideExtractFileName(AImg.FileName);
AGrid.Cells[2, row] := WideExtractFileName(ACatItem.FileName);
Inc(row);
AGrid.Cells[0, row] := 'FilePath';
AGrid.Cells[1, row] := AImg.FileName;
AGrid.Cells[2, row] := ACatItem.FileName;
Inc(row);
AGrid.Cells[0, row] := 'FileSize';
ASize := SizeOfFile(AImg.FileName);
AGrid.Cells[1, row] := IntToStr(ASize) + ' bytes (' + SizeString(ASize) + ')';
ASize := ACatItem.FileSize;
AGrid.Cells[2, row] := IntToStr(ASize) + ' bytes (' + SizeString(ASize) + ')';
Inc(row);
AGrid.Cells[0, row] := 'FileStamp';
AGrid.Cells[1, row] := DateTimeToStr(FileStamp(AImg.FileName));
AGrid.Cells[2, row] := DateTimeToStr(ACatItem.FileStamp);
Inc(row);
AGrid.Cells[0, row] := '';
AGrid.Cells[1, row] := '';
AGrid.Cells[2, row] := '';
if show = cShowInter then
ALeadSl := AInterSl
else if show = cShowDiff then
ALeadSl := ADiffSl
else
ALeadSl := AFileSl;
for i := 0 to ALeadSl.Count - 1 do
begin
if ALeadSl = AFileSl then
AIdx := i
else
AIdx := AFileSl.IndexOfName(ALeadSl.Names[i]);
if AIdx <> -1 then
begin
Inc(row);
AGrid.Cells[0, row] := AFileSl.Names[AIdx];
AGrid.Cells[1, row] := AFileSl.ValueFromIndex[AIdx];
AIdx := ACatSl.IndexOfName(ALeadSl.Names[i]);
if AIdx <> -1 then
AGrid.Cells[2, row] := ACatSl.ValueFromIndex[AIdx]
else
AGrid.Cells[2, row] := '';
end;
end;
if ALeadSl = AFileSl then
begin
for i := 0 to ACatSl.Count - 1 do
begin
AIdx := ALeadSl.IndexOfName(ACatSl.Names[i]);
if AIdx = -1 then
begin
Inc(row);
AGrid.Cells[0, row] := ACatSl.Names[i];
AGrid.Cells[1, row] := '';
AGrid.Cells[2, row] := ACatSl.ValueFromIndex[i]
end;
end;
end;
Inc(row);
AGrid.Cells[0, row] := '';
AGrid.Cells[1, row] := '';
AGrid.Cells[2, row] := '';
ACatItem.Free;
end;
procedure DumpGridToStringList(ASl: TTntStringList);
var
i: Integer;
ALine: TTntStringList;
begin
// add header
ALine := TTntStringList.Create;
ALine.Add('Tag');
ALine.Add('In File');
ALine.Add('In Catalog');
ASl.Add(ALine.CommaText);
ALine.Free;
for i := 0 to AGrid.RowCount - 1 do
begin
ALine := TTntStringList.Create;
ALine.Add(AGrid.Cells[0, i]);
ALine.Add(AGrid.Cells[1, i]);
ALine.Add(AGrid.Cells[2, i]);
ASl.Add(ALine.CommaText);
ALine.Free;
end;
end;
function CheckVersion41: Boolean;
var
ATokens: TTntStringList;
begin
result := False;
ATokens := TTntStringList.Create;
Tokenize(xomProductVersion, '.', ATokens);
if ATokens.Count = 4 then
begin
if (IntToStr(ATokens.Strings[0]) > 4) or
(
(IntToStr(ATokens.Strings[0]) = 4) and
(IntToStr(ATokens.Strings[1]) >= 1)
)
then
result := True;
end;
ATokens.Free;
end;
procedure CheckButtonShowState;
begin
showAllButton.Fill.Style := iif(show = cShowAll, vgBrushSolid, vgBrushNone);
showInterButton.Fill.Style := iif(show = cShowInter, vgBrushSolid, vgBrushNone);
showDiffButton.Fill.Style := iif(show = cShowDiff, vgBrushSolid, vgBrushNone);
end;
procedure ActivateTab(ATabIndex: Integer);
begin
TvxRectangle(ActiveTabButton).Fill.Style := vgBrushNone;
// dump the first selected file to the grid
AGrid.RowCount := 0;
row := 0;
activetab := ATabIndex;
DumpXmp(ActiveTabImage, AGrid, ActiveTabFileData, ActiveTabCatData, ActiveTabInterData, ActiveTabDiffData);
TvxRectangle(ActiveTabButton).Fill.Style := vgBrushSolid;
end;
procedure _SaveToFileClick(Sender: TObject);
var
ASl: TTntStringList;
begin
//SaveDialog.FileName := WideChangeFileExt(TImageItem(ActiveTabImage).FileNameOnly, '.txt');
SaveDialog.FileName := TImageItem(ActiveTabImage).FileNameOnly + '.txt';
if SaveDialog.Execute then
begin
ASl := TTntStringList.Create;
try
DumpGridToStringList(ASl);
ASl.SaveToFile(SaveDialog.FileName);
finally
ASl.Free;
end;
Say('Saved as ' + SaveDialog.FileName);
end;
end;
procedure _ShowAllClick(Sender: TObject);
begin
show := cShowAll;
ActivateTab(activetab);
CheckButtonShowState;
end;
procedure _ShowInterClick(Sender: TObject);
begin
show := cShowInter;
ActivateTab(activetab);
CheckButtonShowState;
end;
procedure _ShowDiffClick(Sender: TObject);
begin
show := cShowDiff;
ActivateTab(activetab);
CheckButtonShowState;
end;
procedure _TabButtonClick(Sender: TObject);
var
ATabButton: TvxRectangle;
begin
ATabButton := TvxRectangle(Sender);
ActivateTab(ATabButton.Tag);
end;
function CreateTab(AImg: TImageItem; ATabBar: TvxScrollBox): TvxRectangle;
var
ATabButton: TvxRectangle;
ALabel: TvxLabel;
begin
ATabButton := TvxRectangle.Create(ATabBar);
ATabButton.Align := vaLeft;
ATabButton.Padding.Rect := vgRect(0, 5, 0, 5);
ALabel := TvxLabel.Create(ATabButton);
ALabel.Align := vaClient;
ALabel.Text := AImg.FileNameOnly;
ATabButton.AddObject(ALabel);
ATabButton.xRadius := 5;
ATabButton.yRadius := ATabButton.xRadius;
ATabButton.Corners := [vgCornerTopLeft, vgCornerTopRight];
ATabButton.Fill.Color := '#80' + MidStr(GUIDesign.HighlightFill.Color, 4, Length(GUIDesign.HighlightFill.Color));
ATabButton.Fill.Style := vgBrushNone;
ATabButton.Stroke.Color := GUIDesign.DarkFill.Color;
ATabButton.Stroke.Style := vgBrushSolid;
ATabButton.Width := vgTextWidth(ALabel.Text, ALabel.Font, vgNormal) + 16;
ATabButton.OnClick := '_TabButtonClick';
ATabButton.TagString := PtrIntToStr(TTntStringList.Create) + ',' +
PtrIntToStr(TTntStringList.Create) + ',' +
PtrIntToStr(TTntStringList.Create) + ',' +
PtrIntToStr(TTntStringList.Create) + ',' +
'';
ATabButton.TagObject := AImg;
ATabButton.Tag := tabcount;
Inc(tabcount);
ATabBar.AddObject(ATabButton);
result := ATabButton;
end;
function CreateOptionButton(AParent: TvxObject; AText: WideString; AOnClick: WideString): TvxVisualObject;
var
ALabel: TvxLabel;
begin
result := TvxRectangle.Create(AParent)
result.Align := vaLeft;
result.Width := 110;
result.Padding.Rect := vxRect(1, 8, 5, 8);
result.OnClick := AOnClick;
result.xRadius := 5;
result.yRadius := result.xRadius;
AParent.AddObject(result);
result.Fill.Color := '#80' + MidStr(GUIDesign.HighlightFill.Color, 4, Length(GUIDesign.HighlightFill.Color));
result.Fill.Style := vgBrushNone;
result.Stroke.Color := '#40' + MidStr(GUIDesign.MidDarkFontFill.Color, 4, Length(GUIDesign.MidDarkFontFill.Color));
result.Stroke.Style := vgBrushSolid;
ALabel := TvxLabel.Create(result);
ALabel.Align := vaClient;
ALabel.text := AText;
result.AddObject(ALabel);
end;
// MAIN
var
i: Integer;
AForm: TvxSceneForm;
ACol: TvxStringColumn;
AButton: TvxButton;
ATabBar: TvxScrollBox;
ATab: TvxRectangle;
begin
if not CheckVersion41 then
begin
Say('This script requires Photo Supreme 4.1 or higher');
exit;
end;
if Selected.Count = 0 then
begin
Say ('No image selected');
exit;
end;
AForm := TvxSceneForm.Create(nil);
if Selected.Count = 1 then
AForm.Caption := UTF8Encode(WideFormat('Compare XMP [%s]', [WideExtractFileName(Selected.Items[0].ExifFileName)]))
else
AForm.Caption := 'Compare XMP: ' + IntToStr(Selected.Count) + ' images';
AForm.Width := 900 * AForm.DPIFactor;
AForm.Height := Trunc(Screen.Height * 0.6);
AForm.BorderStyle := bsSizeable;
ATabBar := TvxScrollBox.Create(AForm.Root);
ATabBar.Height := 40;
ATabBar.Align := vaTop;
ATabBar.UseSmallScrollBars := True;
AForm.Root.AddObject(ATabBar);
AGrid := TvxStringGrid.Create(AForm.Root);
AForm.Root.AddObject(AGrid);
AGrid.Align := vaClient;
AGrid.RowCount := 0;
ACol := TvxStringColumn.Create(AGrid);
ACol.Header := 'Tag';
ACol.Width := 200;
AGrid.AddObject(ACol);
ACol := TvxStringColumn.Create(AGrid);
ACol.Header := 'In File';
ACol.Width := 300;
AGrid.AddObject(ACol);
ACol := TvxStringColumn.Create(AGrid);
ACol.Header := 'In Catalog';
ACol.Width := 300;
AGrid.AddObject(ACol);
ATabList := TStringList.Create;
for i := 0 to Selected.Count - 1 do
begin
ATab := CreateTab(Selected.Items[i], ATabBar);
ATabList.AddObject(Selected.Items[i].GUID, ATab);
end;
tabcount := 0;
activetab := 0;
show := cShowAll;
ActivateTab(activetab);
AForm.PrepareModal([mbOK]);
showAllButton := CreateOptionButton(AForm.ModalPanel, 'Show All', '_ShowAllClick');
showInterButton := CreateOptionButton(AForm.ModalPanel, 'Show Identical', '_ShowInterClick');
showDiffButton := CreateOptionButton(AForm.ModalPanel, 'Show Differences', '_ShowDiffClick');
CheckButtonShowState;
AButton := TvxButton.Create(AForm.ModalPanel)
AButton.Text := 'Save as text file';
AButton.Align := vaLeft;
AButton.Width := 110;
AButton.Padding.Rect := vxRect(25, 8, 5, 8);
AButton.OnClick := '_SaveToFileClick';
AForm.ModalPanel.AddObject(AButton);
AForm.ShowModal;
for i := 0 to ATabList.Count - 1 do
begin
TTntStringList(TabFileDataAtIndex(i)).Free;
TTntStringList(TabCatDataAtIndex(i)).Free;
TTntStringList(TabInterDataAtIndex(i)).Free;
TTntStringList(TabDiffDataAtIndex(i)).Free;
end;
ATabList.Free;
AForm.Free;
end;
|