img-autocrop-whitebg.pl 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 14 June 2015
  5. # https://github.com/trizen
  6. # Auto-crop a list of images that have a white background.
  7. use 5.010;
  8. use strict;
  9. use warnings;
  10. use GD qw();
  11. use File::Basename qw(basename);
  12. use File::Spec::Functions qw(catfile);
  13. # Set true color
  14. GD::Image->trueColor(1);
  15. # Autoflush mode
  16. local $| = 1;
  17. my $dir = 'Cropped images';
  18. sub check {
  19. my ($img, $width, $height) = @_;
  20. my $check = sub {
  21. foreach my $sub (@_) {
  22. $sub->() == 0 or return;
  23. }
  24. 1;
  25. };
  26. my $w_lt_h = $width < $height;
  27. my $min = $w_lt_h ? $width : $height;
  28. my %seen;
  29. # Spiral in to smaller gaps
  30. # -- this algorithm needs to be improved --
  31. for (my $i = int(sqrt($min)) ; $i >= 1 ; $i--) {
  32. foreach my $j (1 .. $min) {
  33. next if $j % $i;
  34. next if $seen{$j}++;
  35. if (
  36. not $check->(
  37. sub { $img->getPixel($j, 0) },
  38. sub { $img->getPixel(0, $j) },
  39. sub { $img->getPixel($j, $height) },
  40. sub { $img->getPixel($width, $j) },
  41. )
  42. ) {
  43. return;
  44. }
  45. }
  46. }
  47. if ($w_lt_h) {
  48. foreach my $y ($width + 1 .. $height) {
  49. if (not $check->(sub { $img->getPixel(0, $y) }, sub { $img->getPixel($width, $y) })) {
  50. return;
  51. }
  52. }
  53. }
  54. else {
  55. foreach my $x ($height + 1 .. $width) {
  56. if (not $check->(sub { $img->getPixel($x, 0) }, sub { $img->getPixel($x, $height) })) {
  57. return;
  58. }
  59. }
  60. }
  61. return 1;
  62. }
  63. sub autocrop {
  64. my @images = @_;
  65. foreach my $file (@images) {
  66. my $img = GD::Image->new($file);
  67. if (not defined $img) {
  68. warn "[!] Can't process image `$file': $!\n";
  69. next;
  70. }
  71. my ($width, $height) = $img->getBounds();
  72. $width -= 1;
  73. $height -= 1;
  74. print "Checking: $file";
  75. check($img, $width, $height) || do {
  76. print " - fail!\n";
  77. next;
  78. };
  79. print " - ok!\n";
  80. print "Cropping: $file";
  81. my $top;
  82. my $bottom;
  83. TB: foreach my $y (1 .. $height) {
  84. foreach my $x (1 .. $width) {
  85. if (not defined $top) {
  86. if ($img->getPixel($x, $y)) {
  87. $top = $y - 1;
  88. }
  89. }
  90. if (not defined $bottom) {
  91. if ($img->getPixel($x, $height - $y)) {
  92. $bottom = $height - $y + 1;
  93. }
  94. }
  95. if (defined $top and defined $bottom) {
  96. last TB;
  97. }
  98. }
  99. }
  100. my $left;
  101. my $right;
  102. LR: foreach my $x (1 .. $width) {
  103. foreach my $y (1 .. $height) {
  104. if (not defined $left) {
  105. if ($img->getPixel($x, $y)) {
  106. $left = $x - 1;
  107. }
  108. }
  109. if (not defined $right) {
  110. if ($img->getPixel($width - $x, $y)) {
  111. $right = $width - $x + 1;
  112. }
  113. }
  114. if (defined $left and defined $right) {
  115. last LR;
  116. }
  117. }
  118. }
  119. my $cropped = GD::Image->new($right - $left + 1, $bottom - $top + 1);
  120. $cropped->copyResized(
  121. $img,
  122. 0, # destX
  123. 0, # destY
  124. $left, # srcX
  125. $top, # srcY
  126. $right, # destW
  127. $bottom, # destH
  128. $right, # srcW
  129. $bottom, # srcH
  130. );
  131. my $name = catfile($dir, basename($file));
  132. open my $fh, '>:raw', $name or die "Can't create file `$name': $!";
  133. print $fh ($name =~ /\.png\z/i ? $cropped->png : $cropped->jpeg);
  134. close $fh;
  135. print " - ok!\n";
  136. }
  137. }
  138. @ARGV || die "usage: $0 [images]\n";
  139. if (not -d $dir) {
  140. mkdir($dir) || die "Can't mkdir `$dir': $!";
  141. }
  142. autocrop(@ARGV);