diff --git a/components/fpexif/examples/file_renamer/frmain.pas b/components/fpexif/examples/file_renamer/frmain.pas
index ccbdb3035..399693499 100644
--- a/components/fpexif/examples/file_renamer/frmain.pas
+++ b/components/fpexif/examples/file_renamer/frmain.pas
@@ -179,17 +179,17 @@ begin
imgInfo := TImgInfo.Create;
try
imgInfo.LoadFromFile(ShellTreeView.Path + Item.Caption);
- if not (imgInfo.HasExif and imgInfo.HasThumbnail) then begin
+ if not (imgInfo.HasThumbnail) then begin
ThumbImg.Picture.LoadFromFile(ShellTreeView.Path + Item.Caption);
exit;
end;
ms := TMemoryStream.Create;
try
- imgInfo.ExifData.SaveThumbnailToStream(ms);
+ imgInfo.SaveThumbnailToStream(ms);
if ms.Size > 0 then begin
ms.Position := 0;
- ThumbImg.Picture.LoadfromStream(ms);
+ ThumbImg.Picture.LoadFromStream(ms);
end else
ThumbImg.Picture.Clear;
finally
diff --git a/components/fpexif/examples/metadata_viewer/MetadataViewer.lpi b/components/fpexif/examples/metadata_viewer/MetadataViewer.lpi
index 8d11694b5..30cc45ad1 100644
--- a/components/fpexif/examples/metadata_viewer/MetadataViewer.lpi
+++ b/components/fpexif/examples/metadata_viewer/MetadataViewer.lpi
@@ -66,6 +66,11 @@
+
+
+
+
+
diff --git a/components/fpexif/examples/metadata_viewer/mdvmain.pas b/components/fpexif/examples/metadata_viewer/mdvmain.pas
index ff375454a..435d9ee25 100644
--- a/components/fpexif/examples/metadata_viewer/mdvmain.pas
+++ b/components/fpexif/examples/metadata_viewer/mdvmain.pas
@@ -320,10 +320,10 @@ begin
end;
end;
- if FImgInfo.HasThumbnail and Assigned(FImgInfo.ExifData) then begin
+ if FImgInfo.HasThumbnail then begin
ms := TMemoryStream.Create;
try
- FImgInfo.ExifData.SaveThumbnailToStream(ms);
+ FImgInfo.SaveThumbnailToStream(ms);
ms.Position := 0;
PreviewImage.Picture.LoadFromStream(ms);
RotateBitmap(PreviewImage.Picture.Bitmap, FImageOrientation);
diff --git a/components/fpexif/examples/simple_demo/ExifSimpleDemo.lpi b/components/fpexif/examples/simple_demo/ExifSimpleDemo.lpi
index 9e620f9a0..8a0da9465 100644
--- a/components/fpexif/examples/simple_demo/ExifSimpleDemo.lpi
+++ b/components/fpexif/examples/simple_demo/ExifSimpleDemo.lpi
@@ -1,11 +1,13 @@
-
+
+
+
+
-
diff --git a/components/fpexif/examples/simple_demo/sdmain.lfm b/components/fpexif/examples/simple_demo/sdmain.lfm
index aefe179e7..423db2b39 100644
--- a/components/fpexif/examples/simple_demo/sdmain.lfm
+++ b/components/fpexif/examples/simple_demo/sdmain.lfm
@@ -130,7 +130,7 @@ object MainForm: TMainForm
Left = 312
Height = 19
Top = 10
- Width = 128
+ Width = 127
BorderSpacing.Left = 8
Caption = 'Truncate binary tags'
Checked = True
@@ -143,7 +143,7 @@ object MainForm: TMainForm
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = CbVerbosity
AnchorSideTop.Side = asrCenter
- Left = 448
+ Left = 447
Height = 19
Top = 10
Width = 123
@@ -233,7 +233,7 @@ object MainForm: TMainForm
Left = 620
Height = 15
Top = 347
- Width = 19
+ Width = 18
Anchors = [akLeft, akBottom]
BorderSpacing.Bottom = 4
Caption = 'Tag'
diff --git a/components/fpexif/examples/simple_demo/sdmain.pas b/components/fpexif/examples/simple_demo/sdmain.pas
index 952c3fa4d..813882b22 100644
--- a/components/fpexif/examples/simple_demo/sdmain.pas
+++ b/components/fpexif/examples/simple_demo/sdmain.pas
@@ -308,12 +308,16 @@ procedure TMainForm.LoadThumbnail;
var
ms: TMemoryStream;
begin
- if (FImgInfo.ExifData = nil) or (not FImgInfo.Exifdata.HasThumbnail) then
+ if not FImgInfo.HasThumbnail then
exit;
+ //if (FImgInfo.ExifData = nil) or (not FImgInfo.Exifdata.HasThumbnail) then
+ // exit;
+
ms := TMemoryStream.Create;
try
- FImgInfo.ExifData.SaveThumbnailToStream(ms);
+ FImgInfo.SaveThumbnailToStream(ms);
+// FImgInfo.ExifData.SaveThumbnailToStream(ms);
ms.Position := 0;
Thumbnail.Picture.LoadfromStream(ms);
finally
diff --git a/components/fpexif/fpemetadata.pas b/components/fpexif/fpemetadata.pas
index f0937fdb3..a9fd9fd80 100644
--- a/components/fpexif/fpemetadata.pas
+++ b/components/fpexif/fpemetadata.pas
@@ -58,6 +58,7 @@ type
FWarnings: TStrings;
FMetadataKinds: TMetadataKinds;
FHeaderSegment: TBytes;
+ FJFXXThumbnail: TBytes;
FComment: String;
private
FExifData: TExifData;
@@ -80,6 +81,7 @@ type
procedure LoadFromStream(AStream: TStream);
procedure Save;
procedure SaveToFile(const AFileName: String; AImgFile: String = '');
+ procedure SaveThumbnailToStream(AStream: TStream);
function CreateExifData(ABigEndian: Boolean = false): TExifData;
function CreateIptcData: TIptcData;
@@ -132,6 +134,13 @@ type
end;
PJpegJFIFSegment = ^TJpegJFIFSegment;
+ TJpegJFXXSegment = packed record
+ Identifier: packed array[0..4] of AnsiChar; // 'JFXX'#0
+ ThumbnailFormat: byte; // 10: JPEG, 11: 1 byte-per-pixel palettized, 12: 3 byte-per-pixel RGB
+ end;
+ // ThumbnailData are following
+ PJpegJFXXSegment = ^TJpegJFXXSegment;
+
TJpegSOF0Segment = packed record
DataPrecision: Byte;
ImageHeight: Word;
@@ -331,7 +340,8 @@ end;
function TImgInfo.HasThumbnail: boolean;
begin
- Result := (FExifData <> nil) and FExifData.HasThumbnail;
+ Result := ((FExifData <> nil) and FExifData.HasThumbnail)
+ or (Length(FJFXXThumbnail) > 0);
end;
function TImgInfo.HasWarnings: boolean;
@@ -433,6 +443,9 @@ begin
end;
procedure TImgInfo.ReadJpeg(AStream: TStream);
+const
+ sJFIF: String[5] = 'JFIF'#0;
+ sJFXX: String[5] = 'JFXX'#0;
var
marker: Byte;
size: Word;
@@ -441,6 +454,7 @@ var
buf: TBytes;
reader: TBasicMetadataReader;
bigEndian: Boolean;
+ hdr: TBytes;
{$IFNDEF FPC}
sa: ansistring;
{$ENDIF}
@@ -517,17 +531,32 @@ begin
end;
M_JFIF:
begin
- SetLength(FHeaderSegment, size);
- AStream.Read(FHeaderSegment[0], size);
- with PJpegJFIFSegment(@FHeaderSegment[0])^ do begin
- if not (
- (Identifier[0]='J') and (Identifier[1]='F') and
- (Identifier[2]='I') and (Identifier[3]='F') and
- (Identifier[4]=#0) )
- then
- exit;
- if (JFIFVersion[0] <> 1) then
- exit;
+ SetLength(hdr, size);
+ AStream.Read(hdr[0], size);
+ with PJpegJFIFSegment(@hdr[0])^ do begin
+ if CompareMem(@Identifier[0], @sJFIF[1], Length(sJFIF)) then
+ begin
+ // JFIF APP0 marker segment
+ SetLength(FHeaderSegment, size);
+ Move(hdr[0], FHeaderSegment[0], size);
+ if (JFIFVersion[0] <> 1) then
+ exit;
+ end else
+ if CompareMem(@Identifier[0], @sJFXX[1], Length(sJFXX)) then
+ begin
+ // JFXX extension APP0 marker segment (optional)
+ // alternative location of a thumbnail image:
+ // https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format#JFIF_extension_APP0_marker_segment
+ {
+ // --- not supported at the moment.
+ SetLength(FJFXXHeaderSegment, size);
+ Move(hdr[0], FJFXXHeaderSegment[0], size);
+ }
+ // --- not working... not a valid jpeg structure.
+
+ SetLength(FJFXXThumbnail, size - SizeOf(TJpegJFXXSegment)); //(AStream.Position - p));
+ Move(hdr[SizeOf(TJpegJFXXSegment)], FJFXXThumbnail[0], Length(FJFXXThumbnail));
+ end;
end;
end;
M_SOF0:
@@ -573,6 +602,15 @@ begin
SaveToFile(FFileName);
end;
+procedure TImgInfo.SaveThumbnailToStream(AStream: TStream);
+begin
+ if (FExifData <> nil) and ExifData.HasThumbnail then
+ FExifData.SaveThumbnailToStream(AStream)
+ else
+ if Length(FJFXXThumbnail) > 0 then
+ AStream.Write(FJFXXThumbnail[0], Length(FJFXXThumbnail));
+end;
+
procedure TImgInfo.SaveToFile(const AFileName: String; AImgFile: String = '');
var
ms: TMemoryStream;