chiark / gitweb /
Fix completion checking in Killer Solo.
[sgt-puzzles.git] / icons / square.pl
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 = [];
20 open IDATA, "convert -depth 8 $infile rgb:- |";
21 push @$data, $rgb while (read IDATA,$rgb,3,0) == 3;
22 close IDATA;
23 # Check we have the right amount of data.
24 $xl = $w * $h;
25 $al = scalar @$data;
26 die "wrong amount of image data ($al, expected $xl) from $infile\n"
27   unless $al == $xl;
28
29 # Find the background colour, by looking around the entire border
30 # and finding the most popular pixel colour.
31 for ($i = 0; $i < $w; $i++) {
32     $pcount{$data->[$i]}++; # top row
33     $pcount{$data->[($h-1)*$w+$i]}++; # bottom row
34 }
35 for ($i = 1; $i < $h-1; $i++) {
36     $pcount{$data->[$i*$w]}++; # left column
37     $pcount{$data->[$i*$w+$w-1]}++; # right column
38 }
39 @plist = sort { $pcount{$b} <=> $pcount{$a} } keys %pcount;
40 $back = $plist[0];
41
42 # Crop rows and columns off the image to find the central rectangle
43 # of non-background stuff.
44 $ystart = 0;
45 $ystart++ while $ystart < $h and scalar(grep { $_ ne $back } map { $data->[$ystart*$w+$_] } 0 .. ($w-1)) == 0;
46 $yend = $h-1;
47 $yend-- while $yend >= $ystart and scalar(grep { $_ ne $back } map { $data->[$yend*$w+$_] } 0 .. ($w-1)) == 0;
48 $xstart = 0;
49 $xstart++ while $xstart < $w and scalar(grep { $_ ne $back } map { $data->[$_*$w+$xstart] } 0 .. ($h-1)) == 0;
50 $xend = $w-1;
51 $xend-- while $xend >= $xstart and scalar(grep { $_ ne $back } map { $data->[$_*$w+$xend] } 0 .. ($h-1)) == 0;
52
53 # Decide how much border we're going to put back on to make the
54 # image perfectly square.
55 $hexpand = ($yend-$ystart) - ($xend-$xstart);
56 if ($hexpand > 0) {
57     $left = int($hexpand / 2);
58     $xstart -= $left;
59     $xend += $hexpand - $left;
60 } elsif ($hexpand < 0) {
61     $vexpand = -$hexpand;
62     $top = int($vexpand / 2);
63     $ystart -= $top;
64     $yend += $vexpand - $top;
65 }
66 $ow = $xend - $xstart + 1;
67 $oh = $yend - $ystart + 1;
68 die "internal computation problem" if $ow != $oh; # should be square
69
70 # And decide how much _more_ border goes on to add the bit around
71 # the edge.
72 $realow = int($ow * ($osize / ($osize - 2*$oborder)));
73 $extra = $realow - $ow;
74 $left = int($extra / 2);
75 $xstart -= $left;
76 $xend += $extra - $left;
77 $top = int($extra / 2);
78 $ystart -= $top;
79 $yend += $extra - $top;
80 $ow = $xend - $xstart + 1;
81 $oh = $yend - $ystart + 1;
82 die "internal computation problem" if $ow != $oh; # should be square
83
84 # Now write out the resulting image, and resize it appropriately.
85 open IDATA, "| convert -size ${ow}x${oh} -depth 8 -resize ${osize}x${osize}! rgb:- $outfile";
86 for ($y = $ystart; $y <= $yend; $y++) {
87     for ($x = $xstart; $x <= $xend; $x++) {
88         if ($x >= 0 && $x < $w && $y >= 0 && $y < $h) {
89             print IDATA $data->[$y*$w+$x];
90         } else {
91             print IDATA $back;
92         }
93     }
94 }
95 close IDATA;