fpexif: Fix detection of EXIF structure if a JFIF extension APP0 marker segment is in file (JFXX). Extract JFXX thumbnail.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7194 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
8c301b7ce0
commit
cd0aa90768
@ -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
|
||||
|
@ -66,6 +66,11 @@
|
||||
<Debugging>
|
||||
<UseExternalDbgSyms Value="True"/>
|
||||
</Debugging>
|
||||
<Options>
|
||||
<Win32>
|
||||
<GraphicApplication Value="True"/>
|
||||
</Win32>
|
||||
</Options>
|
||||
</Linking>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
|
@ -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);
|
||||
|
@ -1,11 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="11"/>
|
||||
<Version Value="12"/>
|
||||
<PathDelim Value="\"/>
|
||||
<General>
|
||||
<Flags>
|
||||
<CompatibilityMode Value="True"/>
|
||||
</Flags>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
<MainUnit Value="0"/>
|
||||
<Title Value="ExifSimpleDemo"/>
|
||||
<ResourceType Value="res"/>
|
||||
<UseXPManifest Value="True"/>
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user