Code to construct Windows icon files for the puzzles, by munging the
[sgt/puzzles] / icons / square.pl
CommitLineData
afc306fc 1#!/usr/bin/perl
2
3# Read an input image, crop its border to a standard width, and
4# convert it into a square output image. Parameters are:
5#
6# - the required total image size
7# - the output border thickness
8# - the input image file name
9# - the output image file name.
10
11($osize, $oborder, $infile, $outfile) = @ARGV;
12
13# Determine the input image's size.
14$ident = `identify -format "%w %h" $infile`;
15$ident =~ /(\d+) (\d+)/ or die "unable to get size for $infile\n";
16($w, $h) = ($1, $2);
17
18# Read the input image data.
19$data = [];
fbd2dc51 20open IDATA, "convert -depth 8 $infile rgb:- |";
afc306fc 21push @$data, $rgb while (read IDATA,$rgb,3,0) == 3;
22close IDATA;
23# Check we have the right amount of data.
24$xl = $w * $h;
25$al = scalar @$data;
fbd2dc51 26die "wrong amount of image data ($al, expected $xl) from $infile\n"
afc306fc 27 unless $al == $xl;
28
29# Find the background colour. We assume the image already has a
30# border, so this is just the pixel colour of the top left corner.
31$back = $data->[0];
32
33# Crop rows and columns off the image to find the central rectangle
34# of non-background stuff.
35$ystart = 0;
36$ystart++ while $ystart < $h and scalar(grep { $_ ne $back } map { $data->[$ystart*$w+$_] } 0 .. ($w-1)) == 0;
37$yend = $h-1;
38$yend-- while $yend >= $ystart and scalar(grep { $_ ne $back } map { $data->[$yend*$w+$_] } 0 .. ($w-1)) == 0;
39$xstart = 0;
40$xstart++ while $xstart < $w and scalar(grep { $_ ne $back } map { $data->[$_*$w+$xstart] } 0 .. ($h-1)) == 0;
41$xend = $w-1;
42$xend-- while $xend >= $xstart and scalar(grep { $_ ne $back } map { $data->[$_*$w+$xend] } 0 .. ($h-1)) == 0;
43
44# Decide how much border we're going to put back on to make the
45# image perfectly square.
46$hexpand = ($yend-$ystart) - ($xend-$xstart);
47if ($hexpand > 0) {
48 $left = int($hexpand / 2);
49 $xstart -= $left;
50 $xend += $hexpand - $left;
51} elsif ($hexpand < 0) {
52 $vexpand = -$hexpand;
53 $top = int($vexpand / 2);
54 $ystart -= $top;
55 $yend += $vexpand - $top;
56}
57$ow = $xend - $xstart + 1;
58$oh = $yend - $ystart + 1;
59die "internal computation problem" if $ow != $oh; # should be square
60
61# And decide how much _more_ border goes on to add the bit around
62# the edge.
63$realow = int($ow * ($osize / ($osize - 2*$oborder)));
64$extra = $realow - $ow;
65$left = int($extra / 2);
66$xstart -= $left;
67$xend += $extra - $left;
68$top = int($extra / 2);
69$ystart -= $top;
70$yend += $extra - $top;
71$ow = $xend - $xstart + 1;
72$oh = $yend - $ystart + 1;
73die "internal computation problem" if $ow != $oh; # should be square
74
75# Now write out the resulting image, and resize it appropriately.
76open IDATA, "| convert -size ${ow}x${oh} -depth 8 -resize ${osize}x${osize}! rgb:- $outfile";
77for ($y = $ystart; $y <= $yend; $y++) {
78 for ($x = $xstart; $x <= $xend; $x++) {
79 if ($x >= 0 && $x < $w && $y >= 0 && $y < $h) {
80 print IDATA $data->[$y*$w+$x];
81 } else {
82 print IDATA $back;
83 }
84 }
85}
86close IDATA;