#!/usr/bin/perl

# version 0.0.1
# file version 00000001

# import ImageMagick perl wrapper and POSIX functions
use Image::Magick;
use POSIX;
use integer;

# check arguments
if ($#ARGV < 1) {
	die <<EOF;
Error: not enough arguments.
	
steg-decode.pl - Hide a message in an image.
------------------------------------------------------------------------------
Usage: steg-encode.pl infile outfile

EOF
} 

# grab arguments
$infile = shift @ARGV;
$outfile = shift @ARGV;

# some useful globals
$xSize = 0;
$ySize = 0;
$msgSize = 0;

# read image - note: this function also sets $xSize and $ySize.
@letter = &readImageIntoArray($infile);

@body = &unfoldLetter(@letter);

$message = &readLetter(@body);

open(F,">$outfile");
print F $message;
close(F);

################## Functions ################## 

sub readImageIntoArray {

	# open the file
	$f = shift @_;
	$image = Image::Magick->new;
	$image->Read($f);
	
	# set to 24bit colour
	$image->Set(depth=>8);
	
	# find dimensions
	($xSize, $ySize) = $image->[0]->Get('width', 'height');
	&debug("Image $f: x is $xSize, y is $ySize");
	
	# prepare initial array
	@retval = ();
	
	# loop through each pixel of the image
	for ($x = 0; $x < $xSize; $x++) {
		for ($y = 0; $y < $ySize; $y++) {
		
			# look at the pixel colour
			$p = $image->Get("pixel[$x,$y]");
			
			# split into RGBA components. discard alpha channel.
			($r,$g,$b,$a) = split(/\,/, $p);
			
			# IMPORTANT:
			# Some versions of ImageMagic use 24-bit RGB, if this describes you, then
			# change the next line to read "if ( 1==0 ) {". 
			if ( 1==1 ) {
				# ImageMagick is using 48-bit RGB, so divide through to get 24-bit.
				$r = $r >> 8;
				$g = $g >> 8;
				$b = $b >> 8;
			}
			
			# add these values to the array.
			@retval = (@retval, $r, $g, $b);
			
		}
	}
	
	# image is now contained into array.
	return @retval;
	
}

sub unfoldLetter {

	# get version string
	$version = '';
	for($i = 0; $i < 8; $i++) {
		$v = shift @_;
		$version .= $v%2;
	}
	&debug ("Version string: $version");
	
	# check it's one we know.
	die ("Unrecognised steg version: $version") unless ($version eq '00000001');

	# find out body size and set $msgSize global.
	$msgSize = 0;
	for($i = 0; $i < 24; $i++) {
		$s = shift @_;
		$msgSize = ($msgSize * 2) + ($s%2);
	}
	&debug ("Letter Body is $msgSize bytes");
	
	# return the letter body.
	return @_;
	
}

sub readLetter {

	# initialise variable
	$retval = '';

	# for each character of the message (ignoring empty parts of the envelope)
	for($i = 0; $i < $msgSize; $i++) {
	
		# get 8 bits
		$thisbyte = '';
		for($j = 0; $j < 8; $j++) {
			$b = shift @_;
			$thisbyte .= $b%2;
		}
		
		# convert them into a character
		$char = pack('B8', $thisbyte);

		# tack it onto the end of the return value
		$retval .= $char;
	
	}
	
	# return
	return $retval;
	
}

sub debug {
	$l = shift @_;
	print "$l\n";
}
