@@ -1,3 +1,24 @@
+0.159 2015-05-11 Ricardo Signes <rjbs@cpan.org>
+
+ - deal with >4b APP0 (thanks, isync!)
+ - add metadata to distribution
+ - clean up pod abstracts
+
+2014-05-12 Ricardo Signes <rjbs@cpan.org>
+
+ * avoid useless use of ? modifier on fixed-length {n} repetition
+ in regex; avoids a warning in 5.20.0
+
+2014-02-04 Ricardo Signes <rjbs@cpan.org>
+
+ * avoid having output corrupted by assignment to $,
+
+2014-02-02 Ricardo Signes <rjbs@cpan.org>
+
+ * only run Pod::Checker tests when releasing
+ * encode all source at UTF-8, including comments
+ * add =encoding directives to Pod where needed
+
2009-06-18 Stefano Bettelli <bettelli@cpan.org>
* lib/Image/MetaData/JPEG.pm: setting $VERSION to 0.153, and
@@ -30,6 +30,8 @@ t/mknt_Pentax_Optio430.jpg
t/mknt_Sony_MVC-CD500.jpg
t/mknt_Toshiba_PDRM70.jpg
t/test_frankenstein.jpg
+t/test_APP0_Ocad.jpg
+t/test_APP0_AJPEG.jpg
t/test_photo.desc
t/test_photo.jpg
t/test_thumbnail.jpg
@@ -62,4 +64,5 @@ lib/Image/MetaData/JPEG/access/various.pl
lib/Image/MetaData/JPEG/access/comments.pl
lib/Image/MetaData/JPEG/access/app1_exif.pl
lib/Image/MetaData/JPEG/access/app13.pl
-META.yml
+META.yml Module YAML meta-data (added by MakeMaker)
+META.json Module JSON meta-data (added by MakeMaker)
@@ -0,0 +1,46 @@
+{
+ "abstract" : "Perl extension for showing/modifying JPEG (meta)data.",
+ "author" : [
+ "Stefano Bettelli <bettelli@cpan.org>"
+ ],
+ "dynamic_config" : 1,
+ "generated_by" : "ExtUtils::MakeMaker version 7.04, CPAN::Meta::Converter version 2.143240",
+ "license" : [
+ "unknown"
+ ],
+ "meta-spec" : {
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
+ "version" : "2"
+ },
+ "name" : "Image-MetaData-JPEG",
+ "no_index" : {
+ "directory" : [
+ "t",
+ "inc"
+ ]
+ },
+ "prereqs" : {
+ "build" : {
+ "requires" : {
+ "ExtUtils::MakeMaker" : "0"
+ }
+ },
+ "configure" : {
+ "requires" : {
+ "ExtUtils::MakeMaker" : "0"
+ }
+ },
+ "runtime" : {
+ "requires" : {}
+ }
+ },
+ "release_status" : "stable",
+ "resources" : {
+ "repository" : {
+ "type" : "git",
+ "url" : "https://github.com/rjbs/Image-MetaData-JPEG.git",
+ "web" : "https://github.com/rjbs/Image-MetaData-JPEG"
+ }
+ },
+ "version" : "0.159"
+}
@@ -1,13 +1,23 @@
---- #YAML:1.0
-name: Image-MetaData-JPEG
-version: 0.153
-abstract: Perl extension for showing/modifying JPEG (meta)data.
-license: ~
-author:
- - Stefano Bettelli <bettelli@cpan.org>
-generated_by: ExtUtils::MakeMaker version 6.42
-distribution_type: module
-requires:
+---
+abstract: 'Perl extension for showing/modifying JPEG (meta)data.'
+author:
+ - 'Stefano Bettelli <bettelli@cpan.org>'
+build_requires:
+ ExtUtils::MakeMaker: '0'
+configure_requires:
+ ExtUtils::MakeMaker: '0'
+dynamic_config: 1
+generated_by: 'ExtUtils::MakeMaker version 7.04, CPAN::Meta::Converter version 2.143240'
+license: unknown
meta-spec:
- url: http://module-build.sourceforge.net/META-spec-v1.3.html
- version: 1.3
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: '1.4'
+name: Image-MetaData-JPEG
+no_index:
+ directory:
+ - t
+ - inc
+requires: {}
+resources:
+ repository: https://github.com/rjbs/Image-MetaData-JPEG.git
+version: '0.159'
@@ -7,12 +7,22 @@
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
-WriteMakefile
- (NAME => 'Image::MetaData::JPEG',
- VERSION_FROM => 'lib/Image/MetaData/JPEG.pm',
- PREREQ_PM => {}, # e.g., Module::Name => 1.1
- ($] >= 5.005 ? ## Add these new keywords supported since 5.005
- (ABSTRACT_FROM => 'lib/Image/MetaData/JPEG.pod',
- AUTHOR => 'Stefano Bettelli <bettelli@cpan.org>') : ()),
- clean => {FILES => "*~ */*~ */*/*~ */*/*/*~ */*/*/*/*~"},
- );
+WriteMakefile(
+ NAME => 'Image::MetaData::JPEG',
+ VERSION_FROM => 'lib/Image/MetaData/JPEG.pm',
+ PREREQ_PM => {}, # e.g., Module::Name => 1.1
+ META_MERGE => {
+ 'meta-spec' => { version => 2 },
+ resources => {
+ repository => {
+ type=> 'git',
+ url => 'https://github.com/rjbs/Image-MetaData-JPEG.git',
+ web => 'https://github.com/rjbs/Image-MetaData-JPEG',
+ },
+ },
+ },
+ clean => {FILES => "*~ */*~ */*/*~ */*/*/*~ */*/*/*/*~"},
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'lib/Image/MetaData/JPEG.pod',
+ AUTHOR => 'Stefano Bettelli <bettelli@cpan.org>') : ()),
+);
@@ -12,12 +12,16 @@
=head1 NAME
-Image::MetaData::JPEG::MakerNotes - This document contains random
-information and details on MakerNotes; it is an appendix to the main manual
-page of the L<Image::MetaData::JPEG> module, which the reader should refer
-to for further details and the general scope. The note on L<MakerNote
-parsing|Image::MetaData::JPEG/On the problem of MakerNote corruption and
-ways to overcome it> in the main manual page is of particular interest.
+Image::MetaData::JPEG::MakerNotes - random information and details on MakerNotes
+
+=head1 OVERVIEW
+
+This document contains random information and details on MakerNotes; it is an
+appendix to the main manual page of the L<Image::MetaData::JPEG> module, which
+the reader should refer to for further details and the general scope. The note
+on L<MakerNote parsing|Image::MetaData::JPEG/On the problem of MakerNote
+corruption and ways to overcome it> in the main manual page is of particular
+interest.
=head1 Pieces of information available after parsing the MakerNote
@@ -259,7 +259,7 @@ sub output_segment_data {
$preamble .= pack("n", 2 + $length)
unless $name =~ /SOI|EOI|RST|ECS|Post-EOI/;
# output the preamble and the data buffer (return the status)
- return print {$out} $preamble, $this->data(0, $length);
+ return print {$out} $preamble . $this->data(0, $length);
}
###########################################################
@@ -10,9 +10,15 @@
# type "perldoc <name_of_this_file>". #
###########################################################
+=encoding utf-8
+
=head1 NAME
-Image::MetaData::JPEG::Structures - This document describes the structure
+Image::MetaData::JPEG::Structures - describes the structure of a JPEG file
+
+=head1 OVERVIEW
+
+This document describes the structure
of a JPEG file; it is an appendix to the main manual page of the
L<Image::MetaData::JPEG> module, which the reader should refer to for
further details and the general scope.
@@ -630,7 +636,7 @@ JPEG Segments):
The reference document for the IPTC standard is:
B<"IPTC-NAA: Information Interchange Model", version 4, 1-Jul-1999,
- Comité International des Télécommunications de Presse>
+ Comité International des Télécommunications de Presse>
=head1 AUTHOR
@@ -12,10 +12,13 @@
=head1 NAME
-Image::MetaData::JPEG::TagLists - This document contains a collection of
-tag tables for JPEG segments; it is an appendix to the main manual page of
-the L<Image::MetaData::JPEG> module, which the reader should refer to for
-further details and the general scope.
+Image::MetaData::JPEG::TagLists - a collection of tag tables for JPEG segments
+
+=head1 OVERVIEW
+
+This document contains a collection of tag tables for JPEG segments; it is an
+appendix to the main manual page of the L<Image::MetaData::JPEG> module, which
+the reader should refer to for further details and the general scope.
=head1 Valid tags for Exif APP1 data
@@ -733,8 +736,8 @@ C-strings).
2:xx datasets from the application record (editorial tags)
-------------------------------------------------------------------------
0 RecordVersion N [ 2 ] binary, always 2 in JPEGs ?
- 3 ObjectTypeReference N [ 3-67 ] /\d{2}?:[\w\s]{0,64}?/
- 4 ObjectAttributeReference [ 4-68 ] /\d{3}?:[\w\s]{0,64}?/
+ 3 ObjectTypeReference N [ 3-67 ] /\d{2}:[\w\s]{0,64}?/
+ 4 ObjectAttributeReference [ 4-68 ] /\d{3}:[\w\s]{0,64}?/
5 ObjectName N [ <=64 ] line (see note 5)
7 EditStatus N [ <=64 ] line (see note 5)
8 EditorialUpdate N [ 2 ] /01/
@@ -767,7 +770,7 @@ C-strings).
90 City N [ <=32 ] line (see note 5)
92 SubLocation N [ <=32 ] line (see note 5)
95 Province/State N [ <=32 ] line (see note 5)
- 100 Country/PrimaryLocationCode N [ 3 ] /[A-Z]{3}?/
+ 100 Country/PrimaryLocationCode N [ 3 ] /[A-Z]{3}/
101 Country/PrimaryLocationName N [ <=64 ] line (see note 5)
103 OriginalTransmissionReference N [ <=32 ] line (see note 5)
105 Headline N [ <=256] line (see note 5)
@@ -782,8 +785,8 @@ C-strings).
131 ImageOrientation N [ 1 ] /P|L|S/
135 LanguageIdentifier N [ 2-3 ] /[a-zA-Z]{2,3}?/
150 AudioType N [ 2 ] /[012][ACMQRSTVW]/
- 151 AudioSamplingRate N [ 6 ] /\d{6}?/
- 152 AudioSamplingResolution N [ 2 ] /\d{2}?/
+ 151 AudioSamplingRate N [ 6 ] /\d{6}/
+ 152 AudioSamplingResolution N [ 2 ] /\d{2}/
153 AudioDuration N [ 6 ] duration (see note 6)
154 AudioOutcue N [ <=64 ] line (see note 5)
200 ObjDataPreviewFileFormat N [ 2 ] invalid, binary (see 1:20)
@@ -822,7 +825,7 @@ C-strings).
6) A "duration" is stored like a "time", but there is no time zone spec;
this means that the string is only six characters wide (see also note 3).
7) The complicated regular expression for the SubjectReference is the
- following: /[$validchar]{1,32}?:[01]\d{7}?(:[$validchar\s]{0,64}?){3}?/,
+ following: /[$validchar]{1,32}?:[01]\d{7}(:[$validchar\s]{0,64}?){3}/,
where $validchar is '\040-\051\053-\071\073-\076\100-\176'.
=head1 AUTHOR
@@ -739,7 +739,7 @@ my $IPTC_re_date = $re_date; # CCYYMMDD full #
my $IPTC_re_dura = $re_time; # HHMMSS #
my $IPTC_re_time = $IPTC_re_dura . '[\+-]' . $re_zone; # HHMMSS+/-HHMM #
my $vchr = '\040-\051\053-\071\073-\076\100-\176'; # (SubjectRef.) #
-my $IPTC_re_sure='['.$vchr.']{1,32}?:[01]\d{7}?(:['.$vchr.'\s]{0,64}?){3}?'; #
+my $IPTC_re_sure='['.$vchr.']{1,32}?:[01]\d{7}(:['.$vchr.'\s]{0,64}?){3}'; #
#--- Mandatory records ------------------------------------------------------#
my $HASH_IPTC_MANDATORY_1 = {'ModelVersion' => "\000\004" }; #
my $HASH_IPTC_MANDATORY_2 = {'RecordVersion' => "\000\002" }; #
@@ -762,8 +762,8 @@ my $HASH_IPTC_GENERAL_1 = #
#--- Legal records' list ( datasets 2:xx ) ----------------------------------#
my $HASH_IPTC_GENERAL_2 = #
{0 => ['RecordVersion', 'N', 2, 2, 'binary' ], #
- 3 => ['ObjectTypeReference', 'N', 3, 67, '\d{2}?:[\w\s]{0,64}?'], #
- 4 => ['ObjectAttributeReference', ' ', 4, 68, '\d{3}?:[\w\s]{0,64}?'], #
+ 3 => ['ObjectTypeReference', 'N', 3, 67, '\d{2}:[\w\s]{0,64}?' ], #
+ 4 => ['ObjectAttributeReference', ' ', 4, 68, '\d{3}:[\w\s]{0,64}?' ], #
5 => ['ObjectName', 'N', 1, 64, $IPTC_re_line ], #
7 => ['EditStatus', 'N', 1, 64, $IPTC_re_line ], #
8 => ['EditorialUpdate', 'N', 2, 2, '01' ], #
@@ -796,7 +796,7 @@ my $HASH_IPTC_GENERAL_2 = #
90 => ['City', 'N', 1, 32, $IPTC_re_line ], #
92 => ['SubLocation', 'N', 1, 32, $IPTC_re_line ], #
95 => ['Province/State', 'N', 1, 32, $IPTC_re_line ], #
- 100 => ['Country/PrimaryLocationCode', 'N', 3, 3, '[A-Z]{3}?' ], #
+ 100 => ['Country/PrimaryLocationCode', 'N', 3, 3, '[A-Z]{3}' ], #
101 => ['Country/PrimaryLocationName', 'N', 1, 64, $IPTC_re_line ], #
103 => ['OriginalTransmissionReference','N',1, 32, $IPTC_re_line ], #
105 => ['Headline', 'N', 1,256, $IPTC_re_line ], #
@@ -811,8 +811,8 @@ my $HASH_IPTC_GENERAL_2 = #
131 => ['ImageOrientation', 'N', 1, 1, '[PLS]' ], #
135 => ['LanguageIdentifier', 'N', 2, 3, '[a-zA-Z]{2,3}?' ], #
150 => ['AudioType', 'N', 2, 2, '[012][ACMQRSTVW]' ], #
- 151 => ['AudioSamplingRate', 'N', 6, 6, '\d{6}?' ], #
- 152 => ['AudioSamplingResolution', 'N', 2, 2, '\d{2}?' ], #
+ 151 => ['AudioSamplingRate', 'N', 6, 6, '\d{6}' ], #
+ 152 => ['AudioSamplingResolution', 'N', 2, 2, '\d{2}' ], #
153 => ['AudioDuration', 'N', 6, 6, $IPTC_re_dura ], #
154 => ['AudioOutcue', 'N', 1, 64, $IPTC_re_line ], #
200 => ['ObjDataPreviewFileFormat', 'N', 2, 2, 'invalid,binary' ], #
@@ -72,15 +72,25 @@ sub parse_app0 {
my ($this) = @_;
my $offset = 0;
my $thumb_x_dim = 0; my $thumb_y_dim = 0;
- # first, decode the identifier. It can be simple
- # (JFIF), or extended (JFXX). We need five bytes
+
+ # Decode the APP0 app-extension identifier. It's an arbitrarily
+ # long string, terminated by binary zero. Find length:
+ my $length = 1; # assuming the app id is at least one byte long should be safe
+ for(;;){
+ my $byte = $this->data($length, 1);
+ last if $byte eq "\x00";
+ last if $length >= $this->size(); # no infinite loop
+ $length++;
+ }
my $identifier = $this->store_record
- ('Identifier', $ASCII, $offset, length $APP0_JFIF_TAG)->get_value();
- # go to the relevant decoding routine depending on it
+ ('Identifier', $ASCII, $offset, $length + 1)->get_value(); # +1 as Tables.pm currently includes the null-terminator
+ # go to the appropriate decoding routine depending on found identifier
goto APP0_simple if $identifier eq $APP0_JFIF_TAG;
goto APP0_extended if $identifier eq $APP0_JFXX_TAG;
- # if we are still here, let us die of an unknown identifier
- $this->die("Unknown identifier ($identifier)");
+ # JPEG specs tell us to simply ignore unknown identifiers
+ # $this->die("Unknown identifier ($identifier)");
+ $offset += ($this->size() - $length - 1); # skip over (NOPARSE) unknown data
+ goto APP0_END;
APP0_simple:
# as far as I know, in a JFIF APP0 there are always the following
# seven fields, even if the thumbnail is absent. This means that
@@ -183,7 +183,7 @@ sub parse_resource_data_block {
# order, but this rule is currently not enforced here. #
#=========================================================#
# Ref: "IPTC-NAA: Information Interchange Model Version 4"#
-# Comité Internat. des Télécommunications de Presse. #
+# Comité Internat. des Télécommunications de Presse. #
###########################################################
sub parse_IPTC_dataset {
my ($this, $offset) = @_;
@@ -12,7 +12,7 @@ no integer;
use strict;
use warnings;
-our $VERSION = '0.153';
+our $VERSION = '0.159';
###########################################################
# These simple methods should be used instead of standard #
@@ -10,6 +10,8 @@
# type "perldoc <name_of_this_file>". #
###########################################################
+=encoding utf-8
+
=head1 NAME
Image::MetaData::JPEG - Perl extension for showing/modifying JPEG (meta)data.
@@ -1541,7 +1543,7 @@ expanded. The output is nicely formatted, with indentation and
colouration; this program is a great tool for inspecting a JPEG/TIFF
structure while debugging.
-=item "libexif" by Lutz Müller
+=item "libexif" by Lutz Müller
This is a library, written in C, for parsing, editing, and saving Exif
data. All Exif tags described in Exif standard 2.1 are supported. Libexif
@@ -1,9 +1,11 @@
-use Test::More tests => 33;
+use Test::More tests => 45;
BEGIN { require 't/test_setup.pl'; }
my $tphoto = 't/test_photo.jpg';
my $tdata = 't/test_photo.desc';
my $tfrank = 't/test_frankenstein.jpg';
+my $t_app0_ocad = 't/test_APP0_Ocad.jpg'; # file with photobucket's Ocad "marker" segment
+my $t_app0_ajpeg = 't/test_APP0_AJPEG.jpg'; # file with Animated JPEG segment
my $trim = sub { join '\n', map { s/^.*\"(.*)\".*$/$1/; $_ }
grep { /0:/ } split '\n', $_[0] };
my ($image, @segs, $seg, $hash, $num, $rec, $problem, $data);
@@ -157,6 +159,54 @@ $data = "\377\330\377\376\000\010com"; # not enough data
trap_error('DIE', 'newimage(\ $data)');
like( $problem, qr/data not found/, "Error on segment too short" );
+
+# test parsing a photobucket file with APP0 "Ocad" marker
+#########################
+{ local $SIG{'__WARN__'} = sub { $problem = shift; };
+ $problem = undef; $image = newimage($t_app0_ocad); }
+isnt( $image, undef, "test_APP0_Ocad file read" );
+
+#########################
+ok( !$problem, "No warnings generated during file read" );
+
+#########################
+$num = scalar $image->get_segments();
+is( $num, 37, "Number of segments is correct" );
+
+#########################
+$num = scalar grep { $_->{error} } $image->get_segments();
+is( $num, 0, "No segment shows an error condition");
+
+#########################
+@segs = $image->get_segments('APP0');
+$num = grep { /^Ocad\$Rev: 14797/i } map { $_->search_record_value('Identifier') } @segs;
+is( $num, 1, "APP0 Ocad identifier found" );
+is( length($segs[1]->{records}->[0]->{values}->[0]), 17+1, "APP0 Ocad identifier length ok" ); # currently Tables.pm includes the null-terminator, so does app0.pl
+
+
+# test parsing an Animated JPEG file with APP0 "AJPEG" marker
+#########################
+{ local $SIG{'__WARN__'} = sub { $problem = shift; };
+ $problem = undef; $image = newimage($t_app0_ajpeg); }
+isnt( $image, undef, "test_APP0_AJPEG file read" );
+
+#########################
+ok( !$problem, "No warnings generated during file read" );
+
+#########################
+$num = scalar $image->get_segments();
+is( $num, 14, "Number of segments is correct" );
+
+#########################
+$num = scalar grep { $_->{error} } $image->get_segments();
+is( $num, 0, "No segment shows an error condition");
+
+#########################
+@segs = $image->get_segments('APP0');
+$num = grep { /^AJPEG/ } map { $_->search_record_value('Identifier') } @segs;
+is( $num, 1, "APP0 AJPEG identifier found" );
+is( length($segs[1]->{records}->[0]->{values}->[0]), 5+1, "APP0 AJPEG identifier length ok" ); # currently Tables.pm includes the null-terminator, so does app0.pl
+
### Local Variables: ***
### mode:perl ***
### End: ***
@@ -5,11 +5,19 @@ BEGIN { my $root = "lib/Image/MetaData";
"$name/TagLists.pod",
"$name/MakerNotes.pod"); }
-BEGIN { my $Available = undef;
- my $DoTests = "use Test::More tests => " . scalar @::docfiles;
- my $SkipTests = "use Test::More skip_all => 'Pod::Checker unavailable'";
- eval { require Pod::Checker; $Available = 'yes'; };
- if ($Available) { eval "$DoTests"; } else { eval "$SkipTests"; } }
+use Test::More;
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ plan skip_all => "test only run during release process";
+ }
+ my $Available = eval { require Pod::Checker; 1 };
+ if (! $Available) {
+ plan skip_all => 'Pod::Checker unavailable';
+ }
+
+ plan tests => 0+@::docfiles;
+}
BEGIN { require 't/test_setup.pl'; }
diff --git a/var/tmp/source/RJBS/Image-MetaData-JPEG-0.159/Image-MetaData-JPEG-0.159/t/test_APP0_AJPEG.jpg b/var/tmp/source/RJBS/Image-MetaData-JPEG-0.159/Image-MetaData-JPEG-0.159/t/test_APP0_AJPEG.jpg
new file mode 100644
index 00000000..1b5da4b8
Binary files /dev/null and b/var/tmp/source/RJBS/Image-MetaData-JPEG-0.159/Image-MetaData-JPEG-0.159/t/test_APP0_AJPEG.jpg differ
diff --git a/var/tmp/source/RJBS/Image-MetaData-JPEG-0.159/Image-MetaData-JPEG-0.159/t/test_APP0_Ocad.jpg b/var/tmp/source/RJBS/Image-MetaData-JPEG-0.159/Image-MetaData-JPEG-0.159/t/test_APP0_Ocad.jpg
new file mode 100644
index 00000000..5119e844
Binary files /dev/null and b/var/tmp/source/RJBS/Image-MetaData-JPEG-0.159/Image-MetaData-JPEG-0.159/t/test_APP0_Ocad.jpg differ