#!/usr/bin/perl
#
# Currently this code is an unholy
# rats nest of pain and death. I've 
# got a kind of step through of what 
# I'm doing that runs as the program does
# but it's a little too integrated into the
# actual data processing side of things right
# now. Next step before anything else is to 
# seperate out the components, and clean up
# this code. Sorry if you have to read this.
# 
# -Sam 4/14/04
#
#############################


###
# Includes
###
use GD;
use Math::MatrixReal;
use Math::FFT;


###
# Clear the screen for ease of debug
###
$cs = `clear`;
print $cs;

### 
# Grab image info
###
my $pic = 'kblock.png';
my $truecolor = '1';
my $img = GD::Image->newFromPng($pic, $truecolor);
my ($width, $height) = $img->getBounds();
my $wblock = ($width / 8);
my $hblock = ($height / 8);
my $blocks = ($wblock * $hblock);


###
# Build the color matrices and use them
###

my $YVals  = new Math::MatrixReal($width, $height);
my $CbVals = new Math::MatrixReal($width, $height);
my $CrVals = new Math::MatrixReal($width, $height);

for ($xct = 1; $xct != $width; $xct++)
        {
        for ($yct = 1; $yct != $height; $yct++)
                {
                my ($r,$g,$b) = $img->rgb($img->getPixel($x,$y));
                my $Y  = ( 0.299  * $r +   0.587 * $g + 0.114  * $b +   0);
                my $Cb = (-0.1687 * $r - 0.03313 * $g + 0.5    * $b + 128);
                my $Cr = ( 0.5    * $r - 0.4187  * $g - 0.0813 * $b + 128);
                $y++;
                $xrow = ($x + 1);
                $yrow = ($y + 1);
		####
		# Level Shift here.           
		####

		$Y -= 128; $Cb -= 128; $Cr -= 128;
                $YVals ->assign($xrow, $yrow, $Y );
                $CbVals->assign($xrow, $yrow, $Cb);
                $CrVals->assign($xrow, $yrow, $Cr);
               }
        $y = 0;
        $x++;
        }

walkthrough(1);


###
# Run DCT on entire block. This needs to be done on
# a block by block basis, but for now I just wanna
# get the dct running.
###

