test_pie/external/exiftool/lib/Image/ExifTool/GIMP.pm

295 lines
8.4 KiB
Perl

#------------------------------------------------------------------------------
# File: GIMP.pm
#
# Description: Read meta information from GIMP XCF images
#
# Revisions: 2010/10/05 - P. Harvey Created
# 2018/08/21 - PH Updated to current XCF specification (v013)
#
# References: 1) GIMP source code
# 2) https://gitlab.gnome.org/GNOME/gimp/blob/master/devel-docs/xcf.txt
#------------------------------------------------------------------------------
package Image::ExifTool::GIMP;
use strict;
use vars qw($VERSION);
use Image::ExifTool qw(:DataAccess :Utils);
$VERSION = '1.03';
sub ProcessParasites($$$);
# GIMP XCF properties (ref 2)
%Image::ExifTool::GIMP::Main = (
GROUPS => { 2 => 'Image' },
VARS => { ALPHA_FIRST => 1 },
NOTES => q{
The GNU Image Manipulation Program (GIMP) writes these tags in its native
XCF (eXperimental Computing Facilty) images.
},
header => { SubDirectory => { TagTable => 'Image::ExifTool::GIMP::Header' } },
# recognized properties
# 1 - ColorMap
# 17 - SamplePoints? (doc says 17 is also "PROP_SAMPLE_POINTS"??)
17 => {
Name => 'Compression',
Format => 'int8u',
PrintConv => {
0 => 'None',
1 => 'RLE Encoding',
2 => 'Zlib',
3 => 'Fractal',
},
},
# 18 - Guides
19 => {
Name => 'Resolution',
SubDirectory => { TagTable => 'Image::ExifTool::GIMP::Resolution' },
},
20 => {
Name => 'Tattoo',
Format => 'int32u',
},
21 => {
Name => 'Parasites',
SubDirectory => { TagTable => 'Image::ExifTool::GIMP::Parasite' },
},
22 => {
Name => 'Units',
Format => 'int32u',
PrintConv => {
1 => 'Inches',
2 => 'mm',
3 => 'Points',
4 => 'Picas',
},
},
# 23 Paths
# 24 UserUnit
# 25 Vectors
);
# information extracted from the XCF file header (ref 2)
%Image::ExifTool::GIMP::Header = (
GROUPS => { 2 => 'Image' },
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
9 => {
Name => 'XCFVersion',
Format => 'string[5]',
DataMember => 'XCFVersion',
RawConv => '$$self{XCFVersion} = $val',
PrintConv => {
'file' => '0',
'v001' => '1',
'v002' => '2',
OTHER => sub { my $val = shift; $val =~ s/^v0*//; return $val },
},
},
14 => { Name => 'ImageWidth', Format => 'int32u' },
18 => { Name => 'ImageHeight', Format => 'int32u' },
22 => {
Name => 'ColorMode',
Format => 'int32u',
PrintConv => {
0 => 'RGB Color',
1 => 'Grayscale',
2 => 'Indexed Color',
},
},
# 26 - [XCF 4 or later] Precision
);
# XCF resolution data (property type 19) (ref 2)
%Image::ExifTool::GIMP::Resolution = (
GROUPS => { 2 => 'Image' },
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
FORMAT => 'float',
0 => 'XResolution',
1 => 'YResolution',
);
# XCF "Parasite" data (property type 21) (ref 1/PH)
%Image::ExifTool::GIMP::Parasite = (
GROUPS => { 2 => 'Image' },
PROCESS_PROC => \&ProcessParasites,
'gimp-comment' => {
Name => 'Comment',
Format => 'string',
},
'exif-data' => {
Name => 'ExifData',
SubDirectory => {
TagTable => 'Image::ExifTool::Exif::Main',
ProcessProc => \&Image::ExifTool::ProcessTIFF,
Start => 6, # starts after "Exif\0\0" header
},
},
'jpeg-exif-data' => { # (deprecated, untested)
Name => 'JPEGExifData',
SubDirectory => {
TagTable => 'Image::ExifTool::Exif::Main',
ProcessProc => \&Image::ExifTool::ProcessTIFF,
Start => 6,
},
},
'iptc-data' => { # (untested)
Name => 'IPTCData',
SubDirectory => { TagTable => 'Image::ExifTool::IPTC::Main' },
},
'icc-profile' => {
Name => 'ICC_Profile',
SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
},
'icc-profile-name' => {
Name => 'ICCProfileName',
Format => 'string',
},
'gimp-metadata' => {
Name => 'XMP',
SubDirectory => {
TagTable => 'Image::ExifTool::XMP::Main',
Start => 10, # starts after "GIMP_XMP_1" header
},
},
'gimp-image-metadata' => {
Name => 'XML',
SubDirectory => { TagTable => 'Image::ExifTool::XMP::XML' },
},
# Seen, but not yet decoded:
# gimp-image-grid
# jpeg-settings
);
#------------------------------------------------------------------------------
# Read information in a GIMP XCF parasite data (ref PH)
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
# Returns: 1 on success
sub ProcessParasites($$$)
{
my ($et, $dirInfo, $tagTablePtr) = @_;
my $unknown = $et->Options('Unknown') || $et->Options('Verbose');
my $dataPt = $$dirInfo{DataPt};
my $pos = $$dirInfo{DirStart} || 0;
my $end = length $$dataPt;
$et->VerboseDir('Parasites', undef, $end);
for (;;) {
last if $pos + 4 > $end;
my $size = Get32u($dataPt, $pos); # length of tag string
$pos += 4;
last if $pos + $size + 8 > $end;
my $tag = substr($$dataPt, $pos, $size);
$pos += $size;
$tag =~ s/\0.*//s; # trim at null terminator
# my $flags = Get32u($dataPt, $pos); (ignore flags)
$size = Get32u($dataPt, $pos + 4); # length of data
$pos += 8;
last if $pos + $size > $end;
if (not $$tagTablePtr{$tag} and $unknown) {
my $name = $tag;
$name =~ tr/-_A-Za-z0-9//dc;
$name =~ s/^gimp-//;
next unless length $name;
$name = ucfirst $name;
$name =~ s/([a-z])-([a-z])/$1\u$2/g;
$name = "GIMP-$name" unless length($name) > 1;
AddTagToTable($tagTablePtr, $tag, { Name => $name, Unknown => 1 });
}
$et->HandleTag($tagTablePtr, $tag, undef,
DataPt => $dataPt,
Start => $pos,
Size => $size,
);
$pos += $size;
}
return 1;
}
#------------------------------------------------------------------------------
# Read information in a GIMP XCF document
# Inputs: 0) ExifTool ref, 1) dirInfo ref
# Returns: 1 on success, 0 if this wasn't a valid XCF file
sub ProcessXCF($$)
{
my ($et, $dirInfo) = @_;
my $raf = $$dirInfo{RAF};
my $buff;
return 0 unless $raf->Read($buff, 26) == 26;
return 0 unless $buff =~ /^gimp xcf /;
my $tagTablePtr = GetTagTable('Image::ExifTool::GIMP::Main');
my $verbose = $et->Options('Verbose');
$et->SetFileType();
SetByteOrder('MM');
# process the XCF header
$et->HandleTag($tagTablePtr, 'header', $buff);
# skip over precision for XCV version 4 or later
$raf->Seek(4, 1) if $$et{XCFVersion} =~ /^v0*(\d+)/ and $1 >= 4;
# loop through image properties
for (;;) {
$raf->Read($buff, 8) == 8 or last;
my $tag = Get32u(\$buff, 0) or last;
my $size = Get32u(\$buff, 4);
$verbose and $et->VPrint(0, "XCF property $tag ($size bytes):\n");
unless ($$tagTablePtr{$tag}) {
$raf->Seek($size, 1);
next;
}
$raf->Read($buff, $size) == $size or last;
$et->HandleTag($tagTablePtr, $tag, undef,
DataPt => \$buff,
DataPos => $raf->Tell() - $size,
Size => $size,
);
}
return 1;
}
1; # end
__END__
=head1 NAME
Image::ExifTool::GIMP - Read meta information from GIMP XCF images
=head1 SYNOPSIS
This module is used by Image::ExifTool
=head1 DESCRIPTION
This module contains definitions required by Image::ExifTool to read meta
information from GIMP (GNU Image Manipulation Program) XCF (eXperimental
Computing Facility) images. This is the native image format used by the
GIMP software.
=head1 AUTHOR
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 REFERENCES
=over 4
=item L<GIMP source code>
=item L<http://svn.gnome.org/viewvc/gimp/trunk/devel-docs/xcf.txt?view=markup>
=back
=head1 SEE ALSO
L<Image::ExifTool::TagNames/GIMP Tags>,
L<Image::ExifTool(3pm)|Image::ExifTool>
=cut