File Coverage

blib/lib/Image/MetaData/JPEG/dumpers/app13.pl
Criterion Covered Total %
statement 51 51 100.0
branch 15 18 83.3
condition n/a
subroutine 7 7 100.0
pod 0 3 0.0
total 73 79 92.4


line stmt bran cond sub pod time code
1             ###########################################################
2             # A Perl package for showing/modifying JPEG (meta)data. #
3             # Copyright (C) 2004,2005,2006 Stefano Bettelli #
4             # See the COPYING and LICENSE files for license terms. #
5             ###########################################################
6 15     15   83 use Image::MetaData::JPEG::data::Tables qw(:TagsAPP13);
  15         29  
  15         2500  
7 15     15   85 no integer;
  15         31  
  15         91  
8 15     15   323 use strict;
  15         27  
  15         439  
9 15     15   73 use warnings;
  15         27  
  15         10116  
10              
11             ###########################################################
12             # This routine dumps the Adobe identifier and then enters #
13             # a loop on the resource data block dumper, till the end. #
14             # TODO: implement dumping of multiple blocks!!!! #
15             ###########################################################
16             sub dump_app13 {
17 97     97 0 145 my ($this) = @_;
18             # get a reference to the segment record list
19 97         214 my $records = $this->{records};
20             # the segment always starts with an Adobe identifier
21 97 50       300 $this->die('Identifier not found') unless
22             my $id = $this->search_record_value('Identifier');
23 97         423 $this->set_data($id);
24             # version 2.5 (old) is followed by eight undocumented bytes
25             # (maybe resolution info): output them if present and valid
26 97         312 my $rec = $this->search_record('Resolution');
27 97 50       411 $this->die('Header problem') unless (defined $rec) eq ($id =~ /2\.5/);
28 97 50       227 $this->set_data($rec->get_value()) if $rec;
29             # for each possible IPTC record number (remember that there can be
30             # multiple IPTC subdirs, referring to different IPTC records), dump
31             # the corresponding IPTC block, if present; the easiest solution is
32             # to create a fake Record, which is then dumped as usual
33 97         242 for my $r_number (1..9) {
34 873 100       3437 next unless my $record
35             = $this->search_record("${APP13_IPTC_DIRNAME}_${r_number}");
36 98         343 my $content = $record->get_value();
37 98         321 my $block = dump_IPTC_datasets($r_number, $content);
38 98         441 my $fake_record = new Image::MetaData::JPEG::Record
39             ($APP13_PHOTOSHOP_IPTC, $UNDEF, \ $block, length $block);
40 98         256 $fake_record->{extra} = $record->{extra};
41 98         381 $this->dump_resource_data_block($fake_record); }
42             # do the same on all non-IPTC subdirs (remember that there can be
43             # multiple non-IPTC subdirs, with type '8BIM', '8BPS', 'PHUT', ...)
44 97         275 for my $type (@$APP13_PHOTOSHOP_TYPE) {
45 291 100       1202 next unless my $record
46             = $this->search_record("${APP13_PHOTOSHOP_DIRNAME}_${type}");
47 86         157 $this->dump_resource_data_block($_,$type) for @{$record->get_value()};}
  86         257  
48             # return without errors
49 97         427 return undef;
50             }
51              
52             ###########################################################
53             # TODO: implement dumping of multiple blocks!!!! #
54             ###########################################################
55             sub dump_resource_data_block {
56 1399     1399 0 2058 my ($this, $record, $type) = @_;
57             # try to extract an optional name from the extra field
58 1399 100       3195 my $name = $record->{extra} ? $record->{extra} : '';
59             # provide a default type if $type is null
60 1399 100       2684 $type = $$APP13_PHOTOSHOP_TYPE[0] unless $type;
61             # dump the resource data block type
62 1399         3626 $this->set_data($type);
63             # dump the block identifier, which is the numeric tag
64             # of the record (as a 2-byte unsigned integer).
65 1399         5544 $this->set_data(pack "n", $record->{key});
66             # the block name is usually "\000"; calculate its length,
67             # then pad it so that storing the name length (1 byte)
68             # + $name + padding takes an even number of bytes
69 1399         2065 my $name_length = length $name;
70 1399 100       2954 my $padding = ($name_length % 2) == 0 ? "\000" : "";
71 1399         5168 $this->set_data(pack("C", $name_length) . $name . $padding);
72             # initialise $data with the record dump.
73 1399         4274 my $data = $record->get();
74             # the next four bytes encode the resource data size. Also in this
75             # case the total size must be padded to an even number of bytes
76 1399         2084 my $data_length = length $data;
77 1399 100       3683 $data .= "\000" if ($data_length % 2) == 1;
78 1399         5107 $this->set_data(pack("N", $data_length));
79 1399         4034 $this->set_data($data);
80             }
81              
82             ###########################################################
83             # This auxiliary routine dumps all IPTC datasets in the #
84             # @$record subdirectory, referring to the $r_number IPTC #
85             # record, and concatenates them into a string, which is #
86             # returned at the end. See parse_IPTC_dataset for details.#
87             ###########################################################
88             sub dump_IPTC_datasets {
89 98     98 0 195 my ($r_number, $record) = @_;
90             # prepare the scalar to be returned at the end
91 98         176 my $block = "";
92             # Each IPTC record is a sequence of variable length data sets. Each
93             # dataset begins with a "tag marker" (its value is fixed) followed
94             # by the "record number" (given by $r_number), followed by the
95             # dataset number, length and data.
96 98         214 for (@$record) {
97 910         2656 my ($dnumber, $type, $count, $dataref) = $_->get();
98 910         3115 $block .= pack "CCCn", ($APP13_IPTC_TAGMARKER, $r_number,
99             $dnumber, length $$dataref);
100 910         1804 $block .= $$dataref;
101             }
102             # return the encoded datasets
103 98         314 return $block;
104             }
105              
106             # successful load
107             1;