Image-ExifTool

 view release on metacpan or  search on metacpan

lib/Image/ExifTool/WriteXMP.pl  view on Meta::CPAN

            # match last index except for lang-alt items where we want to put each
            # item in a different lang-alt list (so match the 2nd-last for these)
            my $pat = $writable eq 'lang-alt' ? '.* (\d+)(.*? \d+)' : '.* (\d+)';
            pos($path) = 0;
            $path =~ m/$pat/g or warn("Internal error: no list index for $tag ($path) ($pat)!\n"), next;
            my $idx = $1;
            my $len = length $1;
            my $pos = pos($path) - $len - ($2 ? length $2 : 0);
            # use sub-indices if necessary to store additional values in sequence
            if ($subIdx) {
                $idx = substr($idx, 0, -length($subIdx));   # remove old sub-index
                $subIdx = substr($subIdx, 1) + 1;
                $subIdx = length($subIdx) . $subIdx;
            } elsif (@delPaths) {
                $path = shift @delPaths;
                # make sure new path is unique
                while ($capture{$path}) {
                    last unless $path =~ s/ \d(\d+)$/' '.length($1+1).($1+1)/e;
                }
                next;
            } else {
                $subIdx = '10';
            }
            substr($path, $pos, $len) = $idx . $subIdx;
        }
        # make sure any empty structures are deleted
        # (ExifTool shouldn't write these, but other software may)
        if (defined $$tagInfo{Flat}) {
            my $p = $path;
            while ($p =~ s/\/[^\/]+$//) {
                next unless $capture{$p};
                # it is an error if this property has a value
                $et->Error("Improperly structured XMP ($p)",1) if $capture{$p}[0] =~ /\S/;
                delete $capture{$p};    # delete the (hopefully) empty structure
            }
        }
    }
    # remove the ExifTool members we created
    delete $$et{XMP_CAPTURE};
    delete $$et{XMP_NS};

    my $maxDataLen = $$dirInfo{MaxDataLen};
    # get DataPt again because it may have been set by ProcessXMP
    $dataPt = $$dirInfo{DataPt};

    # return now if we didn't change anything
    unless ($changed or ($maxDataLen and $dataPt and defined $$dataPt and
        length($$dataPt) > $maxDataLen))
    {
        return undef unless $xmpFile;   # just rewrite original XMP
        Write($$dirInfo{OutFile}, $$dataPt) or return -1 if $dataPt and defined $$dataPt;
        return 1;
    }
#
# write out the new XMP information (serialize it)
#
    # start writing the XMP data
    my (@long, @short, @resFlag);
    $long[0] = $long[1] = $short[0] = '';
    if ($$et{XMP_NO_XPACKET}) {
        # write BOM if flag is set
        $long[-2] .= "\xef\xbb\xbf" if $$et{XMP_NO_XPACKET} == 2;
    } else {
        $long[-2] .= $pktOpen;
    }
    $long[-2] .= $xmlOpen if $$et{XMP_IS_XML};
    $long[-2] .= $xmpOpen . $rdfOpen;

    # initialize current property path list
    my (@curPropList, @writeLast, @descStart, $extStart);
    my (%nsCur, $prop, $n, $path);
    my @pathList = sort TypeFirst keys %capture;
    # order properties to write large values last if we have a MaxDataLen limit
    if ($maxDataLen and @pathList) {
        my @pathTmp;
        my ($lastProp, $lastNS, $propSize) = ('', '', 0);
        my @pathLoop = (@pathList, ''); # add empty path to end of list for loop
        undef @pathList;
        foreach $path (@pathLoop) {
            $path =~ /^((\w*)[^\/]*)/;  # get path element ($1) and ns ($2)
            if ($1 eq $lastProp) {
                push @pathTmp, $path;   # accumulate all paths with same root
            } else {
                # put in list to write last if recommended or values are too large
                if ($extendedRes{$lastProp} or $extendedRes{$lastNS} or
                    $propSize > $newDescThresh)
                {
                    push @writeLast, @pathTmp;
                } else {
                    push @pathList, @pathTmp;
                }
                last unless $path;      # all done if we hit empty path
                @pathTmp = ( $path );
                ($lastProp, $lastNS, $propSize) = ($1, $2, 0);
            }
            $propSize += length $capture{$path}->[0];
        }
    }

    # write out all properties
    for (;;) {
        my (%nsNew, $newDesc);
        unless (@pathList) {
            last unless @writeLast;
            @pathList = @writeLast;
            undef @writeLast;
            $newDesc = 2;   # start with a new description for the extended data
        }
        $path = shift @pathList;
        my @propList = split('/',$path); # get property list
        # must open/close rdf:Description too
        unshift @propList, $rdfDesc;
        # make sure we have defined all necessary namespaces
        foreach $prop (@propList) {
            $prop =~ /(.*):/ or next;
            $1 eq 'rdf' and next;       # rdf namespace already defined
            my $uri = $nsUsed{$1};
            unless ($uri) {
                $uri = $nsURI{$1};      # we must have added a namespace
                unless ($uri) {
                    # (namespace prefix may be empty if trying to write empty XMP structure, forum12384)



( run in 0.594 second using v1.01-cache-2.11-cpan-39bf76dae61 )