fpExif: Fix writing of multi-string IPTC tags. Nicer display text for IPTC CodeCharacterSet tag.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8992 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2023-10-28 18:05:41 +00:00
parent 0599bd5dcd
commit f36bceb0ca
3 changed files with 95 additions and 2 deletions

View File

@ -60,6 +60,12 @@ type
property MaxLength: Integer read FMaxLen; property MaxLength: Integer read FMaxLen;
end; end;
TIptcCodedCharacterSetTag = class(TIptcStringTag)
protected
function GetAsString: String; override;
procedure SetAsString(const AValue: String); override;
end;
TIptcMultiStringTag = class(TIptcStringTag) TIptcMultiStringTag = class(TIptcStringTag)
protected protected
function GetAsString: String; override; function GetAsString: String; override;
@ -136,7 +142,7 @@ begin
with IptcTagDefs do begin with IptcTagDefs do begin
Clear; Clear;
// NOTE: The Count field is "abused" as MaxLength of string value // NOTE: The Count field is "abused" as MaxLength of string value
AddStringTag(I+$015A {1:90}, 'CodedCharacterSet', 32, rsCodedCharSet, '', TIptcStringTag); AddStringTag(I+$015A {1:90}, 'CodedCharacterSet', 32, rsCodedCharSet, '', TIptcCodedCharacterSetTag);
AddUShortTag(I+$0200 {2: 0}, 'RecordVersion', 1, rsRecordVersion); AddUShortTag(I+$0200 {2: 0}, 'RecordVersion', 1, rsRecordVersion);
AddStringTag(I+$0203 {2: 3}, 'ObjectType', 64, rsObjectType, '', TIptcStringTag); AddStringTag(I+$0203 {2: 3}, 'ObjectType', 64, rsObjectType, '', TIptcStringTag);
AddStringTag(I+$0204 {2: 4}, 'ObjectAttr', 68, rsObjectAttr, '', TIptcObjectAttrTag); AddStringTag(I+$0204 {2: 4}, 'ObjectAttr', 68, rsObjectAttr, '', TIptcObjectAttrTag);
@ -474,6 +480,36 @@ begin
end; end;
//==============================================================================
// TIptcCodedCharacterSetTag
//==============================================================================
function TIptcCodedCharacterSetTag.GetAsString: String;
var
s: String;
i: Integer;
begin
s := inherited GetAsString;
if s = #27#37#71 then
Result := 'UTF8'
else
begin
if s[1] = #27 then
Result := 'ESC'
else
Result := s[1];
for i := 2 to Length(s) do
Result := Result + ' ' + s[i];
end;
end;
procedure TIptcCodedCharacterSetTag.SetAsString(const AValue: String);
begin
if Uppercase(AValue) = 'UTF8' then
inherited SetAsString(#27#37#71)
else
inherited SetAsString(AValue);
end;
//============================================================================== //==============================================================================
// TIptcMultiStringTag // TIptcMultiStringTag
//============================================================================== //==============================================================================

View File

@ -72,6 +72,7 @@ type
TIPTCWriter = class(TBasicMetadataWriter) TIPTCWriter = class(TBasicMetadataWriter)
private private
FIPTCSegmentStartPos: Int64; FIPTCSegmentStartPos: Int64;
function SplitMultiStringTag(ATag: TTag): TStringArray;
protected protected
procedure WriteEndOfDataResourceBlock(AStream: TStream); procedure WriteEndOfDataResourceBlock(AStream: TStream);
procedure WriteImageResourceBlockHeader(AStream: TStream; AResourceID: Integer; procedure WriteImageResourceBlockHeader(AStream: TStream; AResourceID: Integer;
@ -320,6 +321,19 @@ begin
WriteImageResourceBlockHeader(AStream, $0B04, ''); //, nil, 0); WriteImageResourceBlockHeader(AStream, $0B04, ''); //, nil, 0);
end; end;
//------------------------------------------------------------------------------
// During reading repeatable string tags were merged into a single string and
// separated by a IPTC_MULTI_TAG_SEPARATOR. Here the combined string is split
// into its parts so that they can be written as separate tags again.
//------------------------------------------------------------------------------
function TIptcWriter.SplitMultiStringTag(ATag: TTag): TStringArray;
var
s: String;
begin
s := PChar(ATag.RawData);
Result := s.Split(IPTC_MULTI_TAG_SEPARATOR);
end;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Writes the IPTC header needed by JPEG files (Segment APP13 header) // Writes the IPTC header needed by JPEG files (Segment APP13 header)
// Call WriteToStream immediately afterwards // Call WriteToStream immediately afterwards
@ -405,9 +419,43 @@ end;
procedure TIptcWriter.WriteTag(AStream: TStream; ATag: TTag); procedure TIptcWriter.WriteTag(AStream: TStream; ATag: TTag);
const const
TAG_MARKER = $1C; TAG_MARKER = $1C;
procedure WriteString(AIptcTag: TIptcTag; AText: PChar; ALength: Integer);
begin
if odd(ALength) then begin
inc(ALength);
end;
// "Standard" dataset
if ALength < 32768 then begin
AIptcTag.Size := NtoBE(word(ALength));
AStream.WriteBuffer(AIptcTag, SizeOf(AIptcTag));
AStream.WriteBuffer(AText^, ALength);
end
else
// "Extended" dataset
if ALength < 65536 then begin
// Size is 2, but we must set highest bit to mark tag as being extended.
AIptcTag.Size := NtoBE($8002);
AStream.WriteBuffer(AIptcTag, SizeOf(AIptcTag));
WriteWord(AStream, NtoBE(word(ALength)));
AStream.WriteBuffer(AText^, ALength);
end else begin
// Size is 4, but we must set highest bit to mark tag as being extended.
AIptcTag.Size := $8004;
AStream.WriteBuffer(AIptcTag, SizeOf(AIptcTag));
WriteDWord(AStream, NtoBE(ALength));
AStream.WriteBuffer(AText^, ALength);
end;
if odd(ALength) then // zero-termination of string
WriteByte(AStream, 0);
end;
var var
iptcTag: TIptcTag; iptcTag: TIptcTag;
len: DWord; len: DWord;
i: Integer;
sa: TStringArray;
begin begin
iptcTag.TagMarker := byte(TAG_MARKER); iptcTag.TagMarker := byte(TAG_MARKER);
iptcTag.RecordNumber := byte((ATag.TagID and $FF00) shr 8); iptcTag.RecordNumber := byte((ATag.TagID and $FF00) shr 8);
@ -421,6 +469,14 @@ begin
end; end;
ttString: ttString:
begin begin
if ATag is TIptcMultiStringTag
then begin
sa := SplitMultiStringTag(ATag);
for i := 0 to High(sa) do
WriteString(iptcTag, PChar(sa[i]), Length(sa[i]));
end else
WriteString(iptcTag, PChar(ATag.RawData), Length(ATag.RawData));
(*
len := Length(ATag.RawData); len := Length(ATag.RawData);
if odd(len) then begin if odd(len) then begin
inc(len); inc(len);
@ -447,6 +503,7 @@ begin
end; end;
if odd(Length(ATag.RawData)) then // zero-termination of string if odd(Length(ATag.RawData)) then // zero-termination of string
WriteByte(AStream, 0); WriteByte(AStream, 0);
*)
end; end;
else else
// I've never seen other tag types than USHORT and STRING... // I've never seen other tag types than USHORT and STRING...

View File

@ -190,7 +190,7 @@ type
property Count: Integer read FCount write FCount; property Count: Integer read FCount write FCount;
{ Raw data of the tag value as read from the file or to be written to the file } { Raw data of the tag value as read from the file or to be written to the file }
property RawData: TBytes read FRawData write SetRawData; property RawData: TBytes read FRawData write SetRawData;
{ Indicates wheter the raw data are in little endian or big endian byte order } { Indicates whether the raw data are in little endian or big endian byte order }
property BigEndian: Boolean read GetBigEndian; property BigEndian: Boolean read GetBigEndian;
{ Determines whether the meaning of numberical values will be decoded. } { Determines whether the meaning of numberical values will be decoded. }
property DecodeValue: Boolean read GetDecodeValue write SetDecodeValue; property DecodeValue: Boolean read GetDecodeValue write SetDecodeValue;