#!perl # $Id: counter.pl,v 1.3 2004/09/30 07:34:13 jlinoff Exp $ # ================================================ # Copyright Notice # Copyright (C) 1998-2003 by Joe Linoff (http://www.joelinoff.com) # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL JOE LINOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # # Comments and suggestions are always welcome. # ================================================ # # Acknowledgements are reported in interactive help. # # ================================================ # Generate counter output for displaying accesses to my web pages. It # can be used as a cgi script because it will output the GIF # information to standard out by default. # # The 8x8 font was derived from text2gif written by the authors of # libungif. The 16x24 font was hand generated by me. # # The algorithm used here generates uncompressed GIF. In fact it # generates expanded GIF so there is no violation of the LZW patent. # # If you run the program in debug mode it will create a counter.gif # file that can be used to analyze the font. Here is how you would run # it from the command line: # # % perl counter.pl -debug -noct -font=8x8 -img_file=x1.gif # % ls -l x1.gif # % perl counter.pl -debug -noct -font=16x24 -img_file=x2.gif # % ls -l x2.gif # # By default, this script reads a file called counter.dat in the local # directory. This is a simple text file that stores the state of the # counter. # # Use the -help switch to get up to date information about running the # script. # ================================================ use strict; &Main; # ================================================ # Main # ================================================ sub Main { # Get the arguments. my $align; my $bg_red; my $bg_green; my $bg_blue; my $commas_flag; my $counter_file; my $debug_flag; my $fg_red; my $fg_green; my $fg_blue; my $font; my $format; my $id; my $img_file; my $ct_flag; my $num_digits; my $pad; my $text; ( $align, $bg_red, $bg_green, $bg_blue, $commas_flag, $counter_file, $debug_flag, $fg_red, $fg_green, $fg_blue, $font, $format, $id, $img_file, $ct_flag, $num_digits, $pad, $text ) = &ParseArgs(\@ARGV); # ================================================ # Now open the file to see what is already # in there unless the -text switch as specified. # ================================================ my $current_count = 0; if( $text eq "" ) { $current_count = &UpdateCounterFile($counter_file,$id); } else { $current_count = $text; } # ================================================ # Format the string. # ================================================ my $counter_string = &FormatString($align, $commas_flag, $current_count, $num_digits, $pad); # ================================================ # Constants. # ================================================ my $digit_width = 8; my $digit_height = 8; if( $font eq "16x24" ) { $digit_width = 16; $digit_height = 24; } # ================================================ # Derive the image info. # ================================================ my $len = length $counter_string; my $width = $len * $digit_width; my $height = $digit_height; # ================================================ # Debug output. # ================================================ if( $debug_flag ) { print "digit_width = $digit_width\n"; print "digit_height = $digit_height\n"; print "FG red = $fg_red\n"; print "FG green = $fg_green\n"; print "FG blue = $fg_blue\n"; print "BG red = $bg_red\n"; print "BG green = $bg_green\n"; print "BG blue = $bg_blue\n"; print "commas = $commas_flag\n"; print "num_digits = $num_digits\n"; print "align = $align\n"; print "counter_file = $counter_file\n"; print "id = $id\n"; print "img_file = $img_file\n"; print "length = $len\n"; print "width = $width\n"; print "height = $height\n"; print "counter_string = $counter_string\n"; } # ================================================ # Raster image storage # Fill in the image contents from the # available pixmaps. # ================================================ my @raster_image = (); my $row; for($row=0;$row<$digit_height;$row++) { my $col; for($col=0;$col<$len;$col++) { my $digit = substr($counter_string,$col,1); my @digit_map = (); if( $font eq "8x8" ) { @digit_map = &Pixmap8x8Digit0() if( $digit eq "0" ); @digit_map = &Pixmap8x8Digit1() if( $digit eq "1" ); @digit_map = &Pixmap8x8Digit2() if( $digit eq "2" ); @digit_map = &Pixmap8x8Digit3() if( $digit eq "3" ); @digit_map = &Pixmap8x8Digit4() if( $digit eq "4" ); @digit_map = &Pixmap8x8Digit5() if( $digit eq "5" ); @digit_map = &Pixmap8x8Digit6() if( $digit eq "6" ); @digit_map = &Pixmap8x8Digit7() if( $digit eq "7" ); @digit_map = &Pixmap8x8Digit8() if( $digit eq "8" ); @digit_map = &Pixmap8x8Digit9() if( $digit eq "9" ); @digit_map = &Pixmap8x8Comma() if( $digit eq "," ); @digit_map = &Pixmap8x8Colon() if( $digit eq ":" ); @digit_map = &Pixmap8x8SemiColon() if( $digit eq ";" ); @digit_map = &Pixmap8x8Dot() if( $digit eq "." ); @digit_map = &Pixmap8x8Space() if( $digit eq " " ); } elsif( $font eq "16x24" ) { @digit_map = &Pixmap16x24Digit0() if( $digit eq "0" ); @digit_map = &Pixmap16x24Digit1() if( $digit eq "1" ); @digit_map = &Pixmap16x24Digit2() if( $digit eq "2" ); @digit_map = &Pixmap16x24Digit3() if( $digit eq "3" ); @digit_map = &Pixmap16x24Digit4() if( $digit eq "4" ); @digit_map = &Pixmap16x24Digit5() if( $digit eq "5" ); @digit_map = &Pixmap16x24Digit6() if( $digit eq "6" ); @digit_map = &Pixmap16x24Digit7() if( $digit eq "7" ); @digit_map = &Pixmap16x24Digit8() if( $digit eq "8" ); @digit_map = &Pixmap16x24Digit9() if( $digit eq "9" ); @digit_map = &Pixmap16x24Comma() if( $digit eq "," ); @digit_map = &Pixmap16x24Colon() if( $digit eq ":" ); @digit_map = &Pixmap16x24SemiColon() if( $digit eq ";" ); @digit_map = &Pixmap16x24Dot() if( $digit eq "." ); @digit_map = &Pixmap16x24Space() if( $digit eq " " ); } my $i; my $j = $row * $digit_width; for($i=0;$i<$digit_width;$i++,$j++) { $digit = $digit_map[$j]; push @raster_image,$digit; } } } # ================================================ # Write out the image file. # ================================================ if( $format eq "gif" ) { &WriteGifImage($img_file, \@raster_image, $debug_flag, $width, $height, $ct_flag, $bg_red, $bg_green, $bg_blue, $fg_red, $fg_green, $fg_blue); } if( $format eq "png" ) { &WritePngImage($img_file, \@raster_image, $debug_flag, $width, $height, $ct_flag, $bg_red, $bg_green, $bg_blue, $fg_red, $fg_green, $fg_blue); } exit 0; } # ================================================ # Write out a buffer. # ================================================ sub Write { my $hnd = shift; my $bytes = shift; my $byte; foreach $byte ( @$bytes ) { my $fld = pack("C",$byte); syswrite $hnd,$fld,1; } } # ================================================ # UpdateCounterFile # ================================================ sub UpdateCounterFile { my $counter_file = shift; my $id = shift; my $current_count = 0; # Wait for the locks to break. my $lock_file = "counter.lck"; while( -e $lock_file ) { sleep 1; } open LOCK,">$lock_file"; print LOCK "locked\n"; close LOCK; # Allow any number of user ids. my %records; if( -e $counter_file ) { open HND,"$counter_file"; while( ) { chop; if( /^\s*(\S+)\s+(\d+)\s*$/ ) { my $val = $2; if( "$id" eq "$1") { $current_count = 1 + $val; $records{$1} = $current_count; } else { $records{$1} = $val; } } elsif( /^(\d+)$/ ) { # This is an old-style entry, convert to anonymous. $records{"__anonymous__"} = $1; } } close HND; if( $current_count == 0 ) { # Add a new record. $current_count = 1; $records{$id} = $current_count; } } else { $records{$id} = 1; } # Save the new count. open HND,">$counter_file"; my $key; foreach $key ( sort keys %records ) { my $val = $records{$key}; print HND "$key $val\n"; } close HND; unlink $lock_file; return $current_count; } # ================================================ # WriteGifImage # ================================================ sub WriteGifImage { my $img_file = shift; my $in_raster_image = shift; my $debug_flag = shift; my $width = shift; my $height = shift; my $ct_flag = shift; my $bg_red = shift; my $bg_green = shift; my $bg_blue = shift; my $fg_red = shift; my $fg_green = shift; my $fg_blue = shift; # ================================================ # Constants. # ================================================ my @raster_image = @$in_raster_image; my $N = 7; my $CC = 2**($N); my $EI = $CC+1; my $CC_cycle = (2**$N)-2; my $width_lsb; my $width_msb; ($width_msb,$width_lsb) = &IntDiv($width,256); my $height_lsb; my $height_msb; ($height_msb,$height_lsb) = &IntDiv($height,256); # ================================================ # Debug # ================================================ if( $debug_flag ) { print "N = $N\n"; print "CC = $CC\n"; print "EI = $EI\n"; print "CC_cycle = $CC_cycle\n"; print "width = $width\n"; print "width_lsb = $width_lsb\n"; print "width_msb = $width_msb\n"; print "height = $height\n"; print "height_lsb = $height_lsb\n"; print "height_msb = $height_msb\n"; } # ================================================ # Write it out as a GIF87a image. # ================================================ if( $img_file ne "" ) { unlink $img_file; open HND,">$img_file"; } else { open HND,">-"; } binmode HND; # Write out the content type: # Content-type: image/gif\n\n my $fld; if( $ct_flag ) { $fld = pack("aaaaaaaa",'C','o','n','t','e','n','t','-'); syswrite HND,$fld,8; $fld = pack("aaaaaa",'t','y','p','e',':',' '); syswrite HND,$fld,6; $fld = pack("aaaaaa",'i','m','a','g','e','/'); syswrite HND,$fld,6; $fld = pack("aaacc",'g','i','f',10,10); syswrite HND,$fld,5; } # Write out the header: GIF87a $fld = pack("aaaaaa",'G','I','F','8','7','a'); syswrite HND,$fld,6; # ================================================ # Screen Descriptor # 7654 3210 # 1010 0110 <- 7 bits deep for each pixel (6+1) # ================================================ my @screen = ( $width_lsb, $width_msb, # 1,2: raster width $height_lsb, $height_msb, # 3,4: raster height 0xa6, # 5: 1010 0110 bits 0x00, # 6: bg color index 0x00 ); # 7: global color map Write(\*HND,\@screen); # ================================================ # Initialize the color table. # ================================================ my @colors = (); my $i; for($i=0;$i<128;$i++) { push @colors,0x00; push @colors,0x00; push @colors,0x00; } $colors[0] = $bg_red; $colors[1] = $bg_green; $colors[2] = $bg_blue; $colors[3] = $fg_red; $colors[4] = $fg_green; $colors[5] = $fg_blue; Write(\*HND,\@colors); # ================================================ # Image descriptor # ================================================ my @image_descriptor = ( 0x2c, # 1: ',' 0x00, 0x00, # 2,3: image left 0x00, 0x00, # 4,5: image top $width_lsb, $width_msb, # 6,7: image width $height_lsb, $height_msb, # 8,9: image height 0x00 ); # 10: bit map Write(\*HND,\@image_descriptor); # ================================================ # Create the raster image compression header. # In this case we are faking out the LZW compression # algorithm. # ================================================ my @image_header = ( 7 ); # 8 bit code entries Write(\*HND,\@image_header); # ================================================ # Insert clear-code information in the appropriate # places. # ================================================ my @image_out = (); my $num_bytes = $width * $height; my $image_size = 1 + $#raster_image; if( $debug_flag ) { if( $num_bytes != $image_size ) { print "ERROR: Image size ($image_size) does not\n"; print " match the number of image bytes ($num_bytes).\n"; exit 1; } print "image size = $image_size\n"; } # ================================================ # Walk through the image bytes and output a CC # every 126. # ================================================ my @image_data = (); my $byte; my $jj = 0; foreach $byte ( @raster_image ) { push @image_data,$CC if( $jj == 0 ); push @image_data,$byte; $jj++; $jj = 0 if( $jj == 126 ); } # ================================================ # Convert the image data for output. # This means the block size must be inserted for # each block. # ================================================ $num_bytes = 1 + $#image_data; my $block_size = 0xff; my $num_blocks = sprintf "%d",(($num_bytes + ($block_size-1))/$block_size); if( $debug_flag ) { print "image bytes (+CC) = $num_bytes\n"; print "block size = $block_size\n"; print "number of blocks = $num_blocks\n"; } my $ii = 0; for($i=0;$i<$num_blocks;$i++) { my $num = $block_size; $num = $num_bytes+2 if( $num_bytes < $block_size ); if( $debug_flag ) { print "block $i has $num bytes\n"; } push @image_out,$num; my $j; for($j=0;$j<$num;$j++,$ii++) { my $byte = $image_data[$ii]; push @image_out,$byte; # send the byte } $num_bytes = $num_bytes - $block_size; } # ================================================ # End of data. # ================================================ push @image_out,$EI; # end of data push @image_out,0; push @image_out,0x3b; if( $debug_flag ) { print "$ii image codes written\n"; } Write(\*HND,\@image_out); close HND; } # ================================================ # WritePngImage # ================================================ sub WritePngImage { my $img_file = shift; my $in_raster_image = shift; my $debug_flag = shift; my $width = shift; my $height = shift; my $ct_flag = shift; my $bg_red = shift; my $bg_green = shift; my $bg_blue = shift; my $fg_red = shift; my $fg_green = shift; my $fg_blue = shift; # TODO: Implement PNG format. } # ================================================ # Integer divide with modulus. # ================================================ sub IntDiv { my $num = shift; my $div = shift; my $x = 0; if( $num < $div ) { return (0,$num); } while( $num > $div ) { $num = $num - $div; $x++; } return ($x,$num); } # ================================================ # Pixmap16x24Digit0 # ================================================ sub Pixmap16x24Digit0 { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Digit1 # ================================================ sub Pixmap16x24Digit1 { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0, 0,0,1,1,1,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Digit2 # ================================================ sub Pixmap16x24Digit2 { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,1,1,1,1,0,0,0,0,0,1,1,1,1,0,0, 0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0, 0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0, 0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0, 0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0, 0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0, 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Digit3 # ================================================ sub Pixmap16x24Digit3 { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,1,1,1,1,0,0,0,0,0,1,1,1,1,0,0, 0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, 0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0, 0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0, 0,1,1,1,1,0,0,0,0,0,1,1,1,1,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Digit4 # ================================================ sub Pixmap16x24Digit4 { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,1,1,1,0,1,1,1,0,0, 0,0,0,0,0,0,1,1,1,0,0,1,1,1,0,0, 0,0,0,0,0,1,1,1,0,0,0,1,1,1,0,0, 0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0, 0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0, 0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Digit5 # ================================================ sub Pixmap16x24Digit5 { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0, 0,1,1,1,1,0,0,0,0,0,1,1,1,1,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Digit6 # ================================================ sub Pixmap16x24Digit6 { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,1,1,1,1,0,0,0,0,0,1,1,1,1,0, 0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,1,1,1,1,0,0,0,0,0,1,1,1,1,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,0, 0,0,1,1,1,1,0,0,0,0,0,1,1,1,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Digit7 # ================================================ sub Pixmap16x24Digit7 { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0, 0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0, 0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0, 0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Digit8 # ================================================ sub Pixmap16x24Digit8 { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Digit9 # ================================================ sub Pixmap16x24Digit9 { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0, 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0, 0,0,0,0,0,1,1,1,1,1,1,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0, 0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Comma # ================================================ sub Pixmap16x24Comma { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0, 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Colon # ================================================ sub Pixmap16x24Colon { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Dot # ================================================ sub Pixmap16x24Dot { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24SemiColon # ================================================ sub Pixmap16x24SemiColon { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0, 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap16x24Space # ================================================ sub Pixmap16x24Space { my @pixmap = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Digit0 # ================================================ sub Pixmap8x8Digit0 { my @pixmap = ( 0,1,1,1,1,1,0,0, 1,1,0,0,0,1,1,0, 1,1,0,0,0,1,1,0, 1,1,0,0,0,1,1,0, 1,1,0,0,0,1,1,0, 1,1,0,0,0,1,1,0, 0,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Digit1 # ================================================ sub Pixmap8x8Digit1 { my @pixmap = ( 0,0,0,1,1,0,0,0, 0,0,1,1,1,0,0,0, 0,1,1,1,1,0,0,0, 0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0, 0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Digit2 # ================================================ sub Pixmap8x8Digit2 { my @pixmap = ( 0,1,1,1,1,1,0,0, 1,1,0,0,0,1,1,0, 0,0,0,0,0,1,1,0, 0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0, 0,1,1,1,0,0,0,0, 1,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Digit3 # ================================================ sub Pixmap8x8Digit3 { my @pixmap = ( 0,1,1,1,1,1,0,0, 1,1,0,0,0,1,1,0, 0,0,0,0,0,1,1,0, 0,0,1,1,1,1,0,0, 0,0,0,0,0,1,1,0, 1,1,0,0,0,1,1,0, 0,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Digit4 # ================================================ sub Pixmap8x8Digit4 { my @pixmap = ( 0,0,0,0,1,1,1,0, 0,0,0,1,1,1,1,0, 0,0,1,1,0,1,1,0, 0,1,1,0,0,1,1,0, 1,1,1,1,1,1,1,0, 0,0,0,0,0,1,1,0, 0,0,0,0,0,1,1,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Digit5 # ================================================ sub Pixmap8x8Digit5 { my @pixmap = ( 1,1,1,1,1,1,1,0, 1,1,0,0,0,0,0,0, 1,1,0,0,0,0,0,0, 1,1,1,1,1,1,0,0, 0,0,0,0,0,1,1,0, 0,0,0,0,0,1,1,0, 1,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Digit6 # ================================================ sub Pixmap8x8Digit6 { my @pixmap = ( 0,1,1,1,1,1,0,0, 1,1,0,0,0,1,1,0, 1,1,0,0,0,0,0,0, 1,1,1,1,1,1,0,0, 1,1,0,0,0,1,1,0, 1,1,0,0,0,1,1,0, 0,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Digit7 # ================================================ sub Pixmap8x8Digit7 { my @pixmap = ( 1,1,1,1,1,1,1,0, 0,0,0,0,0,1,1,0, 0,0,0,0,1,1,0,0, 0,0,0,1,1,0,0,0, 0,0,1,1,0,0,0,0, 0,1,1,0,0,0,0,0, 0,1,1,0,0,0,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Digit8 # ================================================ sub Pixmap8x8Digit8 { my @pixmap = ( 0,1,1,1,1,1,0,0, 1,1,0,0,0,1,1,0, 1,1,0,0,0,1,1,0, 0,1,1,1,1,1,0,0, 1,1,0,0,0,1,1,0, 1,1,0,0,0,1,1,0, 0,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Digit9 # ================================================ sub Pixmap8x8Digit9 { my @pixmap = ( 0,1,1,1,1,1,0,0, 1,1,0,0,0,1,1,0, 1,1,0,0,0,1,1,0, 0,1,1,1,1,1,1,0, 0,0,0,0,0,1,1,0, 1,1,0,0,0,1,1,0, 0,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Comma # ================================================ sub Pixmap8x8Comma { my @pixmap = ( 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,1,1,0,0,0, 0,1,1,1,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Colon # ================================================ sub Pixmap8x8Colon { my @pixmap = ( 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Dot # ================================================ sub Pixmap8x8Dot { my @pixmap = ( 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8SemiColon # ================================================ sub Pixmap8x8SemiColon { my @pixmap = ( 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,1,1,0,0,0, 0,0,0,1,1,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,1,1,0,0,0, 0,1,1,1,0,0,0,0 ); return @pixmap; } # ================================================ # Pixmap8x8Space # ================================================ sub Pixmap8x8Space { my @pixmap = ( 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 ); return @pixmap; } # ================================================ # Format the string according to the -align, # -pad, -num_digits and -commas flags. # ================================================ sub FormatString { my $align = shift; my $commas_flag = shift; my $current_count = shift; my $num_digits = shift; my $pad = shift; my $counter_string; if( $commas_flag == 0 ) { if( $pad eq "0" ) { # Pad with leading zeros. # The alignment specification is ignored. my $fmt = "%0${num_digits}d"; $counter_string = sprintf $fmt,$current_count; } elsif( $pad eq " " ) { # Pad with leading spaces. # Make sure that it is aligned correctly. if( $align eq "right" ) { my $fmt = "%${num_digits}d"; $counter_string = sprintf $fmt,$current_count; } elsif( $align eq "left" ) { my $fmt = "%-${num_digits}d"; $counter_string = sprintf $fmt,$current_count; } elsif( $align eq "center" ) { my $tmp1 = sprintf "%d",$current_count; my $len = length $tmp1; if( $len < $num_digits ) { my $tmp2 = $num_digits - $len; $tmp2 = sprintf "%d",$tmp2/2; my $fmt = "%${tmp2}s"; $tmp2 = sprintf $fmt," "; $counter_string = "${tmp2}${tmp1}${tmp2}"; $len = length $counter_string; if( $len < $num_digits ) { $counter_string = " ${counter_string}"; } } else { $counter_string = $tmp1; } } } } else { # Comma's were specified. if( $pad eq "0" ) { # Zero pad requires special processing. # First the current_count string is # padded out with zeros, then the # leading characters are trimmed. # Alignment is ignored because all characters # are used. my $fmt = "%0${num_digits}d"; my $tmp = sprintf $fmt,$current_count; $current_count = $tmp; my $len = length $current_count; while( $len > 3 ) { my $digits = substr($current_count,$len-3,3); $counter_string = ",$digits$counter_string"; $tmp = substr($current_count,0,$len-3); $current_count = $tmp; $len = length $current_count; } $counter_string = "$current_count$counter_string"; # Now trim off the leading characters. $len = length $counter_string; while( $len > $num_digits ) { $tmp = substr($counter_string,1); $counter_string = $tmp; $len = length $counter_string; } # Now change the leading comma to a space, # if necessary. if( $counter_string =~ /^,/ ) { $counter_string =~ s/^,/ /; } } else { my $len = length $current_count; while( $len > 3 ) { my $digits = substr($current_count,$len-3,3); $counter_string = ",$digits$counter_string"; $current_count = sprintf "%d",($current_count/1000); $len = length $current_count; } $counter_string = "$current_count$counter_string"; if( $align eq "right" ) { $len = length $counter_string; if( $len < $num_digits ) { my $num_spaces = $num_digits - $len; my $spaces = sprintf "%${num_spaces}s",$pad; $counter_string = "$spaces$counter_string"; } } elsif( $align eq "left" ) { $len = length $counter_string; if( $len < $num_digits ) { my $num_spaces = $num_digits - $len; my $spaces = sprintf "%${num_spaces}s",$pad; $counter_string = "$counter_string$spaces"; } } elsif( $align eq "center" ) { $len = length $counter_string; if( $len < $num_digits ) { my $num_spaces = ($num_digits - $len) / 2; my $spaces = sprintf "%${num_spaces}s",$pad; $counter_string = "$spaces$counter_string$spaces"; $len = length $counter_string; if( $len < $num_digits ) { $counter_string = " ${counter_string}"; } } } } } return $counter_string; } # ================================================ # Parse args # This parse both cgi type arguments and # command line arguments. In cgi mode # it assumes that the separator is &. # ================================================ sub ParseArgs { my $in_args = shift; my @args = @$in_args; # 0 if this a command line help request # 1 if this a CGI help request my $html_flag = 0; my $tmp1 = $ENV{'GATEWAY_INTERFACE'}; if( $tmp1 ne "" ) { # This is a CGI script. $html_flag = 1; my $arg = $ENV{'QUERY_STRING'}; @args = split(/\&/,$arg); } # Initialize the return arguments. my $align = "right"; my $bg_red = 0x00; my $bg_green = 0x00; my $bg_blue = 0x00; my $commas_flag = 0; my $counter_file = "counter.dat"; my $debug_flag = 0; my $fg_red = 0xff; my $fg_green = 0xff; my $fg_blue = 0xff; my $font = "8x8"; my $format = "gif"; my $id = "__anonymous__"; my $img_file = ""; my $ct_flag = 1; my $num_digits = 6; my $pad = "0"; my $text = ""; # Initialize the internal arguments. my $env_flag = 0; # Process the command line arguments. # The leading - for switches is optional. while( $#args >= 0 ) { my $arg = shift @args; # Strip off the leading - if it is there. # This means that I only have to check # for the whole word switch values. $arg =~ s/^-// if( $arg =~ /^-/ ); if( $arg =~ /^align=(right|left|center)/ ) { $align = $1; } elsif( $arg =~ /^bg=(\d+),(\d+),(\d+)/ ) { $bg_red = $1; $bg_green = $2; $bg_blue = $3; } elsif( $arg =~ /^commas$/ ) { $commas_flag = 1; } elsif( $arg =~ /^counter_file=(.*)/ ) { $counter_file = $1; } elsif( $arg eq "env" ) { # This variable is not documented because it # is really only useful for CGI debugging. $env_flag = 1; } elsif( $arg =~ /^debug$/ ) { $debug_flag = 1; } elsif( $arg =~ /^fg=(\d+),(\d+),(\d+)/ ) { $fg_red = $1; $fg_green = $2; $fg_blue = $3; } elsif( $arg =~ /^font=8x8/ ) { $font = "8x8"; } elsif( $arg =~ /^font=16x24/ ) { $font = "16x24"; } elsif( $arg =~ /^format=gif/ ) { $format = "gif"; } elsif( $arg =~ /^format=png/ ) { $format = "png"; } elsif( $arg =~ /^id=(.+)/ ) { $id = $1; } elsif( $arg =~ /^img_file=(.+)/ ) { $img_file = $1; } elsif( $arg =~ /^help$/ ) { &Usage($html_flag,"",$counter_file,$env_flag); exit 0; } elsif( $arg =~ /^noct$/ ) { $ct_flag = 0; } elsif( $arg =~ /^num_digits=(\d+)/ ) { $num_digits = $1; } elsif( $arg =~ /^pad=space/ ) { $pad = " "; } elsif( $arg =~ /^pad=zero/ ) { $pad = "0"; } elsif( $arg =~ /^text=(\d+)/ ) { $text = $1; } elsif( $arg =~ /^width=(\d+)/ ) { $num_digits = $1; } elsif ( $arg ne "" ) { &Usage($html_flag,$arg,$counter_file,$env_flag); exit 0; } } # Make sure that the GIF information doesn't # go to stdout in debug mode. $img_file = "counter.gif" if( $img_file eq "" && $debug_flag == 1 ); # Return arguments. return ( $align, $bg_red, $bg_green, $bg_blue, $commas_flag, $counter_file, $debug_flag, $fg_red, $fg_green, $fg_blue, $font, $format, $id, $img_file, $ct_flag, $num_digits, $pad, $text ); } # ================================================ # Display the program usage. # ================================================ sub Usage { my $html_flag = shift; my $arg = shift; my $counter_file = shift; my $env_flag = shift; my $errmsg = ""; if( $arg ne "" ) { $errmsg = "ERROR: Unrecognized switch '$arg'\n"; $errmsg .= " or invalid switch arguments.\n"; } my $msg =<<'END'; Usage: counter.pl [] It is important to note that the '-' prefix on the switches is optional. This makes it easier to code the IMG SRC reference in your HTML file. -align=[left,center,right] Define the alignment. -bg=,, The background color. Red is a number from 0-255 that specifies the red intensity. Green is a number from 0-255 that specifies the green intensity and blue is a number from 0-255 that specifies the blue intensity. Here is an example usage that specifies a black background (the default): -bg=0,0,0 -commas Insert commas, these are counted as digits. The default is to not insert commas. -counter_file= The name of the counter file. -debug Enable interactive debugging. It should not be used from the CGI invocation. It causes the GIF data to be written to counter.gif instead of standard out. It also generates a number of informational messages. -fg=red,green,blue The foreground color. Red is a number from 0-255 that specifies the red intensity. Green is a number from 0-255 that specifies the green intensity and blue is a number from 0-255 that specifies the blue intensity. Here is an example usage that specifies a white foreground (the default): -fg=255,255,255 -font=[8x8,16x24] Specify the font. The 8x8 format is pretty small but useful because it conveys the information without cluttering up the page. The 16x24 is larger and more readable. Both were hand generated by me and can updated by editing this script. The 8x8 font was derived from the font generated by text2gif from authors of the libungif package. -format=[gif,png] Specify the image format. The choices are uncompressed GIF and PNG. Note that png format is not yet available. -help Display this help message and exit. -id= The user id that designates your unique counter in the data file. The unique id should only contain alpha-numeric characters, dots, dashes and underscores. It should be derived from something like your email address and project. For ccdoc, the id that I use is jlinoff-www.joelinoff.com-ccdoc. If no id is specified, the default __anonymous__. Beware that using this id will not provide valid count information unless you are using a custom data file. -img_file= The output image file name (for debugging). If this switch is not specified, the image is output to stdout. -noct Don't output the content-type header. This is useful for debugging when creating a standalone GIF. In normal operation a type header is output to inform the HTML processor that the incoming bits represent a GIF image. -num_digits= The number of digits to display (with leading zero's). This is the same as width. -pad=[space,zero] Defines the pad character. -text= Manually specify a digit string on the command line. The string can contain only contain decimal digits. When this switch is specified, no data is written to the counter file. -width The width of the field. Same as -num_digits. The examples below show how to use this script from the command line: % perl counter.pl -help % perl counter.pl -debug % perl counter.pl > tmp.gif % perl counter.pl -fg=255,0,0 -bg=0,255,0 % perl counter.pl -commas -counter_file=counter.dat % perl counter.pl -noct -commas -num_digits=10 -text="1234567" > tmp.gif % perl counter.pl -noct -num_digits=10 -text="1234567" -img_file tmp.gif The example below shows how to use this script from an HTML file. Acknowlegements: Eric S. Raymond For the libungif package. I used text2gif to derive the 8x8 fonts used here. Dr. Tom Lane For his explanation of the LZW patent issues in his posting to comp.graphics.misc on Dec 05 1996 as referenced in Subject V-7 in part of the FAQ found at: ftp://rtfm.mit.edu/pub/usenet/news.answers/graphics/fileformats-faq/part. I also used his explanation of where to insert the CC codes to create an uncompressed (or expanded) GIF that does not use the LZW algorithm. END my $tmpx; # hack to fix editor alignment if( $html_flag ) { $msg =~ s/&/&/g; $msg =~ s//>/g; # ================================================ # Arguments # ================================================ print "Content-type: text/html\n\n"; print "\n"; print "\n"; print "\n"; print "counter.pl help\n"; print "\n"; print "\n"; print "\n"; print "
\n"; print "

