You've already forked lazarus-ccr
fpexif: Fix crash when writing big-endian file with thumbnail (see https://forum.lazarus.freepascal.org/index.php/topic,43714). Add button for changing EXIF date/time to MetadataViewer.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6776 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<CONFIG>
|
<CONFIG>
|
||||||
<ProjectOptions>
|
<ProjectOptions>
|
||||||
<Version Value="10"/>
|
<Version Value="11"/>
|
||||||
<PathDelim Value="\"/>
|
<PathDelim Value="\"/>
|
||||||
<General>
|
<General>
|
||||||
<SessionStorage Value="InProjectDir"/>
|
<SessionStorage Value="InProjectDir"/>
|
||||||
@ -18,9 +18,10 @@
|
|||||||
<Version Value="2"/>
|
<Version Value="2"/>
|
||||||
</PublishOptions>
|
</PublishOptions>
|
||||||
<RunParams>
|
<RunParams>
|
||||||
<local>
|
<FormatVersion Value="2"/>
|
||||||
<FormatVersion Value="1"/>
|
<Modes Count="1">
|
||||||
</local>
|
<Mode0 Name="default"/>
|
||||||
|
</Modes>
|
||||||
</RunParams>
|
</RunParams>
|
||||||
<RequiredPackages Count="2">
|
<RequiredPackages Count="2">
|
||||||
<Item1>
|
<Item1>
|
||||||
|
@ -8,7 +8,7 @@ object MainForm: TMainForm
|
|||||||
ClientWidth = 926
|
ClientWidth = 926
|
||||||
OnCreate = FormCreate
|
OnCreate = FormCreate
|
||||||
OnDestroy = FormDestroy
|
OnDestroy = FormDestroy
|
||||||
LCLVersion = '1.9.0.0'
|
LCLVersion = '2.1.0.0'
|
||||||
object ShellPanel: TPanel
|
object ShellPanel: TPanel
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 691
|
Height = 691
|
||||||
@ -112,7 +112,7 @@ object MainForm: TMainForm
|
|||||||
end
|
end
|
||||||
object PageControl1: TPageControl
|
object PageControl1: TPageControl
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 573
|
Height = 539
|
||||||
Top = 23
|
Top = 23
|
||||||
Width = 647
|
Width = 647
|
||||||
ActivePage = PgMetadata
|
ActivePage = PgMetadata
|
||||||
@ -122,11 +122,11 @@ object MainForm: TMainForm
|
|||||||
OnChange = PageControl1Change
|
OnChange = PageControl1Change
|
||||||
object PgMetadata: TTabSheet
|
object PgMetadata: TTabSheet
|
||||||
Caption = 'Meta data'
|
Caption = 'Meta data'
|
||||||
ClientHeight = 545
|
ClientHeight = 511
|
||||||
ClientWidth = 639
|
ClientWidth = 639
|
||||||
object TagListView: TListView
|
object TagListView: TListView
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 525
|
Height = 491
|
||||||
Top = 0
|
Top = 0
|
||||||
Width = 639
|
Width = 639
|
||||||
Align = alClient
|
Align = alClient
|
||||||
@ -158,7 +158,7 @@ object MainForm: TMainForm
|
|||||||
object Panel1: TPanel
|
object Panel1: TPanel
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 20
|
Height = 20
|
||||||
Top = 525
|
Top = 491
|
||||||
Width = 639
|
Width = 639
|
||||||
Align = alBottom
|
Align = alBottom
|
||||||
AutoSize = True
|
AutoSize = True
|
||||||
@ -201,7 +201,7 @@ object MainForm: TMainForm
|
|||||||
object Messages: TMemo
|
object Messages: TMemo
|
||||||
Left = 4
|
Left = 4
|
||||||
Height = 90
|
Height = 90
|
||||||
Top = 596
|
Top = 567
|
||||||
Width = 639
|
Width = 639
|
||||||
Align = alBottom
|
Align = alBottom
|
||||||
BorderSpacing.Left = 4
|
BorderSpacing.Left = 4
|
||||||
@ -212,11 +212,64 @@ object MainForm: TMainForm
|
|||||||
Cursor = crVSplit
|
Cursor = crVSplit
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 5
|
Height = 5
|
||||||
Top = 686
|
Top = 562
|
||||||
Width = 647
|
Width = 647
|
||||||
Align = alBottom
|
Align = alBottom
|
||||||
ResizeAnchor = akBottom
|
ResizeAnchor = akBottom
|
||||||
end
|
end
|
||||||
|
object DateTimePanel: TPanel
|
||||||
|
Left = 0
|
||||||
|
Height = 34
|
||||||
|
Top = 657
|
||||||
|
Width = 647
|
||||||
|
Align = alBottom
|
||||||
|
AutoSize = True
|
||||||
|
BevelOuter = bvNone
|
||||||
|
ClientHeight = 34
|
||||||
|
ClientWidth = 647
|
||||||
|
TabOrder = 4
|
||||||
|
object LblChangeDate: TLabel
|
||||||
|
AnchorSideLeft.Control = DateTimePanel
|
||||||
|
AnchorSideTop.Control = EdChangeDate
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 4
|
||||||
|
Height = 15
|
||||||
|
Top = 10
|
||||||
|
Width = 135
|
||||||
|
BorderSpacing.Left = 4
|
||||||
|
Caption = 'Change EXIF date/time to'
|
||||||
|
ParentColor = False
|
||||||
|
end
|
||||||
|
object EdChangeDate: TEdit
|
||||||
|
AnchorSideLeft.Control = LblChangeDate
|
||||||
|
AnchorSideLeft.Side = asrBottom
|
||||||
|
AnchorSideTop.Control = DateTimePanel
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 144
|
||||||
|
Height = 23
|
||||||
|
Top = 6
|
||||||
|
Width = 152
|
||||||
|
BorderSpacing.Left = 5
|
||||||
|
BorderSpacing.Bottom = 4
|
||||||
|
TabOrder = 0
|
||||||
|
end
|
||||||
|
object BtnChangeDate: TButton
|
||||||
|
AnchorSideLeft.Control = EdChangeDate
|
||||||
|
AnchorSideLeft.Side = asrBottom
|
||||||
|
AnchorSideTop.Control = EdChangeDate
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 304
|
||||||
|
Height = 25
|
||||||
|
Top = 5
|
||||||
|
Width = 66
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Left = 8
|
||||||
|
BorderSpacing.Bottom = 4
|
||||||
|
Caption = 'Execute'
|
||||||
|
OnClick = BtnChangeDateClick
|
||||||
|
TabOrder = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
object StatusBar1: TStatusBar
|
object StatusBar1: TStatusBar
|
||||||
Left = 0
|
Left = 0
|
||||||
|
@ -14,14 +14,18 @@ type
|
|||||||
{ TMainForm }
|
{ TMainForm }
|
||||||
|
|
||||||
TMainForm = class(TForm)
|
TMainForm = class(TForm)
|
||||||
|
BtnChangeDate: TButton;
|
||||||
CbDecodeMakerNotes: TCheckBox;
|
CbDecodeMakerNotes: TCheckBox;
|
||||||
|
EdChangeDate: TEdit;
|
||||||
FilenameInfo: TLabel;
|
FilenameInfo: TLabel;
|
||||||
Image: TImage;
|
Image: TImage;
|
||||||
|
LblChangeDate: TLabel;
|
||||||
Messages: TMemo;
|
Messages: TMemo;
|
||||||
PageControl1: TPageControl;
|
PageControl1: TPageControl;
|
||||||
Panel1: TPanel;
|
Panel1: TPanel;
|
||||||
Panel2: TPanel;
|
Panel2: TPanel;
|
||||||
Panel3: TPanel;
|
Panel3: TPanel;
|
||||||
|
DateTimePanel: TPanel;
|
||||||
PreviewImage: TImage;
|
PreviewImage: TImage;
|
||||||
ImageList: TImageList;
|
ImageList: TImageList;
|
||||||
Splitter3: TSplitter;
|
Splitter3: TSplitter;
|
||||||
@ -34,6 +38,7 @@ type
|
|||||||
ShellTreeView: TShellTreeView;
|
ShellTreeView: TShellTreeView;
|
||||||
Splitter1: TSplitter;
|
Splitter1: TSplitter;
|
||||||
Splitter2: TSplitter;
|
Splitter2: TSplitter;
|
||||||
|
procedure BtnChangeDateClick(Sender: TObject);
|
||||||
procedure FormCreate(Sender: TObject);
|
procedure FormCreate(Sender: TObject);
|
||||||
procedure FormDestroy(Sender: TObject);
|
procedure FormDestroy(Sender: TObject);
|
||||||
procedure PageControl1Change(Sender: TObject);
|
procedure PageControl1Change(Sender: TObject);
|
||||||
@ -66,7 +71,7 @@ implementation
|
|||||||
{$R *.lfm}
|
{$R *.lfm}
|
||||||
|
|
||||||
uses
|
uses
|
||||||
IniFiles, Math, StrUtils,
|
IniFiles, Math, StrUtils, DateUtils,
|
||||||
fpeGlobal, fpeTags, fpeExifData, fpeIptcData;
|
fpeGlobal, fpeTags, fpeExifData, fpeIptcData;
|
||||||
|
|
||||||
|
|
||||||
@ -88,6 +93,37 @@ begin
|
|||||||
//ShellListView.Parent.DoubleBuffered := true;
|
//ShellListView.Parent.DoubleBuffered := true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.BtnChangeDateClick(Sender: TObject);
|
||||||
|
var
|
||||||
|
lTag: TTag;
|
||||||
|
dt: TDateTime;
|
||||||
|
fn: String;
|
||||||
|
begin
|
||||||
|
if (FImgInfo = nil) or (FImgInfo.ExifData = nil) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if not TryStrToDateTime(EdChangeDate.Text, dt) then begin
|
||||||
|
MessageDlg('No valid date/time. Use your locale settings.', mtError, [mbOK], 0);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
lTag := FImgInfo.ExifData.TagByName['DateTimeOriginal'];
|
||||||
|
if lTag <> nil then
|
||||||
|
TDateTimeTag(lTag).AsDateTime := dt;
|
||||||
|
|
||||||
|
lTag := FImgInfo.ExifData.TagByName['DateTimeDigitized'];
|
||||||
|
if lTag <> nil then
|
||||||
|
TDateTimeTag(lTag).AsDateTime := dt;
|
||||||
|
|
||||||
|
lTag := FImgInfo.ExifData.TagByName['DateTime'];
|
||||||
|
if lTag <> nil then
|
||||||
|
TDateTimeTag(lTag).AsDateTime := dt;
|
||||||
|
|
||||||
|
fn := FImgInfo.FileName;
|
||||||
|
fn := ChangeFileExt(fn, '') + '_modified' + ExtractFileExt(fn);
|
||||||
|
FImgInfo.SaveToFile(fn);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TMainForm.FormDestroy(Sender: TObject);
|
procedure TMainForm.FormDestroy(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
@ -136,7 +172,16 @@ begin
|
|||||||
item.SubItems.Add(lTag.Description);
|
item.SubItems.Add(lTag.Description);
|
||||||
item.SubItems.Add(lTag.AsString);
|
item.SubItems.Add(lTag.AsString);
|
||||||
end;
|
end;
|
||||||
end;
|
|
||||||
|
lTag := FImgInfo.ExifData.TagByName['DateTimeOriginal'];
|
||||||
|
if lTag <> nil then
|
||||||
|
EdChangeDate.Text := DateTimeToStr(TDateTimeTag(lTag).AsDateTime)
|
||||||
|
else
|
||||||
|
EdChangeDate.Text := '';
|
||||||
|
DateTimePanel.Show;
|
||||||
|
end else
|
||||||
|
DateTimePanel.Hide;
|
||||||
|
|
||||||
if FImgInfo.HasIptc then begin
|
if FImgInfo.HasIptc then begin
|
||||||
for i := 0 to FImgInfo.IptcData.TagCount-1 do begin
|
for i := 0 to FImgInfo.IptcData.TagCount-1 do begin
|
||||||
lTag := FImgInfo.IptcData.TagByIndex[i];
|
lTag := FImgInfo.IptcData.TagByIndex[i];
|
||||||
|
@ -853,10 +853,9 @@ begin
|
|||||||
Continue;
|
Continue;
|
||||||
|
|
||||||
// Offset to the thumbnail image
|
// Offset to the thumbnail image
|
||||||
if tag.TagID = FULLTAG_THUMBSTARTOFFSET then begin
|
if tag.TagID = FULLTAG_THUMBSTARTOFFSET then
|
||||||
dw := FixEndian32(thumbStartOffset);
|
tag.AsInteger := DWord(thumbStartOffset)
|
||||||
tag.AsInteger := dw;
|
else
|
||||||
end else
|
|
||||||
// Some tags will link to subdirectories. The offset to the start of
|
// Some tags will link to subdirectories. The offset to the start of
|
||||||
// a subdirectory must be specified in the DataValue field of the
|
// a subdirectory must be specified in the DataValue field of the
|
||||||
// written ifd record. Since it is not clear at this moment where the
|
// written ifd record. Since it is not clear at this moment where the
|
||||||
|
@ -1059,7 +1059,8 @@ begin
|
|||||||
else
|
else
|
||||||
raise EFpExif.CreateFmt('Value %d out of range for tag "%s"', [AValue, FName]);
|
raise EFpExif.CreateFmt('Value %d out of range for tag "%s"', [AValue, FName]);
|
||||||
ttUInt16:
|
ttUInt16:
|
||||||
if not WithRangeCheck or ((AValue >= 0) and (AValue <= 65535)) then begin
|
if not WithRangeCheck or ((AValue >= 0) and (AValue <= 65535)) then
|
||||||
|
begin
|
||||||
if BigEndian then
|
if BigEndian then
|
||||||
w := NtoBE(PWord(@AValue)^)
|
w := NtoBE(PWord(@AValue)^)
|
||||||
else
|
else
|
||||||
@ -1069,7 +1070,8 @@ begin
|
|||||||
raise EFpExif.CreateFmt('Value %d out of range for tag "%s"', [AValue, FName]);
|
raise EFpExif.CreateFmt('Value %d out of range for tag "%s"', [AValue, FName]);
|
||||||
ttUInt32,
|
ttUInt32,
|
||||||
ttIFD:
|
ttIFD:
|
||||||
if not WithRangeCheck or (AValue >= 0) then begin
|
if not WithRangeCheck or (AValue >= 0) then
|
||||||
|
begin
|
||||||
if BigEndian then
|
if BigEndian then
|
||||||
dw := NtoBE(PDWord(@AValue)^)
|
dw := NtoBE(PDWord(@AValue)^)
|
||||||
else
|
else
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<CONFIG>
|
<CONFIG>
|
||||||
<ProjectOptions>
|
<ProjectOptions>
|
||||||
<Version Value="10"/>
|
<Version Value="11"/>
|
||||||
<PathDelim Value="\"/>
|
<PathDelim Value="\"/>
|
||||||
<General>
|
<General>
|
||||||
<SessionStorage Value="InProjectDir"/>
|
<SessionStorage Value="InProjectDir"/>
|
||||||
@ -18,9 +18,10 @@
|
|||||||
<Version Value="2"/>
|
<Version Value="2"/>
|
||||||
</PublishOptions>
|
</PublishOptions>
|
||||||
<RunParams>
|
<RunParams>
|
||||||
<local>
|
<FormatVersion Value="2"/>
|
||||||
<FormatVersion Value="1"/>
|
<Modes Count="1">
|
||||||
</local>
|
<Mode0 Name="default"/>
|
||||||
|
</Modes>
|
||||||
</RunParams>
|
</RunParams>
|
||||||
<RequiredPackages Count="1">
|
<RequiredPackages Count="1">
|
||||||
<Item1>
|
<Item1>
|
||||||
|
Binary file not shown.
@ -8,7 +8,7 @@ object MainForm: TMainForm
|
|||||||
ClientHeight = 560
|
ClientHeight = 560
|
||||||
ClientWidth = 1024
|
ClientWidth = 1024
|
||||||
OnCreate = FormCreate
|
OnCreate = FormCreate
|
||||||
LCLVersion = '1.9.0.0'
|
LCLVersion = '2.1.0.0'
|
||||||
object Panel1: TPanel
|
object Panel1: TPanel
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 33
|
Height = 33
|
||||||
|
@ -217,6 +217,7 @@ begin
|
|||||||
end else
|
end else
|
||||||
node.ImageIndex := IMG_INDEX_EXIF;
|
node.ImageIndex := IMG_INDEX_EXIF;
|
||||||
node.SelectedIndex := node.ImageIndex;
|
node.SelectedIndex := node.ImageIndex;
|
||||||
|
node.StateIndex := IMG_CHECKED;
|
||||||
node := node.GetNextSibling;
|
node := node.GetNextSibling;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
This file lists the origin of the used images:
|
||||||
|
|
||||||
|
no_metadata.jpg .... created by fpc code
|
||||||
|
with_exif.jpg ...... created by fpc code, with EXIF (little endian)
|
||||||
|
with_exif.tif ...... dto.
|
||||||
|
with_iptc.jpg ...... created by fpc code, with IPTC
|
||||||
|
with iptc.tif ...... dto.
|
||||||
|
ExThBE_Nokia.jpg ... author's own picture taken by a Nokia smartphone
|
||||||
|
with EXIF (big-endian), with thumbnail image
|
Binary file not shown.
Reference in New Issue
Block a user