3 use IO::Uncompress::Inflate qw(inflate);
7 GetOptions(dumpall => \$dumpall);
10 or die "Usage: $0 filename\n";
12 open my $fh, "<", $file
13 or die "$0: cannot open '$file': $!\n";
18 read($fh, $head, 8) == 8
19 or die "Cann't read header: $!\n";
22 dump_data($offset, $head);
24 $offset += length $head;
25 unless ($head eq "\x89PNG\x0d\x0A\cZ\x0A") {
26 die "Header isn't a PNG header\n";
30 while (my ($dlen, $data, $len, $type, $payload, $crc) = read_chunk($fh)) {
31 dump_data($offset, $data);
33 my $calc_crc = crc($type . $payload);
34 my $src_crc = unpack("N", $crc);
36 $type =~ s/([^ -\x7f])/sprintf("\\x%02x", ord $1)/ge;
37 print " Type: $type\n";
38 print " Length: $len\n";
39 printf " CRC: %x (calculated: %x)\n", $src_crc, $calc_crc;
40 if ($type eq 'IHDR') {
41 my ($w, $h, $d, $ct, $comp, $filter, $inter) =
42 unpack("NNCCCCC", $payload);
53 elsif ($type eq 'sRGB') {
54 print " Rendering intent: ", ord($payload), "\n";
56 elsif ($type eq 'PLTE') {
58 while ($index * 3 < $len) {
59 my @rgb = unpack("CCC", substr($payload, $index * 3, 3));
60 print " $index: @rgb\n";
64 elsif ($type eq 'tRNS') {
65 if ($colour_type == 0) {
66 my $g = unpack("n", $payload);
67 printf " Grey: %d (%x)\n", $g, $g;
69 elsif ($colour_type == 2) {
70 my @rgb = unpack("nnn", $payload);
71 printf " RGB: %d, %d, %d (%x, %x, %x)\n", @rgb, @rgb;
73 elsif ($colour_type == 3) {
75 for my $alpha (unpack("C*", $payload)) {
76 print " Index: $index: $alpha\n";
81 print " Unexpected tRNS for colour type $colour_type\n";
84 elsif ($type eq 'pHYs') {
85 my ($hres, $vres, $unit) = unpack("NNC", $payload);
86 my $unitname = $unit == 1 ? "metre" : "unknown";
88 hRes: $hres / $unitname
89 vRes: $vres / $unitname
90 Unit: $unit ($unitname)
93 elsif ($type eq 'tEXt') {
94 my ($key, $value) = split /\0/, $payload, 2;
99 do_more_text($key, $value);
101 elsif ($type eq 'zTXt') {
102 my ($key, $rest) = split /\0/, $payload, 2;
103 my $ctype = ord $rest;
104 my $ztxt = substr($rest, 1);
105 my $value = do_inflate($ztxt);
110 do_more_text($key, $value);
118 my ($key, $text) = @_;
120 if ($key eq 'Raw profile type xmp'
121 && $text =~ s/^\s*xmp\s+\d+\s+//) {
122 print " XMP: ", pack("H*", join('', split ' ', $text)), "\n";
131 or die "Cannot read chunk length\n";
132 my $len = unpack("N", $rlen);
135 or die "Cannot read chunk type\n";
138 read($fh, $payload, $len) == $len
139 or die "Cannot read payload\n";
142 read($fh, $crc, 4) == 4
143 or die "Cannot read CRC\n";
145 return ( $len + 12, $rlen . $type . $payload . $crc, $len, $type, $payload, $crc );
149 my ($offset, $data) = @_;
151 if (length $data > 28) {
153 for my $i (0 .. int((15 + length $data) / 16) - 1) {
154 my $row = substr($data, $i * 16, 16);
155 (my $clean = $row) =~ tr/ -~/./c;
156 printf("%08x: %-32s %s\n", $offset, unpack("H*", $row), $clean);
160 printf "%08x: %s...\n", $offset, unpack("H*", substr($data, 0, 26));
164 printf "%08x: %s\n", $offset, unpack("H*", $data), "\n";
168 #unsigned long crc_table[256];
171 #/* Flag: has the table been computed? Initially false. */
172 # int crc_table_computed = 0;
174 # /* Make the table for a fast CRC. */
175 # void make_crc_table(void)
181 # for (n = 0; n < 256; n++) {
182 for my $n (0 .. 255) {
183 # c = (unsigned long) n;
185 # for (k = 0; k < 8; k++) {
188 # c = 0xedb88320L ^ (c >> 1);
192 $c = 0xedb88320 ^ ($c >> 1);
203 # crc_table_computed = 1;
207 # /* Update a running CRC with the bytes buf[0..len-1]--the CRC
208 # should be initialized to all 1's, and the transmitted value
209 # is the 1's complement of the final running CRC (see the
210 # crc() routine below). */
212 # unsigned long update_crc(unsigned long crc, unsigned char *buf,
216 my ($crc, $data) = @_;
217 # unsigned long c = crc;
220 # if (!crc_table_computed)
222 @crc_table or make_crc_table();
223 # for (n = 0; n < len; n++) {
224 # c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
226 for my $code (unpack("C*", $data)) {
227 $crc = $crc_table[($crc ^ $code) & 0xFF] ^ ($crc >> 8);
234 # /* Return the CRC of the bytes buf[0..len-1]. */
235 # unsigned long crc(unsigned char *buf, int len)
237 # return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
243 return update_crc(0xFFFFFFFF, $data) ^ 0xFFFFFFFF;