Help

\n"; print "
\n"; print "
\n";
	print $errmsg;
	my $tmp = "\$";
	print "\$Id: counter.pl,v 1.3 2004/09/30 07:34:13 jlinoff Exp $tmp\n";
	print "$msg";
	print "
\n"; # ================================================ # HTML Examples # ================================================ print "
\n"; print "
\n"; print "

HTML Examples

\n"; print "
\n"; print "

\n"; print "This section shows how to add a counter to your HTML file.\n"; print "All of the examples assume that the image statement looks like this:\n"; print "<img border=1 src=example>.\n"; print "

\n"; my $cgi = "http://www.joelinoff.com/cgi-bin/counter.pl"; ##my $cgi = "http://ccdoc.sourceforge.net/cgi-bin/counter.pl"; ##my $cgi = "http://web/randd/cgi-bin/jdl_test_counter.pl"; my $src; ##my $extra = "&counter_file=jdl_test_example.dat"; my $extra = ""; my $id = "counter-help-examples"; $src = "$cgi?id=${id}"; print "

Example 1: Simple

\n"; print "
\n"; print "<img border=1 src=\"$src\">
\n"; print ""; print "
\n"; $src = "$cgi?id=${id}&pad=space"; print "

Example 2: Pad with spaces

\n"; print "
\n"; print "<img border=1 src=\"$src\">
\n"; print ""; print "
\n"; $src = "$cgi?id=${id}&pad=space&align=center"; print "

