#!/usr/bin/perl -w
#
# This script was written by Grant McLean <grantm@cpan.org>
#
# Permission is hereby granted to use, modify and distribute it under the same
# terms as Perl itself.
#

use strict;

use Image::Magick;
use List::Util ();

# For Win32, add folder containing ImageMagick DLLs to PATH
$ENV{PATH} .= ';C:\Perl\site\lib\auto\Image\Magick';

my $page_width  = 700;
my $page_height = 1040;

my $columns     = 5;
my $rows        = 4;

my $char_height = 20;

my $pic_width   = 400;
my $pic_height  = 300;
my $pic_x       = int(($page_width - ($pic_width + $char_height * ($columns - 1))) / 2);
my $pic_y       = $char_height;

my $input_file  = shift or die "Usage: $0 filename.gif\n";

# Read in the source image and work out its dimensions

my $err;
my $src = Image::Magick->new;
$err = $src->Read($input_file);
die $err if($err);

my $src_width  = $src->Get('width');
my $src_height = $src->Get('height');


# Work out the scaled dimensions and resize the source

my $pic_ratio = $pic_width / $pic_height;
my $src_ratio = $src_width / $src_height;

my($new_width, $new_height);
if($pic_ratio > $src_ratio) {
  $new_height = $pic_height;
  $new_width  = int($pic_height * $src_ratio);
}
else {
  $new_width  = $pic_width;
  $new_height = int($pic_width / $src_ratio) + 1;
}

$src->Resize(width => $new_width, height => $new_height);

# Pad the image out to an exact multiple of rows and cols

my $pad = $rows + $columns;
$src->Border(width => $pad, height => $pad, fill => 'white');
my $pad_width  = int(($new_width  + $columns - 1) / $columns) * $columns;
my $pad_height = int(($new_height + $rows    - 1) / $rows)    * $rows;
$src->Crop(
  width  => $pad_width, 
  height => $pad_height, 
  x      => $pad - int(($pad_width  - $new_width)  / 2),
  y      => $pad - int(($pad_height - $new_height) / 2),
);
$new_width  = $src->Get('width');
$new_height = $src->Get('height');


# Create a completely new image to paste the chunks into

my $composite = Image::Magick->new(size => "${page_width}x${page_height}");
$composite->Read('xc:white');


# Build up a list of chunk coordinates and then shuffle them

my $chunk_width  = int($new_width  / $columns);
my $chunk_height = int($new_height / $rows   );

my @row = qw(A B C D);
my @cells;

for(my $i = 0; $i < $rows; $i++) {
  for(my $j = 0; $j < $columns; $j++) {

    push @cells, {
      label => $row[$i] . ($j + 1),
      cx    => $j * $chunk_width,
      cy    => $i * $chunk_height,
    };

  }
}

@cells = List::Util::shuffle(@cells);

# Loop through carving off chunks and pasting them in

for(my $i = 0; $i < @cells; $i++) {
  my $c = $cells[$i];

  my $x = $pic_x + ($chunk_width  + $char_height) * ($i % $columns);
  my $y = $pic_y + ($chunk_height + $char_height) * int($i / $columns);

  my $chunk = $src->Clone();
  $chunk->Crop(
    width  => $chunk_width, 
    height => $chunk_height, 
    x      => $c->{cx},
    y      => $c->{cy},
  );

  $chunk->Border(width => 1, height => 1, fill => 'black');

  $composite->Composite(
    image   => $chunk, 
    compose => 'Over', 
    x       => $x,
    y       => $y,
  );
  
  $composite->Annotate(
    text      => $c->{label},
    x         => $x,
    y         => $y - 1,
    font      => 'Generic.ttf',
    fill      => 'black',
    pointsize => 12,
  );

}

# Calculate the dimensions of the blank grid at the bottom

my $grid_x      = 2 * $char_height;
my $grid_y      = $pic_y + $pic_height + ($rows + 1) * $char_height;
my $grid_width  = $page_width - 4 * $char_height;
my $grid_height = $page_height - $grid_y - 1;

if($grid_width / $src_ratio > $grid_height) {
  $grid_width   = int($grid_height * $src_ratio);
}
else {
  $grid_height  = int($grid_width / $src_ratio);
}
my $grid_ratio  = $grid_width / $grid_height;

my $cell_width  = int($grid_width  / $columns);
my $cell_height = int($grid_height / $rows   );

# Draw the horizontal lines

my($points);

for(my $i = 0; $i < $rows; $i++) {
  $composite->Annotate(
    text      => $row[$i],
    x         => $grid_x - $char_height,
    y         => $grid_y + $i * $cell_height + int($cell_height / 2),
    font      => 'Generic.ttf',
    fill      => 'black',
    pointsize => 14,
  );
  next if($i == 0);

  $points = sprintf("%d,%d %d,%d",
    $grid_x,
    $grid_y + $cell_height * $i,
    $grid_x + $grid_width,
    $grid_y + $cell_height * $i,
  );

  $composite->Draw(primitive => 'line', stroke => '#CCC', points => $points);

}

# Draw the vertical lines

for(my $i = 0; $i < $columns; $i++) {
  $composite->Annotate(
    text      => "" . $i + 1,
    x         => $grid_x + $i * $cell_width + int($cell_width / 2),
    y         => $grid_y - int($char_height / 4),
    font      => 'Generic.ttf',
    fill      => 'black',
    pointsize => 14,
  );
  next if($i == 0);

  $points = sprintf("%d,%d %d,%d",
    $grid_x + $cell_width * $i,
    $grid_y,
    $grid_x + $cell_width * $i,
    $grid_y + $grid_height,
  );

  $composite->Draw(primitive => 'line', stroke => '#CCC', points => $points);
}

# Draw the box

$points = sprintf("%d,%d %d,%d",
  $grid_x,
  $grid_y,
  $grid_x + $grid_width,
  $grid_y + $grid_height,
);

$composite->Draw(
  primitive => 'rectangle',
  fill      => 'none',
  stroke    => 'black',
  points    => $points,
);

# Write out the composite file

$err = $composite->Set(filename => 'composite.gif');
$err = $composite->Write('composite.gif');
#$err = $composite->Write('win:');