my $vals = $YVals->as_matlab((format =>"%.0f"));
$vals  =~ s/ //;
$vals  =~ s/\]//g;
$vals  =~ s/\[//g;
$vals  =~ s/;//g;
$vals  =~ s/\n//g;
@ytemp = split / /, $vals;


my $vals = $CbVals->as_matlab((format =>"%.0f"));
$vals   =~ s/ //;
$vals   =~ s/\]//g;
$vals   =~ s/\[//g;
$vals   =~ s/;//g;
$vals   =~ s/\n//g;
@cbtemp = split / /, $vals;



my $vals = $CrVals->as_matlab((format =>"%.0f"));
$vals   =~ s/ //;
$vals   =~ s/\]//g;
$vals   =~ s/\[//g;
$vals   =~ s/;//g;
$vals   =~ s/\n//g;
@crtemp = split / /, $vals;

$ct = 0;
foreach (@ytemp)
	{
	$ydata->[$ct] = "$_";
	$ct++;
	}
$ct = 0;
foreach (@cbtemp)
	{
	$cbdata->[$ct] = $_;
	$ct++;
	}
$ct = 0;
foreach (@crtemp)
	{
	$crdata->[$ct] = $_;
	$ct++;
	}




my $yfft  = new Math::FFT($ydata);
my $cbfft = new Math::FFT($cbdata);
my $crfft = new Math::FFT($crdata);
my $ycoeff  = $yfft ->ddct();
my $cbcoeff = $cbfft->ddct();
my $crcoeff = $crfft->ddct();

my $ycoeffmatrix = new Math::MatrixReal (8,8);
$ct = 0;
for ($row = 1; $row != 9; $row++)
        {
        for ($col = 1; $col != 9; $col++)
                {
		$ycoeffmatrix->assign($row,$col,$ycoeff->[$ct]);
		$ct++;
		}
	}

my $cbcoeffmatrix = new Math::MatrixReal (8,8);
$ct = 0;
for ($row = 1; $row != 9; $row++)
        {
        for ($col = 1; $col != 9; $col++)
                {
                $cbcoeffmatrix->assign($row,$col,$cbcoeff->[$ct]);
                $ct++;                   
                }
	}

my $crcoeffmatrix = new Math::MatrixReal (8,8);
$ct = 0;
for ($row = 1; $row != 9; $row++)
        {
        for ($col = 1; $col != 9; $col++)
                {
                $crcoeffmatrix->assign($row,$col,$crcoeff->[$ct]);
                $ct++;
                }
	}

walkthrough(2);


#####
# Define the Luminance and Chrominance
# quantization tables here. These are the 
# standard jpeg quantization tables set forth 
# by the itu-t81 jpeg standard. 
#####
$LumQuantTable = Math::MatrixReal->new_from_rows(
        [
                [ 16,  11,  10,  16,  24,   40,   51,   61 ],
                [ 12,  12,  14,  19,  26,   58,   60,   55 ],
                [ 14,  13,  16,  24,  40,   57,   69,   56 ],
                [ 14,  17,  22,  29,  51,   87,   80,   62 ],
                [ 18,  22,  37,  56,  68,   109,  103,  77 ],
                [ 24,  35,  55,  64,  81,   104,  113,  92 ],
                [ 49,  64,  78,  87,  103,  121,  120,  101],
                [ 72,  92,  95,  98,  112,  100,  103,  99 ],
        ]);

$ChromQuantTable = Math::MatrixReal->new_from_rows(
	[
		[ 17, 18, 24, 47, 99, 99, 99, 99 ],	
		[ 18, 21, 26, 66, 99, 99, 99, 99 ],
		[ 24, 26, 56, 99, 99, 99, 99, 99 ],
		[ 47, 56, 99, 99, 99, 99, 99, 99 ],
		[ 99, 99, 99, 99, 99, 99, 99, 99 ], 
                [ 99, 99, 99, 99, 99, 99, 99, 99 ],
                [ 99, 99, 99, 99, 99, 99, 99, 99 ],
                [ 99, 99, 99, 99, 99, 99, 99, 99 ],

	]);




####
# Run DCT coeffecients of Y, Cb, and Cr, 
# through the quantization Matrix.
####


my $yquantized = new Math::MatrixReal(8, 8); 
my @ytemp;
$ct = 0;
for ($row = 1; $row != 9; $row++) 
	{
	for ($col = 1; $col != 9; $col++)
		{
		$quantval = $LumQuantTable->element($row, $col);
		$value = (($ycoeff->[$ct]) / ($quantval + 0.5));
		push (@ytemp, $value);
 		$yquantized->assign($row,$col,$value);
		$ct++;
		}
	}


my $cbquantized = new Math::MatrixReal(8, 8);
my @cbtemp;
$ct = 0;
for ($row = 1; $row != 9; $row++)
        {
        for ($col = 1; $col != 9; $col++)
                {
                $quantval = $ChromQuantTable->element($row, $col);
                $value = (($cbcoeff->[$ct]) / ($quantval + 0.5));
		push (@cbtemp, $value);
                $cbquantized->assign($row,$col,$value);
                $ct++;
                }
        }

 
my @crtemp;
my $crquantized = new Math::MatrixReal(8, 8);
$ct = 0;
for ($row = 1; $row != 9; $row++)
        {
        for ($col = 1; $col != 9; $col++)
                {
                $quantval = $ChromQuantTable->element($row, $col);
                $value = (($crcoeff->[$ct]) / ($quantval + 0.5));
		push (@crtemp, $value);
                $crquantized->assign($row,$col,$value);
                $ct++;                                
                }
        }



walkthrough(3);

@zigsort = qw( 0  1  5  6  14 15 27 28 
               2  4  7  13 16 26 29 42 
               3  8  12 17 25 30 41 43 
               9  11 18 24 31 40 44 53 
               10 19 23 32 39 45 52 54 
               20 22 33 38 46 51 55 60 
               21 34 37 47 50 56 59 61 
               35 36 48 49 57 58 62 63
	      );

@ysorted = sort { $a <=> $b } @ytemp;
my $YZigged = new Math::MatrixReal(8, 8);
$ct = 0;
for ($row = 1; $row != 9; $row++)
        {
        for ($col = 1; $col != 9; $col++)
                {
                $YZigged->assign($row,$col,$ysorted[$zigsort[$ct]]);
                $ct++;
                }
        }

@cbsorted = sort { $a <=> $b } @cbtemp;
my $CbZigged = new Math::MatrixReal(8, 8);
$ct = 0;
for ($row = 1; $row != 9; $row++)
        {
        for ($col = 1; $col != 9; $col++)
                {
                $CbZigged->assign($row,$col,$cbsorted[$zigsort[$ct]]);
                $ct++;
                }
        }



@crsorted = sort { $a <=> $b } @crtemp;
my $CrZigged = new Math::MatrixReal(8, 8);
$ct = 0;
for ($row = 1; $row != 9; $row++)
        {
        for ($col = 1; $col != 9; $col++)
                {
		$CrZigged->assign($row,$col,$crsorted[$zigsort[$ct]]);
		$ct++;
		}
	}

walkthrough(4);
walkthrough(5);



sub walkthrough
{
$num = shift;


if ($num == 1)
{
print <<endofblock;

Initial Luminance Values
-----------------------------------------------

$YVals


Initial Chrominance Values
---------------------------------------------

Cb :
$CbVals


Cr :
$CrVals


Now we run the DCT Transforms on these values, Press enter to Continue

endofblock

<STDIN>;
print $cs;
}



if ($num == 2)
{
print <<endofblock;

at this point the DCT coeffecients of all three components are stuck in 
three seperate arrays. There's no real point to sticking into matrices right
now since we're about to quantize them, but since we're doing show and tell
it helps display the data...

Luminance DCT coeffecients
-----------------------------
$ycoeffmatrix;

Chrominance DCT coeffecients
------------------------------

Cr:
$crcoeffmatrix;

Cb;
$cbcoeffmatrix

next up is the quantification. 
Press enter to continue...

endofblock

<STDIN>;
print $cs;
}

if ($num == 3)
{
print <<endofblock;

Quantized Luminance Matrix
-------------------------------

$yquantized

Quantized Chrominance Matrices
-------------------------------------

Cr :
$crquantized


Cb :
$cbquantized

Now I've got to do the zig-zag re-ordering of the quantized matrices. I actually created
matrices to hold the quantization data, but thats mostly for display purposes since I'm
not using those matrices, but sorting arrays of the numbers that I'm creating at the same
time. Eventually I'll get rid of them, but for now it makes showing the work easier. 

press Enter to continue

endofblock

<STDIN>;
print $cs;
} 


if ($num == 4)
{
print <<endofblock;

Zigged Luminance Matrix
------------------------------
$YZigged

Zigged Chrominance Matrices
------------------------------
Cr : 
$CrZigged

Cb : 
$CbZigged

Pulled this off by creating an array \@zigsort :

\@zigsort = qw(
	       0  1  5  6  14 15 27 28
               2  4  7  13 16 26 29 42
               3  8  12 17 25 30 41 43
               9  11 18 24 31 40 44 53
               10 19 23 32 39 45 52 54
               20 22 33 38 46 51 55 60
               21 34 37 47 50 56 59 61
               35 36 48 49 57 58 62 63
	      )



sorted all the values in the quantized arrays from lowest to
highest and then placed them in order according to this array 
into their new matrices.  

The next step is runlength and then huffman encoding after rounding
all of these numbers off. 

press enter to continue

endofblock

<STDIN>;
print $cs;
}

if ($num == 5)
{
print <<endofblock;

haven't gotten the encoding stuff together yet, I know there's a
huffman encoding module, and I'm hoping there's a runlength one as
well, also at this point I'm beginning to wonder whether or not I
actually need to use matrices at all. They really make handling the
data easier, but it seems like whenever I need to actually do
something to the numbers I'm taking them out of the matrix. I'll most
likely end up removing Math::MatrixReal from the script entirely, but
as of now it makes it conceptually less painful to figure this stuff
out. Also, I still haven't grabbed the DC coeffecient, for each of the
blocks, but I figure thats more of a weekend project at this point.

endofblock
}

## End of subroutine
}# DONT ERASE THIS
## !!!!!!!!!!!!!!!!!!





#################################################################
# This was the old note that was at step 3 in the walkthrough.
# saving it because it's a pretty good description of what I  
# need to finish this up
#
#
#
# Now I still have to zig-zag order these numbers, 
# do runlength and then huffman encoding
# I forgot to grab the DC coeffecient before I ran the quantization, 
# but I should still be
# able to grab that, mainly due to the fact that I've been sloppy 
# about getting rid of
# matrices and data that I'm not using anymore. After I get the 
# encoding out of the way,
# I'm gonna organize the variables in a slightly more decent 
# (read sane) manner. Also, it's
# occured to me that a way to actually get a finished product 
# out of this is to package it
# as a module that works on 8x8 blocks of RGB data, which 
# would be something that could be
# used later if I want to continue on this.
#
###################################################################
