You've already forked lazarus-ccr
fpexif: Fix incorrect copying of XMP meta data when a file with XMP is re-saved.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7983 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@@ -803,7 +803,7 @@ begin
|
|||||||
FExifSegmentStartPos := AStream.Position;
|
FExifSegmentStartPos := AStream.Position;
|
||||||
AStream.WriteBuffer(SEGMENT_MARKER[0], 2);
|
AStream.WriteBuffer(SEGMENT_MARKER[0], 2);
|
||||||
// Next two zero bytes are the size of the entire Exif segiment, they will be
|
// Next two zero bytes are the size of the entire Exif segiment, they will be
|
||||||
// replaced when the segment is completely written. For this, we store the
|
// replaced when the segment is completely written. For this, we stored the
|
||||||
// offset to the beginning of the EXIF segment in FExifSegmentStartPos.
|
// offset to the beginning of the EXIF segment in FExifSegmentStartPos.
|
||||||
AStream.WriteBuffer(SIZE, 2);
|
AStream.WriteBuffer(SIZE, 2);
|
||||||
AStream.WriteBuffer(EXIF_SIGNATURE[0], 6);
|
AStream.WriteBuffer(EXIF_SIGNATURE[0], 6);
|
||||||
|
@@ -230,7 +230,7 @@ begin
|
|||||||
AStream.Position := startPos;
|
AStream.Position := startPos;
|
||||||
|
|
||||||
// ... and write the segment size.
|
// ... and write the segment size.
|
||||||
w := BEToN(segmentSize);
|
w := NToBE(segmentSize);
|
||||||
AStream.WriteBuffer(w, SizeOf(w));
|
AStream.WriteBuffer(w, SizeOf(w));
|
||||||
|
|
||||||
// Rewind stream to the end
|
// Rewind stream to the end
|
||||||
@@ -393,18 +393,16 @@ type
|
|||||||
TSegmentHeader = packed record
|
TSegmentHeader = packed record
|
||||||
Key: byte;
|
Key: byte;
|
||||||
Marker: byte;
|
Marker: byte;
|
||||||
Size: Word;
|
Size: Word; // total size of the segment without "Key" and "Marker", but with "Size"
|
||||||
end;
|
end;
|
||||||
const
|
const
|
||||||
SOI_MARKER: array[0..1] of byte = ($FF, $D8);
|
|
||||||
XMP_SIGNATURE = 'http://ns.adobe.com/xap/1.0/';
|
XMP_SIGNATURE = 'http://ns.adobe.com/xap/1.0/';
|
||||||
var
|
var
|
||||||
header: TSegmentHeader;
|
header: TSegmentHeader;
|
||||||
headerSize, newHeaderSize: Word;
|
headerSize: Word;
|
||||||
n, count: Int64;
|
n, count: Int64;
|
||||||
savedPos: Int64;
|
savedPos: Int64;
|
||||||
jfif: TJpegJFIFSegment;
|
s: RawByteString;
|
||||||
s: String;
|
|
||||||
begin
|
begin
|
||||||
// Write the header segment and all metadata segments stored in TImgInfo
|
// Write the header segment and all metadata segments stored in TImgInfo
|
||||||
// to the beginning of the stream
|
// to the beginning of the stream
|
||||||
@@ -424,10 +422,8 @@ begin
|
|||||||
|
|
||||||
// Some images do not specify the segment length correctly and fill the
|
// Some images do not specify the segment length correctly and fill the
|
||||||
// space to the next segment with zero bytes.
|
// space to the next segment with zero bytes.
|
||||||
if LongInt(header) = 0 then begin
|
if (header.Key = 0) then begin
|
||||||
n := 0;
|
repeat until AInputStream.ReadByte = $FF;
|
||||||
while AInputStream.ReadByte = 0 do
|
|
||||||
inc(n);
|
|
||||||
AInputStream.Position := AInputStream.Position - 1;
|
AInputStream.Position := AInputStream.Position - 1;
|
||||||
n := AInputStream.Read(header, SizeOf(Header));
|
n := AInputStream.Read(header, SizeOf(Header));
|
||||||
if n <> SizeOf(Header) then
|
if n <> SizeOf(Header) then
|
||||||
@@ -438,39 +434,32 @@ begin
|
|||||||
Error(rsJpegSegmentMarkerExpected);
|
Error(rsJpegSegmentMarkerExpected);
|
||||||
headerSize := BEToN(header.Size);
|
headerSize := BEToN(header.Size);
|
||||||
|
|
||||||
// Save stream position before segment size value.
|
// Stream position at start of segment header
|
||||||
|
savedPos := AInputStream.Position - SizeOf(header);
|
||||||
|
// Save stream position after marker bytes, i.e. at begin of segment size value.
|
||||||
savedPos := AInputStream.Position - 2;
|
savedPos := AInputStream.Position - 2;
|
||||||
|
|
||||||
case header.Marker of
|
case header.Marker of
|
||||||
M_SOI:
|
M_SOI:
|
||||||
headerSize := 0;
|
headerSize := 0;
|
||||||
M_JFIF, M_IPTC, M_COM: // These segments were already written by WriteJpeg
|
M_JFIF, M_IPTC, M_COM: // These segments were already written by WriteJpeg
|
||||||
;
|
;
|
||||||
M_EXIF:
|
M_EXIF:
|
||||||
// there may be also the XMP segment which has the same key $E1.
|
|
||||||
begin
|
begin
|
||||||
|
// XMP segment found which has the same key $E1 as the normal EXIF segment.
|
||||||
SetLength(s, Length(XMP_SIGNATURE));
|
SetLength(s, Length(XMP_SIGNATURE));
|
||||||
AInputStream.Read(s[1], Length(XMP_SIGNATURE));
|
AInputStream.Read(s[1], Length(XMP_SIGNATURE));
|
||||||
if s = XMP_SIGNATURE then
|
if s = XMP_SIGNATURE then
|
||||||
begin
|
begin
|
||||||
// XMP segment found --> write it back as it is (needs to be fixed to write current meta data)
|
// Return to where the segment begins
|
||||||
newHeaderSize := (Trunc(headerSize / 256) + 1) * 256 - SizeOf(header);
|
AInputStream.Position := savedPos - 2;
|
||||||
SetLength(s, newHeaderSize - Length(XMP_SIGNATURE));
|
// Copy entire segment incl header
|
||||||
FillChar(s[1], Length(s), 0);
|
n := AOutputStream.CopyFrom(AInputStream, headerSize + 2);
|
||||||
AInputStream.Read(s[1], headerSize);
|
if n <> Int64(headerSize) + 2 then
|
||||||
header.Size := NToBE(newHeaderSize);
|
|
||||||
AOutputStream.Write(header, SizeOf(Header));
|
|
||||||
AOutputStream.Write(XMP_SIGNATURE, Length(XMP_SIGNATURE));
|
|
||||||
AOutputStream.Write(s[1], Length(s));
|
|
||||||
{
|
|
||||||
AInputStream.Position := savedPos - 4;
|
|
||||||
n := AOutputStream.CopyFrom(AInputStream, Int64(header.Size) + 2);
|
|
||||||
if n <> Int64(header.Size) + 2 then
|
|
||||||
Error(rsJpegReadWriteErrorInSegment);
|
Error(rsJpegReadWriteErrorInSegment);
|
||||||
}
|
end else
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
begin
|
||||||
// EXIF segment found. But this already has been written by WriteJpeg -> nothing to do
|
// Normal EXIF segment found. But this already has been written by WriteJpeg -> nothing to do
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
M_SOS:
|
M_SOS:
|
||||||
@@ -479,14 +468,16 @@ begin
|
|||||||
// --> just copy the rest of the file
|
// --> just copy the rest of the file
|
||||||
count := AInputStream.Size - savedPos;
|
count := AInputStream.Size - savedPos;
|
||||||
AInputStream.Position := savedPos;
|
AInputStream.Position := savedPos;
|
||||||
AOutputStream.WriteBuffer(header, 2);
|
AOutputStream.Write(header, 2);
|
||||||
n := AOutputStream.CopyFrom(AInputStream, count);
|
n := AOutputStream.CopyFrom(AInputStream, count);
|
||||||
if n <> count then
|
if n <> count then
|
||||||
Error(rsJpegCompressedDataWriting);
|
Error(rsJpegCompressedDataWriting);
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
else
|
else
|
||||||
AInputStream.Position := AInputStream.Position - 4; // go back to where the segment begins
|
// Return to where the segment begins
|
||||||
|
AInputStream.Position := AInputStream.Position - 4;
|
||||||
|
// Copy entire segment incl header
|
||||||
n := AOutputStream.CopyFrom(AInputStream, headerSize + 2);
|
n := AOutputStream.CopyFrom(AInputStream, headerSize + 2);
|
||||||
if n <> Int64(headerSize) + 2 then
|
if n <> Int64(headerSize) + 2 then
|
||||||
Error(rsJpegReadWriteErrorInSegment);
|
Error(rsJpegReadWriteErrorInSegment);
|
||||||
|
Reference in New Issue
Block a user