square.pl 3.1 KB

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