Приглашаем посетить
Join Gif
#!/usr/local/bin/perl
# Simple example of how to call the subroutine
$directory = "/www/cpatch/cgi-bin/Odometer";
@filenames = ("1A.GIF", "0A.GIF", "0A.GIF", "4A.GIF", "6A.GIF", "1A.GIF");
$new_gif = join_gif($directory, *filenames);
open(TEST, ">test.gif");
syswrite(TEST, $new_gif, length($new_gif));
close(TEST);
### Subroutine: &join_gif()
###
### Function: To join multiple gif files into one file.
###
### Usage: &join_gif($directory, *filenames);
###
### Variables: $directory -- Directory containing GIF files.
### Format: "/home/gif"
### *filenames -- Reference to ordered list containing names of
### GIF files to be joined.
### Format: ("file1.gif", "file2.gif", ...)
###
### Returns: String containing joined GIF data if successful
### Null string if unsuccessful
###
### Files Created: None
sub join_gif {
# Initialize & declare variables
local($directory, *filenames) = @_;
local($length, $file, $buf, $gif_data, $new_gif, $flags, $gcm_size, $lcm_size,
$max_width, $width, $bottom, $cur_left, $max_height, $height, $file_width,
$left);
# Process each file
$first = 1;
foreach $file (@filenames) {
# Read the data into a buffer and make sure it's a GIF file
$length = -s "$directory\/$file" || return '';
open (FILE, "$directory\/$file") || return '';
read(FILE, $buf, $length) || return '';
close(FILE);
if (substr($buf, 0, 3) ne "GIF") { return '' }
substr($buf, 3, 3) = "89a";
# Convert the buffer to a list of decimal values
@gif_data = unpack("C*", $buf);
# Determine size of global color map (0 if none)
$flags = $gif_data[10];
$gcm_size = (3 * (2 ** (($flags & 7) + 1))) * (($flags & 128) eq 128);
# If it's the first file, copy the header block (signature, screen descriptor,
# and global color map) to the new GIF. Otherwise just process the width and
# height info and discard the header block.
if ($first) {
# Copy the header block
push(@new_gif, splice(@gif_data, 0, 13 + $gcm_size));
# Initialize our width and height tracking variables
$file_height = $max_height = $new_gif[8] + 256 * $new_gif[9];
$file_width = $new_gif[6] + 256 * $new_gif[7];
$first = 0;
}
else {
# It's not the first file, so process the width and height
$height = $gif_data[8] + 256 * $gif_data[9];
if ($height > $max_height) { $max_height = $height }
$file_width = $gif_data[6] + 256 * $gif_data[7];
# Discard the header block
splice(@gif_data, 0, 13 + $gcm_size);
}
# Scan through the rest of the file
while (@gif_data) {
# Copy the extension block if there is one
if ($gif_data[0] == 33) {
# Copy header
push(@new_gif, splice(@gif_data, 0, 3));
# Copy data blocks
while ($new_gif[@new_gif - 1]) {
push(@new_gif, splice(@gif_data, 0, $new_gif[@new_gif - 1] + 1));
}
}
# Copy image block if there is one
elsif ($gif_data[0] == 44) {
# Calculate and set the new left position for the image
$left = $gif_data[1] + 256 * $gif_data[2] + $cur_left;
@gif_data[1,2] = ($left % 256, int($left/256));
# Determine size of local color map (0 if none)
$flags = $gif_data[9];
$lcm_size = (3 * (2 ** (($flags & 7) + 1))) * (($flags & 128) eq 128);
# Copy image descriptor, local color map, code size, and block count
push(@new_gif, splice(@gif_data, 0, $lcm_size + 12));
# Copy raster data
while ($new_gif[@new_gif - 1]) {
push(@new_gif, splice(@gif_data, 0, $new_gif[@new_gif - 1] + 1));
}
}
# Stop processing file if we get to a terminator
elsif ($gif_data[0] == 59 ) { last }
# If we find anything else then this is an invalid file
else { return ''; }
}
# Set the left position of the next file
$cur_left += $file_width;
}
# Set the terminator for the new GIF
push(@new_gif, 59);
# Set the width and height of the new GIF
if ($cur_left > $file_width) { @new_gif[6,7] = ($cur_left % 256, int($cur_left/256)) }
@new_gif[8,9] = ($max_height % 256, int($max_height/256));
# Return the new GIF as a binary string
return pack("C*", @new_gif);
}