<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#------------------------------------------------------------------------------
# File:         FotoStation.pm
#
# Description:  Read/write FotoWare FotoStation trailer
#
# Revisions:    10/28/2006 - P. Harvey Created
#------------------------------------------------------------------------------

package Image::ExifTool::FotoStation;

use strict;
use vars qw($VERSION);
use Image::ExifTool qw(:DataAccess :Utils);

$VERSION = '1.00';

sub ProcessFotoStation($$);

%Image::ExifTool::FotoStation::Main = (
    PROCESS_PROC =&gt; \&amp;ProcessFotoStation,
    WRITE_PROC =&gt; \&amp;ProcessFotoStation,
    GROUPS =&gt; { 2 =&gt; 'Image' },
    NOTES =&gt; q{
        The following tables define information found in the FotoWare FotoStation
        trailer.
    },
    0x01 =&gt; {
        Name =&gt; 'IPTC',
        SubDirectory =&gt; {
            TagTable =&gt; 'Image::ExifTool::IPTC::Main',
        },
    },
    0x02 =&gt; {
        Name =&gt; 'SoftEdit',
        SubDirectory =&gt; {
            TagTable =&gt; 'Image::ExifTool::FotoStation::SoftEdit',
        },
    },
    0x03 =&gt; {
        Name =&gt; 'ThumbnailImage',
        Writable =&gt; 1,
        RawConv =&gt; '$self-&gt;ValidateImage(\$val,$tag)',
    },
    0x04 =&gt; {
        Name =&gt; 'PreviewImage',
        Writable =&gt; 1,
        RawConv =&gt; '$self-&gt;ValidateImage(\$val,$tag)',
    },
);

# crop coordinate conversions
my %cropConv = (
    ValueConv =&gt; '$val / 1000',
    ValueConvInv =&gt; '$val * 1000',
    PrintConv =&gt; '"$val%"',
    PrintConvInv =&gt; '$val=~tr/ %//d; $val',
);

# soft crop record
%Image::ExifTool::FotoStation::SoftEdit = (
    PROCESS_PROC =&gt; \&amp;Image::ExifTool::ProcessBinaryData,
    WRITE_PROC =&gt; \&amp;Image::ExifTool::WriteBinaryData,
    CHECK_PROC =&gt; \&amp;Image::ExifTool::CheckBinaryData,
    WRITABLE =&gt; 1,
    FORMAT =&gt; 'int32s',
    FIRST_ENTRY =&gt; 0,
    GROUPS =&gt; { 2 =&gt; 'Image' },
    0 =&gt; {
        Name =&gt; 'OriginalImageWidth',
    },
    1 =&gt; 'OriginalImageHeight',
    2 =&gt; 'ColorPlanes',
    3 =&gt; {
        Name =&gt; 'XYResolution',
        ValueConv =&gt; '$val / 1000',
        ValueConvInv =&gt; '$val * 1000',
    },
    4 =&gt; {
        Name =&gt; 'Rotation',
        Notes =&gt; q{
            rotations are stored as degrees CCW * 100, but converted to degrees CW by
            ExifTool
        },
        # raw value is 0, 9000, 18000 or 27000
        ValueConv =&gt; '$val ? 360 - $val / 100 : 0',
        ValueConvInv =&gt; '$val ? (360 - $val) * 100 : 0',
    },
    # 5 Validity Check (0x11222211)
    6 =&gt; {
        Name =&gt; 'CropLeft',
        %cropConv,
    },
    7 =&gt; {
        Name =&gt; 'CropTop',
        %cropConv,
    },
    8 =&gt; {
        Name =&gt; 'CropRight',
        %cropConv,
    },
    9 =&gt; {
        Name =&gt; 'CropBottom',
        %cropConv,
    },
    11 =&gt; {
        Name =&gt; 'CropRotation',
        # raw value in the range -4500 to 4500
        ValueConv =&gt; '-$val / 100',
        ValueConvInv =&gt; '-$val * 100',
    },
);

