Resource

Resource Basics

Resource Name Full Exif Dump
Resource Version 2.0
Category Metadata
Downloads 3471
Release Date 4/24/2018 4:59:03 PM
 

Resource Details

Description Full Exif Dump will dump the full metadata as found in Exif metadata of one or more selected images. This dump includes technical Exif data, IPTC data, as well as XMP data.
Installation Instructions Download the script to your hard drive
Usage Instructions 1. Select one or more thumbs
2. Open Tools -> Scripter
3. Load the downloaded script
4. Run the script with the Run button
Changes in this version 2.0; Implemented tabs for multiple selected files
1.3; When a sidecar XMP file exists then that is loaded as the XMP to display
1.2; Added a save text button
1.1; Dump XMP details as separate strings
1.03; display the data in a grid table.
1.01; fix for error while parsing incorrect Exif metadata
Special Requirements 4.2 or higher
 

Author Information

Author Name IDimager Support
 

Available Attachments

Attachment #1 FullExifDump.png
 

Script

{
   Full Exif Dump will dump the full metadata as found in Exif. This
   could contain: technical Exif data, IPTC data, as well as XMP data

   Version 2.0; Author: IDimager Systems
                Date: 27 jun 2024
                Implemented tabs for multiple selected files

   Version 1.3; Author: IDimager Systems
                Date: 17 dec 2021
                When a sidecar XMP file exists then that is loaded as the XMP to display

   Version 1.2; Author: IDimager Systems
                Date: 18 oct 2018
                Added a save option

   Version 1.1; Author: IDimager Systems
                Date: 16 oct 2018
                Dump XMP details as separate strings

   Version 1.0; Author: IDimager Systems
                Date: 24 aug 2014

}

var
  AGrid: TvxStringGrid;
  row: Integer;

  ATabList: TStringList;
  tabcount: Integer;
  activetab: Integer;

  function TabButtonAtIndex(AIndex: Integer): TvxRectangle;
  begin
    result := ATabList.Objects[AIndex];
  end;

  function TabDataAtIndex(AIndex: Integer): TTntStringList;
  begin
    result := StrToPtrInt(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 ActiveTabData: TTntStringList;
  begin
    result := TabDataAtIndex(activetab);
  end;

  function ActiveTabImage: TImageItem;
  begin
    result := TabImageAtIndex(activetab);
  end;

  procedure DumpExif(AImg: TImageItem; AGrid: TvxStringGrid; ADataSl: TTntStrings);
  var
    ATif: TTif;
    i: Integer;
    AXmp: TXMP;
    AXMPSidecarFileName: WideString;
    ASize: Int64;
  begin
    ATif := TTif.Create(nil);
    ATif.FileName := AImg.ExifFileName;
    ATif.Load(True, False);

    try
      ATif.DumpExif(ADataSl, [itBase, itExif, itIPTC, itInterExif, itGps, itMakerNotes], True);
    except
      ADataSl.Add('Error during reading of Exif');
    end;

    // if there's an XMP sidecar file then load that as the XMP to display
    AXMPSidecarFileName := WideChangeFileExt(AImg.ExifFileName, '.xmp');
    if WideFileExists(AXMPSidecarFileName) then
      ATif.XMPData.LoadFromFile(AXMPSidecarFileName);

    if IsAppVersion(4, 3, 0) then
    begin
      if ATif.XMPData.Count > 0 then
      begin
        AXmp := TXMP.Create(False);
        try
          AXmp.LoadFromStrings(ATif.XMPData, '');
          ADataSl.Add('=');
          AXmp.DumpToStrings(ADataSl);
        finally
          AXmp.Free;
        end;
      end;
    end;

    AGrid.Cells[0, row] := 'FileName';
    AGrid.Cells[1, row] := WideExtractFileName(ATif.FileName);
    Inc(row);
    AGrid.Cells[0, row] := 'FilePath';
    AGrid.Cells[1, row] := ATif.FileName;
    Inc(row);
    ASize := SizeOfFile(ATif.FileName);
    AGrid.Cells[0, row] := 'FileSize';
    AGrid.Cells[1, row] := IntToStr(ASize) + ' bytes (' + SizeString(ASize) + ')';
    Inc(row);
    AGrid.Cells[0, row] := 'FileStamp';
    AGrid.Cells[1, row] := FileStamp(ATif.FileName);
    Inc(row);

    Inc(row);
    for i := 0 to ADataSl.Count - 1 do
    begin
      AGrid.Cells[0, row] := ADataSl.Names[i];
      AGrid.Cells[1, row] := ADataSl.ValueFromIndex[i];
      Inc(row);
    end;

    if not IsAppVersion(4, 3, 0) then
    begin
      if ATif.XMPData.Count > 0 then
      begin
        Inc(row);
        AGrid.Cells[0, row] := 'eXtensible Metadata Platform (XMP)';
        Inc(row);
        for i := 0 to ATif.XMPData.Count -1 do
        begin
          //AGrid.Cells[0, row] := ATif.XMPData.Strings[i];
          AGrid.Cells[1, row] := ATif.XMPData.Strings[i];
          Inc(row);
        end;
      end;
    end;

    ATif.Free;
  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 ActivateTab(ATabIndex: Integer);
  begin
    TvxRectangle(ActiveTabButton).Fill.Style := vgBrushNone;

    // dump the first selected file to the grid
    AGrid.RowCount := 0;
    row := 0;
    activetab := ATabIndex;
    DumpExif(ActiveTabImage, AGrid, ActiveTabData);

    TvxRectangle(ActiveTabButton).Fill.Style := vgBrushSolid;
  end;

  procedure _SaveToFileClick(Sender: TObject);
  begin
    //SaveDialog.FileName := WideChangeFileExt(TImageItem(ActiveTabImage).FileNameOnly, '.txt');
    SaveDialog.FileName := TImageItem(ActiveTabImage).FileNameOnly + '.txt';
    if SaveDialog.Execute then
    begin
      TTntStringList(ActiveTabData).SaveToFile(SaveDialog.FileName);
      Say('Saved as ' + SaveDialog.FileName);
    end;
  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);
    ATabButton.TagObject := AImg;
    ATabButton.Tag := tabcount;
    Inc(tabcount);

    ATabBar.AddObject(ATabButton);

    result := ATabButton;
  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('Full Exif Dump  [%s]', [WideExtractFileName(Selected.Items[0].ExifFileName)]))
  else
    AForm.Caption := IntToStr(Selected.Count) + ' images';
  AForm.Width := 520 * 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 := 'Value';
  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;

  ActivateTab(activetab);

  AForm.PrepareModal([mbOK]);

  AButton := TvxButton.Create(AForm.ModalPanel)
  AButton.Text := 'Save as text file';
  AButton.Align := vaLeft;
  AButton.Width := 110;
  AButton.Padding.Rect := vxRect(5, 8, 5, 8);
  AButton.OnClick := '_SaveToFileClick';
  AForm.ModalPanel.AddObject(AButton);

  AForm.ShowModal;

  for i := 0 to ATabList.Count - 1 do
  begin
    TTntStringList(StrToPtrInt(TvxRectangle(ATabList.Objects[i]).TagString)).Free;
  end;

  ATabList.Free;

  AForm.Free;
end;