Приглашаем посетить
Полевой Н.А. (polevoy.lit-info.ru)

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);
}