#------------------------------------------------------------------------------
# Read/write FotoStation information in a file
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
# Returns: 1 on success, 0 if this file didn't contain FotoStation information
# - updates DataPos to point to start of FotoStation information
# - updates DirLen to trailer length
sub ProcessFotoStation($$)
{
    my ($exifTool, $dirInfo) = @_;
    $exifTool or return 1;    # allow dummy access to autoload this package
    my ($buff, $footer, $dirBuff, $tagTablePtr);
    my $raf = $$dirInfo{RAF};
    my $outfile = $$dirInfo{OutFile};
    my $offset = $$dirInfo{Offset} || 0;
    my $verbose = $exifTool-&gt;Options('Verbose');
    my $out = $exifTool-&gt;Options('TextOut');
    my $rtnVal = 0;

    $$dirInfo{DirLen} = 0;      # initialize returned trailer length
    $raf-&gt;Seek(-$offset, 2);    # seek to specified offset from end of file

    # loop through FotoStation records
    for (;;) {
        # look for trailer signature
        last unless $raf-&gt;Seek(-10, 1) and $raf-&gt;Read($footer, 10) == 10;
        my ($tag, $size, $sig) = unpack('nNN', $footer);
        last unless $sig == 0xa1b2c3d4 and $size &gt;= 10 and $raf-&gt;Seek(-$size, 1);
        $size -= 10; # size of data only
        last unless $raf-&gt;Read($buff, $size) == $size;
        $raf-&gt;Seek(-$size, 1);
        # set variables returned in dirInfo hash
        $$dirInfo{DataPos} = $raf-&gt;Tell();
        $$dirInfo{DirLen} += $size + 10;

        unless ($tagTablePtr) {
            $tagTablePtr = GetTagTable('Image::ExifTool::FotoStation::Main');
            SetByteOrder('MM'); # necessary for the binary data
            $rtnVal = 1;        # we found a valid FotoStation trailer
        }
        unless ($outfile) {
            # print verbose trailer information
            if ($verbose or $exifTool-&gt;{HTML_DUMP}) {
                $exifTool-&gt;DumpTrailer({
                    RAF =&gt; $raf,
                    DataPos =&gt; $$dirInfo{DataPos},
                    DirLen =&gt; $size + 10,
                    DirName =&gt; "FotoStation_$tag",
                });
            }
            # extract information for this tag
            $exifTool-&gt;HandleTag($tagTablePtr, $tag, $buff,
                                 DataPt =&gt; \$buff,
                                 Start =&gt; 0,
                                 Size =&gt; $size,
                                 DataPos =&gt; $$dirInfo{DataPos});
            next;
        }
        if ($exifTool-&gt;{DEL_GROUP}-&gt;{FotoStation}) {
            $verbose and printf $out "  Deleting FotoStation trailer\n";
            $verbose = 0;   # no more verbose messages after this
            ++$exifTool-&gt;{CHANGED};
            next;
        }
        # rewrite this information
        my $tagInfo = $exifTool-&gt;GetTagInfo($tagTablePtr, $tag);
        if ($tagInfo) {
            my $newVal;
            my $tagName = $$tagInfo{Name};
            if ($$tagInfo{SubDirectory}) {
                my %subdirInfo = (
                    DataPt =&gt; \$buff,
                    DirStart =&gt; 0,
                    DirLen =&gt; $size,
                    DataPos =&gt; $$dirInfo{DataPos},
                    DirName =&gt; $tagName,
                    Parent =&gt; 'FotoStation',
                );
                my $subTable = GetTagTable($tagInfo-&gt;{SubDirectory}-&gt;{TagTable});
                $newVal = $exifTool-&gt;WriteDirectory(\%subdirInfo, $subTable);
            } else {
                my $nvHash = $exifTool-&gt;GetNewValueHash($tagInfo);
                if (Image::ExifTool::IsOverwriting($nvHash) &gt; 0) {
                    $newVal = Image::ExifTool::GetNewValues($nvHash);
                    $newVal = '' unless defined $newVal;
                    if ($verbose &gt; 1) {
                        my $n = length $newVal;
                        print $out "    - FotoStation:$tagName ($size bytes)\n" if $size;
                        print $out "    + FotoStation:$tagName ($n bytes)\n" if $n;
                    }
                    ++$exifTool-&gt;{CHANGED};
                }
            }
            if (defined $newVal) {
                # note: length may be 0 here, but we write the empty record anyway
                $buff = $newVal;
                $size = length($newVal) + 10;
                $footer = pack('nNN', $tag, $size, $sig);
            }
        }
        if (defined $dirBuff) {
            # maintain original record order
            $dirBuff = $buff . $footer . $dirBuff;
        } else {
            $dirBuff = $buff . $footer;
        }
    }
    # write the modified FotoStation trailer
    Write($outfile, $dirBuff) or $rtnVal = -1 if $dirBuff;
    return $rtnVal;
}

1;  # end

__END__

=head1 NAME

Image::ExifTool::FotoStation - Read/write FotoWare FotoStation trailer

=head1 SYNOPSIS

This module is used by Image::ExifTool

=head1 DESCRIPTION

This module contains definitions required by Image::ExifTool to read and
write information from the FotoWare FotoStation trailer.

=head1 AUTHOR

Copyright 2003-2011, 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 ACKNOWLEDGEMENTS

Thanks to Mark Tate for information about the FotoStation data format.

=head1 SEE ALSO

L&lt;Image::ExifTool::TagNames/FotoStation Tags&gt;,
L&lt;Image::ExifTool(3pm)|Image::ExifTool&gt;

=cut

</pre></body></html>