#!/usr/bin/perl -w # # png-text - extract tEXt blocks from PNG files # # for more info on PNG, see: http://www.cdrom.com/pub/png/pngdocs.html use strict; use Getopt::Long; my $debug; GetOptions("d|debug:i" => \$debug); if (defined $debug) { ++$debug; } else { $debug = 0; } # valid signature / magic number at the top of PNG files my $valid_sig = join "", map { chr } qw(137 80 78 71 13 10 26 10); # hash to code refs my %decoder; # ================================================== # tEXt chunks my $num_tEXt_chunks = 0; sub decode_tEXt { my ($size, $type, $data, $crc) = @_; my ($key, $text) = split chr(0), $data, 2; my $lkey = length($key); my $ltext = length($text); print <<"EOT"; tEXt chunk $num_tEXt_chunks: key = "$key" ($lkey bytes) value = "$text" ($ltext bytes) EOT ++$num_tEXt_chunks; } $decoder{tEXt} = \&decode_tEXt; # ================================================== # main loop FILE: for my $file (@ARGV) { # sanity check unless (-f $file && -r _) { print STDERR "\"$file\" is not a file or is not readable, skipping\n"; next FILE; } unless (open F, $file) { print STDERR "couldn't open \"$file\", skipping: $!\n"; next FILE; } my $sig; read F, $sig, 8 or die "read size_and_name: $!"; if ($sig ne $valid_sig) { print STDERR "invalid PNG file \"$file\" [bad signature], skipping\n"; close F; next FILE; } CHUNK: while (1) { my $size_and_type; read F, $size_and_type, 8 or die "read size_and_name: $!"; my ($size, $type) = unpack "N A4", $size_and_type; print STDERR "found chunk \"$type\" ($size bytes)\n" if $debug > 1; last CHUNK if $type eq "IEND"; my ($data, $crc); read F, $data, $size or die "read data: $!"; read F, $crc, 4 or die "read crc: $!"; if (exists $decoder{$type}) { $decoder{$type}->($size, $type, $data, $crc); } } }