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

236 lines
7.9 KiB
Perl
Raw Normal View History

2023-09-14 11:12:02 +02:00
#------------------------------------------------------------------------------
# File: CaptureOne.pm
#
# Description: Read Capture One EIP and COS files
#
# Revisions: 2009/11/01 - P. Harvey Created
#
# Notes: The EIP format is a ZIP file containing an image (IIQ or TIFF)
# and some settings files (COS). COS files are XML based.
#------------------------------------------------------------------------------
package Image::ExifTool::CaptureOne;
use strict;
use vars qw($VERSION);
use Image::ExifTool qw(:DataAccess :Utils);
use Image::ExifTool::XMP;
use Image::ExifTool::ZIP;
$VERSION = '1.04';
# CaptureOne COS XML tags
# - tags are added dynamically when encountered
# - this table is not listed in tag name docs
%Image::ExifTool::CaptureOne::Main = (
GROUPS => { 0 => 'XML', 1 => 'XML', 2 => 'Image' },
PROCESS_PROC => \&Image::ExifTool::XMP::ProcessXMP,
VARS => { NO_ID => 1 },
ColorCorrections => { ValueConv => '\$val' }, # (long list of floating point numbers)
);
#------------------------------------------------------------------------------
# We found an XMP property name/value
# Inputs: 0) attribute list ref, 1) attr hash ref,
# 2) property name ref, 3) property value ref
# Returns: true if value was changed
sub HandleCOSAttrs($$$$)
{
my ($attrList, $attrs, $prop, $valPt) = @_;
my $changed;
if (not length $$valPt and defined $$attrs{K} and defined $$attrs{V}) {
$$prop = $$attrs{K};
$$valPt = $$attrs{V};
# remove these attributes from the list
my @attrs = @$attrList;
@$attrList = ( );
my $a;
foreach $a (@attrs) {
if ($a eq 'K' or $a eq 'V') {
delete $$attrs{$a};
} else {
push @$attrList, $a;
}
}
$changed = 1;
}
return $changed;
}
#------------------------------------------------------------------------------
# We found a COS property name/value
# Inputs: 0) ExifTool object ref, 1) tag table ref
# 2) reference to array of XMP property names (last is current property)
# 3) property value, 4) attribute hash ref (not used here)
# Returns: 1 if valid tag was found
sub FoundCOS($$$$;$)
{
my ($et, $tagTablePtr, $props, $val, $attrs) = @_;
my $tag = $$props[-1];
unless ($$tagTablePtr{$tag}) {
$et->VPrint(0, " | [adding $tag]\n");
my $name = ucfirst $tag;
$name =~ tr/-_a-zA-Z0-9//dc;
return 0 unless length $tag;
my %tagInfo = ( Name => $tag );
# try formatting any tag with "Date" in the name as a date
# (shouldn't affect non-date tags)
if ($name =~ /Date(?![a-z])/) {
$tagInfo{Groups} = { 2 => 'Time' };
$tagInfo{ValueConv} = 'Image::ExifTool::XMP::ConvertXMPDate($val,1)';
$tagInfo{PrintConv} = '$self->ConvertDateTime($val)';
}
AddTagToTable($tagTablePtr, $tag, \%tagInfo);
}
# convert from UTF8 to ExifTool Charset
$val = $et->Decode($val, "UTF8");
# un-escape XML character entities
$val = Image::ExifTool::XMP::UnescapeXML($val);
$et->HandleTag($tagTablePtr, $tag, $val);
return 0;
}
#------------------------------------------------------------------------------
# Extract information from a COS file
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
# Returns: 1 on success, 0 if this wasn't a valid XML file
sub ProcessCOS($$)
{
my ($et, $dirInfo) = @_;
# process using XMP module, but override handling of attributes and tags
$$dirInfo{XMPParseOpts} = {
AttrProc => \&HandleCOSAttrs,
FoundProc => \&FoundCOS,
};
my $tagTablePtr = GetTagTable('Image::ExifTool::CaptureOne::Main');
my $success = $et->ProcessDirectory($dirInfo, $tagTablePtr);
delete $$dirInfo{XMLParseArgs};
return $success;
}
#------------------------------------------------------------------------------
# Extract information from a CaptureOne EIP file
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
# Returns: 1
# Notes: Upon entry to this routine, the file type has already been verified
# and the dirInfo hash contains a ZIP element unique to this process proc:
# ZIP - reference to Archive::Zip object for this file
sub ProcessEIP($$)
{
my ($et, $dirInfo) = @_;
my $zip = $$dirInfo{ZIP};
my ($file, $buff, $status, $member, %parseFile);
$et->SetFileType('EIP');
# must catch all Archive::Zip warnings
local $SIG{'__WARN__'} = \&Image::ExifTool::ZIP::WarnProc;
# find all manifest files
my @members = $zip->membersMatching('^manifest\d*.xml$');
# and choose the one with the highest version number (any better ideas?)
while (@members) {
my $m = shift @members;
my $f = $m->fileName();
next if $file and $file gt $f;
$member = $m;
$file = $f;
}
# get file names from our chosen manifest file
if ($member) {
($buff, $status) = $zip->contents($member);
if (not $status) {
my $foundImage;
while ($buff =~ m{<(RawPath|SettingsPath)>(.*?)</\1>}sg) {
$file = $2;
next unless $file =~ /\.(cos|iiq|jpe?g|tiff?)$/i;
$parseFile{$file} = 1; # set flag to parse this file
$foundImage = 1 unless $file =~ /\.cos$/i;
}
# ignore manifest unless it contained a valid image
undef %parseFile unless $foundImage;
}
}
# extract meta information from embedded files
my $docNum = 0;
@members = $zip->members(); # get all members
foreach $member (@members) {
# get filename of this ZIP member
$file = $member->fileName();
next unless defined $file;
$et->VPrint(0, "File: $file\n");
# set the document number and extract ZIP tags
$$et{DOC_NUM} = ++$docNum;
Image::ExifTool::ZIP::HandleMember($et, $member);
if (%parseFile) {
next unless $parseFile{$file};
} else {
# reading the manifest didn't work, so look for image files in the
# root directory and .cos files in the CaptureOne directory
next unless $file =~ m{^([^/]+\.(iiq|jpe?g|tiff?)|CaptureOne/.*\.cos)$}i;
}
# extract the contents of the file
# Note: this could use a LOT of memory here for RAW images...
($buff, $status) = $zip->contents($member);
$status and $et->Warn("Error extracting $file"), next;
if ($file =~ /\.cos$/i) {
# process Capture One Settings files
my %dirInfo = (
DataPt => \$buff,
DirLen => length $buff,
DataLen => length $buff,
);
ProcessCOS($et, \%dirInfo);
} else {
# set HtmlDump error if necessary because it doesn't work with embedded files
if ($$et{HTML_DUMP}) {
$$et{HTML_DUMP}{Error} = "Sorry, can't dump images embedded in ZIP files";
}
# process IIQ, JPEG and TIFF images
$et->ExtractInfo(\$buff, { ReEntry => 1 });
}
undef $buff; # (free memory now)
}
delete $$et{DOC_NUM};
return 1;
}
1; # end
__END__
=head1 NAME
Image::ExifTool::CaptureOne - Read Capture One EIP and COS files
=head1 SYNOPSIS
This module is used by Image::ExifTool
=head1 DESCRIPTION
This module contains definitions required by Image::ExifTool to extract meta
information from Capture One EIP (Enhanced Image Package) and COS (Capture
One Settings) files.
=head1 NOTES
The EIP format is a ZIP file containing an image (IIQ or TIFF) and some
settings files (COS).
=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 SEE ALSO
L<Image::ExifTool::TagNames/ZIP Tags>,
L<Image::ExifTool(3pm)|Image::ExifTool>
=cut