Makeagif.pl
-----------
Author: Shawn Wallace (shawn@as220.org)
Category: Best 'The Perl Journal'
Size: 803 bytes w/o whitespace

The Makeagif.pl script will create an animated GIF that displays 
the letters in "The Perl Journal" one at a time with different 
backgrounds. It should be viewable with a web browser or (hopefully!)
with any image viewer that can display a GIF89a (ImageMagick's
animate, GIMP, etc.). 

Since whitespace is not counted toward the byte limit, the GIF is 
encoded in the whitespace in the document source. 

The encoding scheme is something like this (where a '.' == a space and 
a '!' == a tab):

Encoded	                  Decimal      ASCII
..!........!.!         =     071 =      'G'
....!........!.!       =     073 =      'I'
.!........!.!          =     070 =      'F'
.......!......!.!      =     056 =      '8'
........!......!.!     =     057 =      '9'
........!..........!.! =     097 =      'a'
(etc.)

Basically, each byte is stored as a tuplet of spaces where the number 
of spaces in each is: 
  (one's digit)+1 spaces, then  
  (ten's digit) +1 spaces, then
  (hundreds digit)+1 spaces

These tuplets are arbitrarily grouped in tens and interspersed 
throughout the code.

The program reads it's source (probably a lot of entries doing that, huh?)
and decodes the GIF from the whitespace. Of course, a few things had to be hidden (had to try at least).
 
Going through the code:


# The comment block is used later for some data...

 
# ********************************************************************
# * Makeagif.pl This script generates 'The Perl Journal' in the file *
# * perljournal.gif -- > Can you figure out how it works ?           *
# ********************************************************************



###
# The 'd' subroutine is used to decode the @gifdata and @gifout arrays.
# It is first called with 0 as its first parameter, so it will map 
# a function (multiplying each parameter by pi/4 and adding one) to 
# yield a second list of numbers: 
#  ( 67,42,77,97,107,101,97,103,105,102,46,112,108)
# This list is passed back into the d subroutine with a 1 as the first 
# value, and 'C*' as the second and third values (to be used as parameters 
# to pack). The second time it is called, it yields the string
# 'Makeagif.pl'.

sub  
d {
if (shift) {
pack 
chr(shift).chr(shift),
@_;
} else {
map 
{int($_ * 
atan2(1,1))+1 } 
@_;
}
}

# The gifdata is the string 'C*Makeagif.pl' encoded with an
# arbitary function (each ascii value divided by pi/4). See above. 
# Hopefully the names 'gifdata' and 'gifout' are misleading as well.

@gifdata = 
(0, 0, 85.307, 53.476, 
98.039, 123.504, 136.234,
128.597, 123.504, 131.143, 
133.690, 129.870, 58.569, 
142.602, 137.509) ;

@gifout = d 
@gifdata;


# Now we open the source file 'Makeagif.pl' and read the comment section.
# We'll pull out the '>', 'perljournal.pl', '?', and a '*' for later use.
 
$/="  *";
open O , d 
@gifout;
@__5 = 
split " ", <O>;
open I, 
$__5[$#gifdata+5].
$__5[$#gifdata+3];
binmode I;

# This is just a big ugly regex.
# Did it this way to hide the fact that its matching patterns
# of spaces.
# The regex is clumsy:  /^( *?)\t( *?)\t( *?)\t(.*)$/ 

$d = "^( "; 
$_d = ")\\t( "; 
$__d = 
$__5[$#gifout+14];
$_ = 
$__5[$#gifout+3];
$___d = 
$d.$_.$__d.$_d.$_.$__d.$_d.$_.$__d.")\\t(.".$_.")\$";


# Now read the rest of the file
# 

$/="\n";
while ( <O> ) {

# If a line starts with a space, we'll decode it.
# Hopefully this will confuse the prettyprinters...

if ( $_ =~ 
/^ /) {
$_5 = $_;
while
($_5) {

# This is the ugly regex

$_5 =~ /$___d/;

# $4 is the remainder of the line

$_5 = $4;

# decode as above
 
print I chr( ( length( $1 ) - 1 ) +
( length( $2 ) -1 ) * 10 +
( length ($3 ) - 1 ) * 100 ) ;
}
}
}


That's all. I can answer further questions by e-mail.

--Shawn
shawn@as220.org


