#!/usr/local/bin/perl
## PNG Tester for checking MNG/PNG/JNG files
## pngtester.cgi v0.8a May 3 2001 by techan
## Usage: http://(Path)/pngtester.cgi?Filename1[&Filename2][&Filename3]...
## The latest version is here:
## http://homepage2.nifty.com/sophia0/sub04.html
# Do you check CRC? (yes:1 no:0)
$crc_check = 1;
# Do you check pallet colors? (yes:1 no:0)
$pallet_check = 1;
# MainRoutine
%colortypes = ( 0=>"gray", 2=>"RGB", 3=>"palletted", 4=>"gray+alpha", 6=>"RGB+alpha");
# %filtertypes = ( 0=>"none", 1=>"sub", 2=>"up", 3=>"average", 4=>"paeth");
%windowsize = ( 0=>"0.25K", 1=>"0.5K", 2=>"1K", 3=>"2K", 4=>"4K", 5=>"8K", 6=>"16K", 7=>"32K", 8=>"unknown");
%argorithm = ( 0=>"fastest", 1=>"fast", 2=>"default", 3=>"slowest");
%rendering_intent = ( 0=>"perceptual", 1=>"relative colorimetric", 2=>"saturation", 3=>"absolute colorimetric");
%termination = ( 0=>"last frame", 1=>"cease", 2=>"first frame", 3=>"repeat");
%condition = ( 0=>"Deterministic, not cacheable",
1=>"Decoder discretion, not cacheable",
2=>"User discretion, not cacheable",
3=>"External signal, not cacheable",
4=>"Deterministic, cacheable",
5=>"Decoder discretion, cacheable",
6=>"User discretion, cacheable",
7=>"External signal, cacheable");
%change = ( 0=>"No", 1=>"Yes, for the upcoming subframe only",
2=>"Yes, also reset default");
%change_timeout = ( 0=>"No", 1=>"Deterministic, for the upcoming subframe only",
2=>"Deterministic, also reset default",
3=>"Decoder-discretion, for the upcoming subframe only",
4=>"Decoder-discretion, also reset default",
5=>"User-discretion, for the upcoming subframe only",
6=>"User-discretion, also reset default",
7=>"External-signal, for the upcoming subframe only",
8=>"External-signal, also reset default");
%magnification = ( 0=>"no magnification", 1=>"replication of color and alpha",
2=>"mgnified with interpolation of color and alpha",
3=>"magnified with replication of color and alpha",
4=>"magnified with interpolation of color and replication of alpha",
5=>"magnified with interpolation of alpha and replication of color");
%entrytypes = ( 0=>"Segment (nominal)", 1=>"Segment", 2=>"Subframe", 3=>"Exported image");
$buffer = $ENV{'QUERY_STRING'};
if ($buffer) {
@arg=split(/&/, $buffer);
if ($#arg+1) {
for ($i=0;$i<=$#arg;$i++) {
$arg[$i] =~ s/[^\w\-\~\/\.]//g;
}
}
}
$crc_test_ok = 0;
if ($crc_check) { &TestCrc; }
print "Content-type: text/html\n\n";
print "\n
\n";
print "PNG TESTER\n";
print "\n\n";
if ($arg[0] eq "") { print 'This script is operable.
'; }
else { foreach $file (@arg) { &Testing($file); } }
print "\n";
print "\n";
exit;
# SubRoutine
sub Testing
{
print "==> Testing file "$file"
\n";
$pngsize= -s $file;
unless (open(IN, "< $file")) {
print "Can\'t open file!
\n";
return;
}
binmode(IN);
read (IN, $sig, 8);
unless (&ValidateSignature) {
close(IN);
print "Bad PNG/MNG/JNG signature!
\n";
return;
}
read (IN, $png, $pngsize-8);
close(IN);
$color="";
$pos=0;
print "\n";
print "\n";
print "\t| $find | \n";
print "\tBytes | \n";
print "\tChunk Data | \n";
if ($crc_test_ok) { print "\tCRC | \n"; }
print "
\n";
1 while (&FindChunk);
print "
\n";
if ($crc_check && !$crc_test_ok) { print "note: Can\'t check CRC.
\n"; }
print "
\n";
}
sub ValidateSignature
{
if ($sig eq "\x89PNG\r\n\x1a\n") { $find = 'PNG'; return 1; }
elsif ($sig eq "\x8aMNG\r\n\x1a\n") { $find = 'MNG'; return 1; }
elsif ($sig eq "\x8bJNG\r\n\x1a\n") { $find = 'JNG'; return 1; }
else { return 0; }
}
sub FindChunk
{
if ($pos >= $pngsize-8) { return 0; }
$chunk=substr($png, $pos, 8);
if (length($chunk) !=8) { return 0; }
($length, $type)=unpack("N A4", $chunk);
$type_data=substr($chunk, 4, 4);
$pos +=8;
$chunk=substr($png,$pos,$length+4);
if (length($chunk) !=$length+4) {
if ($crc_test_ok) { $c_n="4"; }
else { $c_n="3"; }
print "\n\t| Premature end error! | \n
\n";
return 0;
}
$crc=substr($chunk,$length,4);
$chunk=substr($chunk,0,$length);
$data=$type_data.$chunk;
$pos +=$length+4;
print "\n";
print "\t| $type | \n";
print "\t$length | \n";
print "\t";
if (!$length) { print "\@"; }
else {
if ($type eq 'MHDR') { &MHDR; }
elsif ($type eq 'DEFI') { &DEFI; }
elsif ($type eq 'FRAM') { &FRAM; }
elsif ($type eq 'TERM') { &TERM; }
elsif ($type eq 'IHDR') { &IHDR; }
elsif ($type eq 'BASI') { &BASI; }
elsif ($type eq 'PLTE') { &PLTE; }
elsif ($type eq 'JHDR') { &JHDR; }
elsif ($type eq 'DHDR') { &DHDR; }
elsif ($type eq 'IDAT') { &IDAT; }
elsif ($type eq 'gAMA') { &gAMA; }
elsif ($type eq 'sBIT') { &sBIT; }
elsif ($type eq 'sRGB') { &sRGB; }
elsif ($type eq 'tEXt') { &tEXt; }
elsif ($type eq 'zTXt') { &zTXt; }
elsif ($type eq 'iTXt') { &iTXt; }
elsif ($type eq 'sPLT') { &sPLT; }
elsif ($type eq 'iCCP') { &iCCP; }
elsif ($type eq 'tIME') { &tIME; }
elsif ($type eq 'pHYs') { &pHYs; }
elsif ($type eq 'cHRM') { &cHRM; }
elsif ($type eq 'LOOP') { &LOOP; }
elsif ($type eq 'ENDL') { &ENDL; }
elsif ($type eq 'SHOW') { &SHOW; }
elsif ($type eq 'MOVE') { &MOVE; }
elsif ($type eq 'CLON') { &CLON; }
elsif ($type eq 'CLIP') { &CLIP; }
elsif ($type eq 'DISC') { &DISC; }
elsif ($type eq 'PAST') { &PAST; }
elsif ($type eq 'MAGN') { &MAGN; }
elsif ($type eq 'SAVE') { &SAVE; }
elsif ($type eq 'SEEK') { &SEEK; }
elsif ($type eq 'eXPI') { &eXPI; }
elsif ($type eq 'fPRI') { &fPRI; }
elsif ($type eq 'nEED') { &nEED; }
elsif ($type eq 'PROM') { &PROM; }
elsif ($type eq 'DROP') { &DROP; }
elsif ($type eq 'DBYK') { &DBYK; }
elsif ($type eq 'ORDR') { &ORDR; }
elsif ($type eq 'bKGD') { &bKGD; }
elsif ($type eq 'hIST') { &hIST; }
elsif ($type eq 'tRNS') { &tRNS; }
elsif ($type eq 'BACK') { &BACK; }
elsif ($type eq 'PPLT') { &PPLT; }
else { print "\@"; }
}
$previous = $type;
print " | \n";
if ($crc_test_ok) {
print "\t";
if ($crc eq &CalcCrc($data)) { print "OK"; }
else { print "NG"; }
print " | \n";
}
print "
\n";
return 1;
}
sub JHDR
{
my $mpos=0;
$Width = unpack("N",substr($chunk,$mpos,4)); $mpos +=4;
$Height = unpack("N",substr($chunk,$mpos,4)); $mpos +=4;
$Color_type = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Image_sample_depth = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Image_compression_method = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Image_interlace_method = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Alpha_sample_depth = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Alpha_compression_method = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Alpha_filter_method = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Alpha_interlace_method = unpack("C",substr($chunk,$mpos,1));
print "$Width x $Height";
if ($Color_type == 8) { print ", gray"; }
elsif ($Color_type == 10) { print ", color"; }
elsif ($Color_type == 12) { print ", gray-alpha"; }
elsif ($Color_type == 14) { print ", color-alpha"; }
else { print ", unknown color type"; }
if ($Image_sample_depth == 8) { print ", 8 bit"; }
elsif ($Image_sample_depth == 12) { print ", 12 bit"; }
elsif ($Image_sample_depth == 20) { print ", 8+12 bit"; }
else { print ", unknown depth"; }
if ($Image_compression_method == 8) { print ", JPEG"; }
else { print ", unknown compression method"; }
if ($Image_interlace_method == 0) { print ", sequential"; }
elsif ($Image_interlace_method == 8) { print ", progressive"; }
else { print ", unknown interlace"; }
if ($Alpha_compression_method == 0) { print ", $Alpha_sample_depth bit IDAT"; }
elsif ($Alpha_compression_method == 8) { print ", $Alpha_sample_depth bit JDAA"; }
else { print ", unknown alpha compression"; }
if ($Alpha_filter_method !=0) { print ", unknown alpha filter"; }
if ($Alpha_interlace_method !=0) { print ", unknown alpha interlace"; }
}
sub MHDR
{
my $mpos=0;
$Frame_width = unpack("N",substr($chunk,$mpos,4)); $mpos +=4;
$Frame_height = unpack("N",substr($chunk,$mpos,4)); $mpos +=4;
$Ticks_per_second = unpack("N",substr($chunk,$mpos,4)); $mpos +=4;
$Nominal_layer_count = unpack("N",substr($chunk,$mpos,4)); $mpos +=4;
$Nominal_frame_count = unpack("N",substr($chunk,$mpos,4)); $mpos +=4;
$Nominal_play_time = unpack("N",substr($chunk,$mpos,4)); $mpos +=4;
$Simplicity_profile = unpack("N",substr($chunk,$mpos,4));
print "$Frame_width x $Frame_height";
print ", $Ticks_per_second\/s";
print ", $Nominal_layer_count layers";
print ", $Nominal_frame_count frames";
print ", time=$Nominal_play_time";
$first = $Simplicity_profile & 0xff;
$second = ($Simplicity_profile & 0xff00) >> 8;
if ($first & 0x01) { print ", specified"; }
else { print "unspecified"; }
if ($first & 0x02) { print ", simple MNG"; }
if ($first & 0x04) { print ", complex MNG"; }
if ($first & 0x08) { print ", transparency"; }
if ($first & 0x10) { print ", JNG/JDAA"; }
if ($first & 0x20) { print ", Delta-PNG"; }
if ($first & 0x40) {
if ($first & 0x80) { print ", background trasparency"; }
if ($second & 0x01) { print ", semitransparency"; }
if ($second & 0x02) { print ", stored object buffers"; }
}
}
sub IHDR
{
my $mpos=0;
$width = unpack("N", substr($chunk, $mpos, 4)); $mpos+=4;
$height = unpack("N", substr($chunk, $mpos, 4)); $mpos+=4;
$depth = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$color = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$compress = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$filter = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$interlace = unpack("C", substr($chunk, $mpos, 1));
print "$width x $height, $depth-bit depth, $colortypes{$color}";
if ($compress !=0) { print ", unkonwn compression method!"; }
if ($filter == 0) { print ", basic filter"; }
elsif ($filter == 64) { print ", intrapixel differencing filter"; }
else { print ", unknown filter type!"; }
if ($interlace == 0) { print ", not interlaced"; }
elsif ($interlace == 1) { print ", Adam7-interlaced"; }
else { print ", unknown interlace type!"; }
}
sub BASI
{
&IHDR;
my $mpos=13;
if ($length <= $mpos) { return; }
$R_sample = '#'.unpack("H4",substr($chunk,$mpos,2)); $mpos+=2;
if ($color == 0 || $color == 4) { print ", Gray sample: $R_sample"; }
else { print ", Red sample: $R_sample"; }
if ($length <= $mpos) { return; }
if ($color == 0 || $color == 4) { $mpos+=4; }
else {
$G_sample = '#'.unpack("H4",substr($chunk,$mpos,2)); $mpos+=2;
print ", Green sample: $G_sample";
if ($length <= $mpos) { return; }
$B_sample = '#'.unpack("H4",substr($chunk,$mpos,2)); $mpos+=2;
print ", Blue sample: $B_sample";
}
if ($length <= $mpos) { return; }
$A_sample = '#'.unpack("H4",substr($chunk,$mpos,2)); $mpos+=2;
print ", Alpha sample: $A_sample";
if ($length <= $mpos) { return; }
$Viewable = unpack("C", substr($chunk, $mpos, 1));
if ($Viewable == 0) { print ", not viewable"; }
else { print ", viewable"; }
}
sub CLON
{
my $mpos=0;
$Source_id = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
$Clone_id = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
print "Source_id=$Source_id, Clone_id=$Clone_id";
if ($length <= $mpos) { return; }
$Clone_type = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
if ($Clone_type == 0) { print ", Full clone"; }
elsif ($Clone_type == 1) { print ", Partial clone"; }
elsif ($Clone_type == 2) { print ", Renumber object"; }
if ($length <= $mpos) { return; }
$Do_not_show = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
if ($Do_not_show == 0) { print ", visible"; }
elsif ($Do_not_show == 1) { print ", not visible"; }
if ($length <= $mpos) { return; }
$Concrete_flag = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
if ($Concrete_flag == 0) { print ", same concrete flag as that of the parent object"; }
elsif ($Concrete_flag == 1) { print ", abstract"; }
if ($length <= $mpos) { return; }
$Loca_delta_type = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$X_location = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
$Y_location = &CalcNegative(unpack("N", substr($chunk, $mpos, 4)));
if ($Loca_delta_type == 0) { print ", direct location"; }
elsif ($Loca_delta_type == 1) { print ", relative to the position of the parent object"; }
print ", X=$X_location, Y=$Y_location";
}
sub CLIP
{
my $mpos=0;
$First_object = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
$Last_object = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
$Clip_delta_type = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$Left_cb = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
$Right_cb = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
$Top_cb = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
$Bottom_cb = &CalcNegative(unpack("N", substr($chunk, $mpos, 4)));
print "First_object=$First_object, Last_object=$Last_object";
if ($Clip_delta_type == 0) { print ", direct"; }
elsif ($Clip_delta_type == 1) { print ", not direct"; }
print ", Left_cb=$Left_cb, Right_cb=$Right_cb, Top_cb=$Top_cb, Bottom_cb=$Bottom_cb";
}
sub DISC
{
my @Discard_id=();
$D_length = int($length / 2);
@Discard_id = unpack("n$D_length", $chunk);
print "Discard_id: ", join(",",@Discard_id);
}
sub PAST
{
my $mpos=0;
my $i;
my $id_count;
$Destination_id = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
print "Destination_id=$Destination_id";
if ($length <= $mpos) { return; }
$Target_delta_type = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$Target_x = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
$Target_y = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
if ($Target_delta_type == 0) { print ", direct"; }
elsif ($Target_delta_type == 1) { print ", from previous PAST with the same id"; }
elsif ($Target_delta_type == 2) { print ", from previous PAST regardless of its id"; }
print ", Target_x=$Target_x, Target_y=$Target_y";
if ($length <= $mpos) { return; }
if (($length - $mpos) % 30 !=0) { print ", Abnormal data sequence!"; return; }
$id_count = ($length - $mpos) / 30;
for ($i=0;$i<$id_count;$i++) {
$Source_id = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
$Composition_mode = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$Orientation = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$Offset_origin = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$X_offset = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
$Y_offset = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
$Boundary_origin = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
$Left_past_cb = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
$Right_past_cb = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
$Top_past_cb = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
$Bottom_past_cb = &CalcNegative(unpack("N", substr($chunk, $mpos, 4))); $mpos+=4;
print ", Source_id=$Source_id";
if ($Composition_mode == 0) { print ", composite over"; }
elsif ($Composition_mode == 1) { print ", replace"; }
elsif ($Composition_mode == 2) { print ", composite under"; }
if ($Orientation == 0) { print ", same as source image"; }
elsif ($Orientation == 2) { print ", flipped left-right and up-down"; }
elsif ($Orientation == 4) { print ", flipped left-right"; }
elsif ($Orientation == 6) { print ", flipped up-down"; }
elsif ($Orientation == 8) { print ", tiled with source image"; }
if ($Offset_origin == 0) { print ", Offsets measured from (0,0)"; }
elsif ($Offset_origin == 1) { print ", Offsets measured from (target_x,target_y)"; }
print "X_offset=$X_offset, Y_offset=$Y_offset";
if ($Boundary_origin == 0) { print ", Boundaries measured from (0,0)"; }
elsif ($Boundary_origin == 1) { print ", Boundaries measured from (target_x,target_y)"; }
print ", Left_past_cb=$Left_past_cb, Right_past_cb=$Right_past_cb";
print ", Top_past_cb=$Top_past_cb, Bottom_past_cb=$Bottom_past_cb";
}
}
sub MAGN
{
my $mpos=0;
$First_magnified_object_id = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
print "First_magnified_object_id=$First_magnified_object_id";
if ($length <= $mpos) { return; }
$Last_magnified_object_id = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
print "Last_magnified_object_id=$Last_magnified_object_id";
if ($length <= $mpos) { return; }
$X_method = unpack("C", substr($chunk, $mpos, 1)); $mpos++;
print ", X_method: $magnification{$X_method}";
if ($length <= $mpos) { return; }
$MX = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
print ", MX=$MX";
if ($length <= $mpos) { return; }
$MY = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
print ", MY=$MY";
if ($length <= $mpos) { return; }
$ML = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
print ", ML=$ML";
if ($length <= $mpos) { return; }
$MR = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
print ", MR=$MR";
if ($length <= $mpos) { return; }
$MT = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
print ", MT=$MT";
if ($length <= $mpos) { return; }
$MB = unpack("n", substr($chunk, $mpos, 2)); $mpos+=2;
print ", MB=$MB";
if ($length <= $mpos) { return; }
$Y_method = unpack("C", substr($chunk, $mpos, 1));
print ", Y_method: $magnification{$Y_method}";
}
sub DHDR
{
my $mpos=0;
$Object_id = unpack("n", substr($chunk,$mpos,2)); $mpos+=2;
$Image_type = unpack("C", substr($chunk,$mpos,1)); $mpos++;
$Delta_type = unpack("C", substr($chunk,$mpos,1)); $mpos++;
print "object_id=$Object_id";
if ($Image_type == 0) { print ", unspecified image type"; }
elsif ($Image_type == 1) { print ", PNG type"; }
elsif ($Image_type == 2) { print ", JNG type"; }
print ", delta_type=$Delta_type";
if ($length <= $mpos) { return; }
$Block_width = unpack("N", substr($chunk,$mpos,4)); $mpos+=4;
$Block_height = unpack("N", substr($chunk,$mpos,4)); $mpos+=4;
print ", block size= $Block_width x $Block_height";
if ($length <= $mpos) { return; }
$Block_X_location = unpack("N", substr($chunk,$mpos,4)); $mpos+=4;
$Block_Y_location = unpack("N", substr($chunk,$mpos,4)); $mpos+=4;
print ", block location: X=$Block_X_location, Y=$Block_Y_location";
}
sub PLTE
{
my $i;
my @RGB=();
if ($length % 3 !=0) { print "Incorrect pallet entry!"; return; }
$p_entry = $length / 3;
print "$p_entry pallet entries";
if (!$pallet_check) { return; }
for ($i=0;$i<$p_entry;$i++) {
$RGB[$i] = '#'.unpack("H6",substr($chunk,$i*3,3));
}
print ":
", join(", ", @RGB);
}
sub hIST
{
my $i;
my @frequency=();
if ($length % 2 !=0) { print "Incorrect histogram!"; return; }
$h_entry = $length / 2;
print "$h_entry histogram entries";
if (!$pallet_check) { return; }
for ($i=0;$i<$h_entry;$i++) {
$frequency[$i] = '#'.unpack("H4",substr($chunk,$i*2,2));
}
print ":
", join(", ", @frequency);
}
sub bKGD
{
if ($length == 1) {
my $p_index = unpack("C",$chunk);
print "Background pallet index=$p_index";
} elsif ($length == 2) {
my $gray = '#'.unpack("H4",$chunk);
print "Background gray=$gray";
} elsif ($length == 6) {
my $R = '#'.unpack("H4", substr($chunk,0,2));
my $G = '#'.unpack("H4", substr($chunk,2,2));
my $B = '#'.unpack("H4", substr($chunk,4,2));
print "Background color: Red=$R, Green=$G, Blue=$B";
}
}
sub BACK
{
my $mpos=0;
my $R = '#'.unpack("H4",substr($chunk,$mpos,2)); $mpos+=2;
my $G = '#'.unpack("H4",substr($chunk,$mpos,2)); $mpos+=2;
my $B = '#'.unpack("H4",substr($chunk,$mpos,2)); $mpos+=2;
print "Background color: Red=$R, Green=$G, Blue=$B";
if ($length <= $mpos) { return; }
my $M = unpack("C",substr($chunk,$mpos,1)); $mpos++;
if ($M == 0) { print ", advisory color and image"; }
elsif ($M == 1) { print ", mandatory color and advisory image"; }
elsif ($M == 2) { print ", mandatory image and advisory color"; }
elsif ($M == 3) { print ", mandatory color and image"; }
if ($length <= $mpos) { return; }
my $id = unpack("n",substr($chunk,$mpos,2)); $mpos+=2;
print ", Background_image_id=$id";
if ($length <= $mpos) { return; }
my $tile = unpack("C",substr($chunk,$mpos,1));
if ($tile == 0) { print ", not tile"; }
elsif ($tile == 1) { print ", tile"; }
}
sub tRNS
{
if ($color eq "" || $color == 3) {
my @value=();
for ($i=0;$i<$length;$i++) {
$value[$i] = '#'.unpack("H2",substr($chunk,$i,1));
}
print "Alpha: ", join(", ",@value);
} elsif ($color == 0) {
my $gray = '#'.unpack("H4",$chunk);
print "Transparent gray=$gray";
} elsif ($color == 2) {
my $R = '#'.unpack("H4",substr($chunk,0,2));
my $G = '#'.unpack("H4",substr($chunk,2,2));
my $B = '#'.unpack("H4",substr($chunk,4,2));
print "Transparent color: Red=$R, Green=$G, Blue=$B";
} else {
print "unknown!";
}
}
sub IDAT
{
if ($previous eq 'IDAT') { print "\@"; return; }
$cmf_flg = substr($chunk,0,2);
($cmf,$flg) = unpack("CC", $cmf_flg);
if ((($cmf * 256 + $flg) % 31) != 0) { print "incorrect FCHECK"; }
else {
$cm = $cmf & 0x0f;
if ($cm!=8) { print "unknown compression method!"; }
else {
$cinfo = ($cmf & 0xf0) >> 4;
print "$windowsize{$cinfo} window size";
$flg = ($flg & 0xe0) >> 5;
$fdict = $flg & 0x01;
$flevel = ($flg & 0x06) >> 1;
print ", $argorithm{$flevel} argorithm";
if ($fdict) { print ", preset dictionary"; }
}
}
}
sub LOOP
{
my $mpos = 0;
my @Signal_number=();
$Nest_level = unpack("C", substr($chunk,$mpos,1)); $mpos++;
$Iteration_count = unpack("N", substr($chunk,$mpos,4)); $mpos +=4;
print "Nest_level=$Nest_level, Iteration_count=$Iteration_count";
if ($length <= $mpos) { return; }
$Termination_condition = unpack("C", substr($chunk,$mpos,1)); $mpos++;
print ", $condition{$Termination_condition}";
if ($length <= $mpos) { return; }
$Iteration_min = unpack("N", substr($chunk,$mpos,4)); $mpos +=4;
print ", Iteration_min=$Iteration_min";
if ($length <= $mpos) { return; }
$Iteration_max = unpack("N", substr($chunk,$mpos,4)); $mpos +=4;
print ", Iteration_max=$Iteration_max";
if ($length <= $mpos) { return; }
@Signal_number = unpack("N*", substr($chunk,$mpos));
print ", Signal_number: ", join(",",@Signal_number);
}
sub ENDL
{
$Nest_level = unpack("C", substr($chunk,0,1));
print "Nest_level=$Nest_level";
}
sub SHOW
{
my $mpos=0;
$First_image = unpack("n", substr($chunk,$mpos,2)); $mpos+=2;
print "First_image=$First_image";
if ($length < 4) { return; }
$Last_image = unpack("n", substr($chunk,$mpos,2)); $mpos+=2;
print ", Last_image=$Last_image";
if ($length < 5) { return; }
$Show_mode = unpack("C", substr($chunk,$mpos,1));
print ", Show_mode=$Show_mode";
}
sub MOVE
{
my $mpos=0;
$First_object = unpack("n", substr($chunk,$mpos,2)); $mpos+=2;
print "First_object=$First_object";
if ($length < 4) { return; }
$Last_object = unpack("n", substr($chunk,$mpos,2)); $mpos+=2;
print ", Last_object=$Last_object";
if ($length < 5) { return; }
$Location_delta_type = unpack("C", substr($chunk,$mpos,1)); $mpos++;
if ($Location_delta_type == 0) { print ", direct"; }
elsif ($Location_delta_type == 1) { print ", relative to the parent object"; }
if ($length < 13) { return; }
$X_location = &CalcNegative(unpack("N", substr($chunk,$mpos,4))); $mpos+=4;
$Y_location = &CalcNegative(unpack("N", substr($chunk,$mpos,4)));
print ", X=$X_location Y=$Y_location";
}
sub gAMA
{
$gamma= unpack ("N", $chunk) / 100000.0;
printf "%2.4f (1/%2.4f)", $gamma, 1/$gamma;
}
sub sBIT
{
my @values=();
@values = unpack("C$length", $chunk);
print "Significant_bits: ", join(", ",@values);
}
sub sRGB
{
my $render = unpack("C", $chunk);
print "$rendering_intent{$render}";
}
sub tEXt
{
$chunk =~ s/\0/: /;
$chunk =~ s/&/&/g;
$chunk =~ s/\"/"/g;
$chunk =~ s/>/>/g;
$chunk =~ s/</g;
print "$chunk";
}
sub zTXt0
{
my $Key;
$search0 = index($chunk,"\0");
if (++$search0) {
$Key = substr($chunk, 0, $search0);
$Key =~ s/\0//;
$Key =~ s/&/&/g;
$Key =~ s/\"/"/g;
$Key =~ s/>/>/g;
$Key =~ s/</g;
print "$Key";
}
}
sub zTXt
{
&zTXt0;
my $mpos=$search0;
my $compress = unpack("C",substr($chunk,$mpos,1));
if ($compress !=0) { print ", unknown compression method"; }
}
sub iTXt
{
&zTXt0;
my $mpos=$search0;
my $flag = unpack("C",substr($chunk,$mpos,1)); $mpos++;
if (!$flag) { print ", not-compressed text"; }
else { print ", compressed text"; }
my $compress = unpack("C",substr($chunk,$mpos,1)); $mpos++;
if ($compress !=0) { print ", unknown compression method"; }
my $search0 = index($chunk,"\0",$mpos);
if ($search0 < 0) { return; }
elsif ($search0 == $mpos) { $mpos++; }
else {
$Tag = substr($chunk,$mpos,$search1-$mpos); $mpos=$search0+1;
print ", Language tag: $Tag";
}
}
sub sPLT
{
my $mpos=0;
&zTXt0;
$mpos = $search0;
$Sample_depth = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print ", Sample_depth=$Sample_depth
";
if (!$pallet_check) { return; }
if ($Sample_depth == 8) {
if (($length - $mpos) % 6 !=0) {
print ", Abnormal pallet entries";
return;
} else {
while ($length > $mpos) {
$rgb = '#'.unpack("H6", substr($chunk,$mpos,3)); $mpos+=3;
$alpha = '-#'.unpack("H2", substr($chunk,$mpos,1)); $mpos++;
$frequency = '-#'.unpack("H4", substr($chunk,$mpos,2)); $mpos+=2;
print ", $rgb$alpha$frequency";
}
}
} elsif ($Sample_depth == 16) {
if (($length - $mpos) % 10 !=0) {
print ", Abnormal pallet entries";
return;
} else {
while ($length > $mpos) {
$rgb = '#'.unpack("H12", substr($chunk,$mpos,6)); $mpos+=12;
$alpha = '-#'.unpack("H4", substr($chunk,$mpos,2)); $mpos+=2;
$frequency = '-#'.unpack("H4", substr($chunk,$mpos,2)); $mpos+=2;
print ", $rgb$alpha$frequency";
}
}
}
}
sub iCCP
{
&zTXt0;
}
sub tIME
{
($Year,$Month,$Day,$Hour,$Minute,$Second)=unpack("nC5", $chunk);
print "Updated $Year $Month $Day $Hour:$Minute:$Second";
}
sub pHYs
{
($X_pixels_per_unit, $Y_pixels_per_unit, $Unit_specifier)=unpack("NNC", $chunk);
print "X: $X_pixels_per_unit pixels per unit";
print ", Y: $Y_pixels_per_unit pixels per unit, unit: ";
if ($Unit_specifier == 1) { print "meter"; }
else { print "unknown"; }
}
sub cHRM
{
my $mpos=0;
$White_Point_x = unpack("N",substr($chunk,$mpos,4)) / 100000.0; $mpos+=4;
$White_Point_y = unpack("N",substr($chunk,$mpos,4)) / 100000.0; $mpos+=4;
$Red_x = unpack("N",substr($chunk,$mpos,4)) / 100000.0; $mpos+=4;
$Red_y = unpack("N",substr($chunk,$mpos,4)) / 100000.0; $mpos+=4;
$Green_x = unpack("N",substr($chunk,$mpos,4)) / 100000.0; $mpos+=4;
$Green_y = unpack("N",substr($chunk,$mpos,4)) / 100000.0; $mpos+=4;
$Blue_x = unpack("N",substr($chunk,$mpos,4)) / 100000.0; $mpos+=4;
$Blue_y = unpack("N",substr($chunk,$mpos,4)) / 100000.0;
printf "White (x= %2.4f, y= %2.4f) ",$White_Point_x,$White_Point_y;
printf "Red (x= %2.4f, y= %2.4f) ",$Red_x,$Red_y;
printf "Green (x= %2.4f, y= %2.4f) ",$Green_x,$Green_y;
printf "Blue (x= %2.4f, y= %2.4f)",$Blue_x,$Blue_y;
}
sub DEFI
{
my $mpos=0;
$Object_id = unpack("n",substr($chunk,$mpos,2)); $mpos+=2;
print "object_id=$Object_id";
if ($length <= 2) { return; }
$Do_not_show = unpack("C",substr($chunk,$mpos,1)); $mpos++;
if ($Do_not_show) { print ", not visible"; }
else { print ", visible"; }
if ($length <= 3) { return; }
$Concrete_flag = unpack("C",substr($chunk,$mpos,1)); $mpos++;
if ($Concrete_flag) { print ", concrete"; }
else { print ", abstract"; }
if ($length <= 4) { return; }
$X_location = &CalcNegative(unpack("N",substr($chunk,$mpos,4))); $mpos+=4;
$Y_location = &CalcNegative(unpack("N",substr($chunk,$mpos,4))); $mpos+=4;
print ", X=$X_location Y=$Y_location";
if ($length <= 12) { return; }
$Left_cb = &CalcNegative(unpack("N",substr($chunk,$mpos,4))); $mpos+=4;
$Right_cb = &CalcNegative(unpack("N",substr($chunk,$mpos,4))); $mpos+=4;
$Top_cb = &CalcNegative(unpack("N",substr($chunk,$mpos,4))); $mpos+=4;
$Bottom_cb = &CalcNegative(unpack("N",substr($chunk,$mpos,4)));
print ", left_cb=$Left_cb, right_cb=$Right_cb, top_cb=$Top_cb, bottom_cb=$Bottom_cb";
}
sub FRAM
{
my $mpos=0;
$Framing_mode = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print "framing_mode=$Framing_mode";
if ($length <= $mpos) { return; }
$ipos = index($chunk,"\0",$mpos);
if ($ipos != $mpos) {
$Subframe_name = substr($chunk, $mpos, $ipos-$mpos);
print ", "$Subframe_name"";
}
$mpos = $ipos + 1;
if ($length <= $mpos) { return; }
$Change_interframe_delay = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print ", Change_interframe_delay: $change{$Change_interframe_delay}";
if ($length <= $mpos) { return; }
$Change_timeout_and_termination = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print ", Change_timeout: $change_timeout{$Change_timeout_and_termination}";
if ($length <= $mpos) { return; }
$Change_layer_clipping_boundaries = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print ", Change_layer_clipping_boundaries: $change{$Change_layer_clipping_boundaries}";
if ($length <= $mpos) { return; }
$Change_sync_id_list = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print ", Change_sync_id_list: $change{$Change_sync_id_list}";
if ($length <= $mpos) { return; }
$Interframe_delay = unpack("N",substr($chunk,$mpos,4)); $mpos+=4;
print ", Interframe_delay=$Interframe_delay";
if ($length <= $mpos) { return; }
$Timeout = unpack("N",substr($chunk,$mpos,4)); $mpos+=4;
print ", Timeout=$Timeout";
if ($length <= $mpos) { return; }
$Layer_clipping_boundary_delta_type = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print ", Layer_clipping_boundary_delta_type: ";
if ($Layer_clipping_boundary_delta_type == 0) { print "direct"; }
else { print "relative to the previous subframe"; }
if ($length <= $mpos) { return; }
$Left_layer_cb = &CalcNegative(unpack("N",substr($chunk,$mpos,4))); $mpos+=4;
print ", Left_layer_cb=$Left_layer_cb";
if ($length <= $mpos) { return; }
$Right_layer_cb = &CalcNegative(unpack("N",substr($chunk,$mpos,4))); $mpos+=4;
print ", Right_layer_cb=$Right_layer_cb";
if ($length <= $mpos) { return; }
$Top_layer_cb = &CalcNegative(unpack("N",substr($chunk,$mpos,4))); $mpos+=4;
print ", Top_layer_cb=$Top_layer_cb";
if ($length <= $mpos) { return; }
$Bottom_layer_cb = &CalcNegative(unpack("N",substr($chunk,$mpos,4))); $mpos+=4;
print ", Bottom_layer_cb=$Bottom_layer_cb";
if ($length <= $mpos) { return; }
$Sync_id = unpack("N",substr($chunk,$mpos,4));
print ", Sync_id=$Sync_id";
}
sub TERM
{
my $mpos=0;
$Termination_action = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print "Termination_action: $termination{$Termination_action}";
if ($length <= $mpos) { return; }
$Action_after_iterations = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Delay = unpack("N",substr($chunk,$mpos,4)); $mpos+=4;
$Iteration_max = unpack("N",substr($chunk,$mpos,4));
print ", Action_after_iterations: $termination{$Action_after_iterations}";
print ", Delay=$Delay, Iteration_max=$Iteration_max";
}
sub SAVE
{
my $mpos=0;
$Offset_size = unpack("C",substr($chunk,$mpos,1)); $mpos++;
if ($Offset_size == 4) { print "Offsets expressed as 32-bit integers"; }
elsif ($Offset_size == 8) { print "Offsets expressed as 64-bit integers"; }
else { print "unknown offsets"; return; }
while ($length > $mpos) {
$Entry_type = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print ", Entry_type: $entrytypes{$Entry_type}";
if ($Entry_type <= 1) {
if ($Offset_size==4) {
$Offset = unpack("H8", substr($chunk,$mpos,4)); $mpos+=4;
} else {
$Offset = unpack("H16", substr($chunk,$mpos,8)); $mpos+=8;
}
print ", Offset=#$Offset";
}
if ($Entry_type == 0) {
if ($Offset_size == 4) {
$Nominal_start_time = unpack("H8", substr($chunk,$mpos,4)); $mpos+=4;
} else {
$Nominal_start_time = unpack("H16", substr($chunk,$mpos,8)); $mpos+=8;
}
print ", Nominal_start_time=#$Nominal_start_time";
$Nominal_layer_number = unpack("N",substr($chunk,$mpos,4)); $mpos+=4;
print ", Nominal_layer_number=$Nominal_layer_number";
$Nominal_frame_number = unpack("N",substr($chunk,$mpos,4)); $mpos+=4;
print ", Nominal_frame_number=$Nominal_frame_number";
}
if ($length <= $mpos) { last; }
$sep_pos = index($chunk,"\0",$mpos);
if ($sep_pos < 0) {
$Name = substr($chunk,$mpos);
print ", "$Name"";
$mpos = $length-1;
} elsif ($sep_pos != $mpos) {
$Name = substr($chunk,$mpos,$sep_pos-$mpos);
print ", "$Name"";
$mpos=$sep_pos;
}
$mpos++;
}
}
sub SEEK
{
if ($length > 79) { print "Segment_name is abnormal!"; }
else { print "Segment_name: $chunk"; }
}
sub eXPI
{
my $mpos=0;
$Snapshot_id = unpack("n",substr($chunk,$mpos,2)); $mpos+=2;
print "Snapshot_id=$Snapshot_id";
if ($length <= $mpos) { return; }
$Snapshot_name = substr($chunk,$mpos);
print ", Snapshot_name: $Snapshot_name";
}
sub fPRI
{
my $mpos=0;
$fPRI_delta_type = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Priority = unpack("C",substr($chunk,$mpos,1));
if ($fPRI_delta_type == 0) { print "direct"; }
elsif ($fPRI_delta_type == 1) { print "not direct"; }
print ", Priority=$Priority";
}
sub nEED
{
my @needs=();
@needs = split(/\0/, $chunk);
print "Keywords: ", join(",",@needs);
}
sub PROM
{
my $mpos=0;
$New_color_type = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$New_sample_depth = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Fill_method = unpack("C",substr($chunk,$mpos,1));
print "New_color_type=$New_color_type, New_sample_depth=$New_sample_depth";
if ($Fill_method == 0) { print ", left-bit-replication"; }
elsif ($Fill_method == 1) { print ", zero fill"; }
}
sub DROP
{
print "Chunk_name: $chunk";
}
sub DBYK
{
my $mpos=0;
while ($length > $mpos) {
$Chunk_name = substr($chunk,$mpos,4); $mpos+=4;
print "Chunk_name: $Chunk_name";
$Priority = unpack("C", substr($chunk,$mpos,1)); $mpos++;
if ($Priority == 0) { print ", only"; }
elsif ($Priority == 1) { print ", all-but"; }
$null_point = index($chunk,"\0",$mpos);
if ($null_point+1) {
$Keywords = substr($chunk,$mpos,$null_point-$mpos);
print "Keywords: $Keyword";
$mpos=$null_point+1;
} else {
$Keywords = substr($chunk,$mpos);
print "Keywords: $Keyword";
$mpos=$length;
}
}
}
sub ORDR
{
my $mpos=0;
while ($length > $mpos) {
$Chunk_name = substr($chunk,$mpos,4); $mpos+=4;
print "Chunk_name: $Chunk_name";
$Order_type = unpack("C", substr($chunk,$mpos,1)); $mpos++;
if ($Order_type == 0) { print ", anywhere"; }
elsif ($Order_type == 1) { print ", after IDAT/JDAT/JDAA"; }
elsif ($Order_type == 2) { print ", before IDAT/JDAT/JDAA"; }
elsif ($Order_type == 3) { print ", before IDAT but not before PLTE"; }
elsif ($Order_type == 4) { print ", before IDAT but not after PLTE"; }
}
}
sub PPLT
{
my $mpos=0;
my $group=1;
$PPLT_delta_type = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print "PPLT_delta_type: ";
if ($PPLT_delta_type == 0) { print "replacement RBG"; }
elsif ($PPLT_delta_type == 1) { print "delta RBG"; }
elsif ($PPLT_delta_type == 2) { print "replacement alpha"; }
elsif ($PPLT_delta_type == 3) { print "delta alpha"; }
elsif ($PPLT_delta_type == 4) { print "replacement RBG+alpha"; }
elsif ($PPLT_delta_type == 5) { print "delta RBG+alpha"; }
while ($length > $mpos) {
print "
Group=$group: ";
$First_index = unpack("C",substr($chunk,$mpos,1)); $mpos++;
$Last_index = unpack("C",substr($chunk,$mpos,1)); $mpos++;
print "First_index=$First_index to Last_index=$Last_index";
if ($PPLT_delta_type <= 1) {
if ($pallet_check==0) { $mpos+=3; }
else {
for ($i=$First_index;$i<=$Last_index;$i++) {
$rgb = '#'.unpack("H6",substr($chunk,$mpos,3)); $mpos+=3;
print ", $rgb";
}
}
} elsif ($PPLT_delta_type >= 4) {
if ($pallet_check==0) { $mpos+=4; }
else {
for ($i=$First_index;$i<=$Last_index;$i++) {
$rgb = '#'.unpack("H6",substr($chunk,$mpos,3)); $mpos+=3;
$alpha = '-#'.unpack("H2",substr($chunk,$mpos,1)); $mpos++;
print ", $rgba$alpha";
}
}
}
else {
if ($pallet_check==0) { $mpos++; }
else {
for ($i=$First_index;$i<=$Last_index;$i++) {
$alpha = '#'.unpack("H2",substr($chunk,$mpos,1)); $mpos++;
print ", $alpha";
}
}
}
$group++;
}
}
sub CalcNegative
{
my $n =$_[0];
if ($n > 0x7fffffff) { $n = -(~$n + 1); }
return($n);
}
sub CalcCrc
{
my $data = $_[0];
my $c = 0xffffffff;
foreach (unpack("C*", $data)) {
$c = $crc_table[($c ^ $_) & 0xff] ^ (($c >> 8) & 0xffffff);
}
return(pack("N", ~$c));
}
sub TestCrc
{
my $test_data = "IEND";
my $test_crc= "\xaeB`\x82";
&CrcTableInit;
$crc_test_ok = ($test_crc eq &CalcCrc($test_data)) ? 1: 0;
}
sub CrcTableInit
{
my $d;
@crc_table = ();
for (0 .. 255) {
$d = $_;
for (0 .. 7) {
if ($d & 1) { $d = 0xedb88320 ^ (($d >> 1) & 0x7fffffff); }
else { $d = ($d >> 1) & 0x7fffffff; }
}
$crc_table[$_] = $d;
}
}
__END__