Example 3: Center

\n"; print "
\n"; print "<img border=1 src=\"$src\">
\n"; print ""; print "
\n"; $src = "$cgi?id=${id}&num_digits=12"; print "

Example 4: Change the width

\n"; print "
\n"; print "<img border=1 src=\"$src\">
\n"; print ""; print "
\n"; $src = "$cgi?id=${id}&fg=255,0,0&bg=0,255,0"; print "

Example 5: Change the foreground and background colors

\n"; print "
\n"; print "<img border=1 src=\"$src\">
\n"; print ""; print "
\n"; $src = "$cgi?id=${id}&font=16x24"; print "

Example 6: Change the font size

\n"; print "
\n"; print "<img border=1 src=\"$src\">
\n"; print ""; print "
\n"; $src = "$cgi?id=${id}&commas&pad=space&width=10"; print "

Example 7: Embed commas

\n"; print "
\n"; print "<img border=1 src=\"$src\">
\n"; print ""; print "
\n"; $src = "$cgi?id=${id}&commas&pad=space&width=14&text=1234567890&font=16x24&align=center"; print "

Example 8: Write a fixed number

\n"; print "
\n"; print "<img border=1 src=\"$src\">
\n"; print ""; print "
\n"; # ================================================ # Usage Data # ================================================ print "
\n"; print "
\n"; print "

