#!/usr/local/bin/perl
# Copyright(C) TAKASUGI Shinji (ts@sf.airnet.ne.jp)
# Based on a script created by MUROTANI Yoshitaka
# The counter will be postincremented.
binmode STDOUT;
$content_type_header = "Content-Type: image/gif\n\n";
if ($ENV{'REQUEST_METHOD'} eq 'HEAD')
{ print $content_type_header;
exit 0;
}
require 'gifinput.pl';
require 'gifoutput.pl';
sub abort
{ print "Content-Type: text/html\n\n",
"\n
\nCounter Error\n\n\n",
"\n", $_[0], "
\n\n\n";
exit 0;
}
foreach (split(/[\&\;]/, $ENV{'QUERY_STRING'}))
{ ($key, $value) = split('=', $_, 2);
$value =~ tr/+/ /;
$value =~ s/%(..)/pack('C', hex($1))/ge;
$param{$key} = $value;
}
$image = $param{'image'} || 'ac!d.gif';
$image =~ s/!/\%/g;
$format = $param{'format'} || '!05d';
$format =~ s/!/\%/g;
while (($digits = ($image =~ /\%(\d+)d/g)))
{ &abort("Too long string.") if ($digits > 20);
}
while (($digits = ($format =~ /\%(\d+)d/g)))
{ &abort("Too long string.") if ($digits > 20);
}
if ($param{'number'} ne '')
{ $visit = $param{'number'};
}
else
{ $counter = $param{'counter'} || 'ac.dat';
open(COUNTER, $counter) || &abort("Failed to open $counter.");
$visit = ;
if ($visit ne '' && $param{'up'} && open(COUNTER, ">$counter"))
{ flock(COUNTER, 2);
print COUNTER $visit + 1;
}
close(COUNTER);
}
$number = sprintf($format, $visit);
&abort("Too long string.") if (length($number) > 20);
@digits = split('', $number);
foreach $digit (@digits)
{ $digit_hash{$digit}++;
}
# GIF functions
sub read_gif
{ local($file, *GIFFILE) = @_;
open(GIFFILE, $file) || &abort("Failed to open $file.");
binmode GIFFILE;
local($gif_data) = &gifinput::gif_read(\*GIFFILE);
close(GIFFILE);
$gif_data;
}
sub set_palette
{ local($gif_data_array) = @_;
local($gif_data, $cx, $cy, $pixels, $palette, $transparent,
$height, $index, $rgb, $global_palette, $palette_index,
$palette_lookup, $global_transparent);
$palette_index = 0;
foreach $gif_data (@$gif_data_array)
{ ($cx, $cy, $pixels, $palette, $transparent) = @$gif_data;
$transparent = -1 if !defined($transparent);
undef($palette_lookup);
if (!defined($height))
{ $height = $cy;
}
elsif ($height != $cy)
{ die "gifxcat.pl: different height, stopped";
}
for ($index = 0; $index < @$palette; $index++)
{ $rgb = $palette->[$index];
if (!exists($global_palette->{$rgb}))
{ if ($palette_index == 256)
{ return;
}
if ($index == $transparent
&& !defined($global_transparent))
{ $global_transparent = $palette_index;
}
$global_palette->{$rgb} = $palette_index++;
}
$palette_lookup->{chr($index)} = chr($index == $transparent
? $global_transparent
: $global_palette->{$rgb});
}
push(@$gif_data, $palette_lookup);
}
($height, $global_palette, $global_transparent);
}
sub force_palette
{ local($gif_data_array) = @_;
local($gif_data, $cx, $cy, $pixels, $palette, $transparent,
$height, $index, $rgb, $global_palette, $palette_index,
$palette_lookup, $red, $green, $blue);
$palette_index = 0;
for ($red = 0; $red <= 5; $red++)
{ for ($green = 0; $green <= 5; $green++)
{ for ($blue = 0; $blue <= 5; $blue++)
{ $global_palette->{(($red * 0x33) << 16) + (($green * 0x33) << 8) + ($blue * 0x33)} =
$red * 36 + $green * 6 + $blue;
}
}
}
foreach $gif_data (@$gif_data_array)
{ ($cx, $cy, $pixels, $palette, $transparent) = @$gif_data;
$transparent = -1 if !defined($transparent);
undef($palette_lookup);
if (!defined($height))
{ $height = $cy;
}
elsif ($height != $y)
{ die "gifxcat.pl: different height, stopped";
}
for ($index = 0; $index < @$palette; $index++)
{ $rgb = $palette->[$index];
$rgb = ((int(((($rgb & 0xff0000) >> 16) + 25) / 51) * 51) << 16)
| ((int(((($rgb & 0xff00) >> 8) + 25) / 51) * 51) << 8)
| (int((($rgb & 0xff) + 25) / 51) * 51);
if ($transparent)
{ $global_transparent = $global_palette->{$rgb};
}
$palette_lookup->{chr($index)} = chr($global_palette->{$rgb});
}
push(@$gif_data, $palette_lookup);
}
($height, $global_palette, $global_transparent);
}
foreach $digit (keys(%digit_hash))
{ $gif_data_hash{$digit} = &read_gif(sprintf($image, $digit));
}
@gif_data_array = values(%gif_data_hash);
($height, $global_palette, $global_transparent) = &set_palette(\@gif_data_array);
if (!$height)
{ ($height, $global_palette, $global_transparent) = &force_palette(\@gif_data_array);
}
foreach $gif_data (@gif_data_array)
{ ($cx, $cy, $pixels, $palette, $transparent, $palette_lookup) = @$gif_data;
$pixels =~ s/(.)/$palette_lookup->{$1}/gs;
$gif_data->[0] = $cx;
$gif_data->[1] = $pixels;
$#$gif_data = 1;
}
$#pixel_array = $height * @digits - 1;
$total_width = 0;
for ($index = 0; $index < @digits; $index++)
{ ($cx, $pixels) = @{$gif_data_hash{$digits[$index]}};
$total_width += $cx;
for ($y = 0; $y < $height; $y++)
{ $pixel_array[$y * @digits + $index] = substr($pixels, $cx * $y, $cx);
}
}
while (($rgb, $index) = each(%$global_palette))
{ $merged_palette[$index] = $rgb;
}
print $content_type_header;
&gifoutput::gif_write(\*STDOUT, $total_width, $height,
join('', @pixel_array), \@merged_palette, $global_transparent, 1);
exit 0;