Used Ids for $counter_file

\n"; print "
\n";
	if( -e $counter_file ) {
	    my $cnt = 0;
	    print "Id                               Count\n";
	    print "================================ ======\n";
	    open HND,"$counter_file";
	    while(  ) {
		if( /^\s*(\S+)\s+(\d+)\s*$/ ) {
		    printf "%-32s %6d\n",$1,$2;
		    $cnt++;
		}
	    }
	    printf "\n%-32s %6d\n","TOTAL",$cnt;
	    close HND;
	}
	print "
\n"; print "
\n"; # ================================================ # License # ================================================ print "
\n"; print "
\n"; print "

License

\n"; print "
\n"; print "Copyright (C) 1998-2003 by Joe Linoff (http://www.joelinoff.com)
\n"; print "

\n"; print "Permission is hereby granted, free of charge, to any person obtaining\n"; print "a copy of this software and associated documentation files (the\n"; print "\"Software\"), to deal in the Software without restriction, including\n"; print "without limitation the rights to use, copy, modify, merge, publish,\n"; print "distribute, sublicense, and/or sell copies of the Software, and to\n"; print "permit persons to whom the Software is furnished to do so, subject to\n"; print "the following conditions:\n"; print "

\n"; print "

\n"; print "The above copyright notice and this permission notice shall be\n"; print "included in all copies or substantial portions of the Software.\n"; print "

\n"; print "

\n"; print "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"; print "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"; print "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n"; print "IN NO EVENT SHALL JOE LINOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n"; print "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n"; print "ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n"; print "OTHER DEALINGS IN THE SOFTWARE.\n"; print "

\n"; print "

\n"; print "Comments and suggestions are always welcome.\n"; print "

\n"; # ================================================ # CGI Environment Variables # ================================================ if( $env_flag ) { print "
\n"; print "
\n"; print "

CGI Environment Variables

\n"; print "
\n"; print "
\n";
	    my $key;
	    foreach $key ( sort keys %ENV ) {
		my $e = $ENV{$key};
		$e =~ s/&/&/g;
		$e =~ s//>/g;
		printf "%-20s \"%s\"\n",$key,$e;
	    }
	    print "
\n"; } print "\n"; print "\n"; } else { print $errmsg; my $tmp = "\$"; print "\$Id: counter.pl,v 1.3 2004/09/30 07:34:13 jlinoff Exp $tmp\n"; print $msg; } }