Skip to content

Instantly share code, notes, and snippets.

@jussikinnula
Last active November 19, 2015 08:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jussikinnula/508bbd57abbe69d47f8e to your computer and use it in GitHub Desktop.
Save jussikinnula/508bbd57abbe69d47f8e to your computer and use it in GitHub Desktop.
Equivalent to ImageMagick's "trim" with Perl's Imager
#!/usr/bin/env perl
use Imager;
use File::Path qw(make_path);
use File::Basename;
use Inline with => 'Imager';
use Inline C => <<'EOS' => WITH => 'Imager';
void trim(Imager::ImgRaw img, int fuzz, SV* res_top, SV* res_left, SV* res_right, SV* res_bottom) {
int top = 0;
int left = 0;
int right = img->xsize;
int bottom = img->ysize;
int x, y, ch;
i_color first, c;
// Get the "matching" color from first pixel
i_gpix(img, left, top, &first);
// Find top
for (y = top; y < img->ysize; ++y) {
int match = 0;
for (x = left; x < img->xsize; ++x) {
i_gpix(img, x, y, &c);
for (ch = 0; ch < img->channels; ++ch) {
if (c.channel[ch] < (first.channel[ch] - fuzz) || c.channel[ch] > (first.channel[ch] + fuzz)) {
match = 1;
break;
}
}
}
if (match) {
top = y;
break;
}
}
// Find bottom
for (y = bottom; y > top; --y) {
int match = 0;
for (x = left; x < img->xsize; ++x) {
i_gpix(img, x, y-1, &c);
for (ch = 0; ch < img->channels; ++ch) {
if (c.channel[ch] < (first.channel[ch] - fuzz) || c.channel[ch] > (first.channel[ch] + fuzz)) {
match = 1;
break;
}
}
}
if (match) {
bottom = y;
break;
}
}
// Find left
for (x = left; x < img->xsize; ++x) {
int match = 0;
for (y = top; y < bottom; ++y) {
i_gpix(img, x, y, &c);
for (ch = 0; ch < img->channels; ++ch) {
if (c.channel[ch] < (first.channel[ch] - fuzz) || c.channel[ch] > (first.channel[ch] + fuzz)) {
match = 1;
break;
}
}
}
if (match) {
left = x;
break;
}
}
// Find right
for (x = right; x > left; --x) {
int match = 0;
for (y = top; y < bottom; ++y) {
i_gpix(img, x-1, y, &c);
for (ch = 0; ch < img->channels; ++ch) {
if (c.channel[ch] < (first.channel[ch] - fuzz) || c.channel[ch] > (first.channel[ch] + fuzz)) {
match = 1;
break;
}
}
}
if (match) {
right = x;
break;
}
}
sv_setiv(res_top, top);
sv_setiv(res_bottom, bottom);
sv_setiv(res_left, left);
sv_setiv(res_right, right);
}
EOS
die "Usage: trim.pl [source_image] [source_image] [fuzziness]\n"
unless @ARGV and $ARGV[0] and $ARGV[1];
my ($source, $target, $fuzziness) = @ARGV;
$fuzziness = $fuzziness || 0;
my ($target_filename, $target_path) = fileparse($target);
my $target_filetype = (split(/\./, $target_filename))[1] || 'png';
$target_filetype = 'jpeg' if $target_filetype eq 'jpg' or $target_filetype eq 'jpe';
my $imager = Imager->new( file => $source )
or die "Cannot open $source -file: ", Imager->errstr();
# Trim background
my ($top, $left, $right, $bottom);
trim($imager, $fuzziness, $top, $left, $right, $bottom);
$imager = $imager->crop(
left => $left,
right => $right,
top => $top,
bottom => $bottom,
);
# Fit the original image to a square box
# First create directory for the file
make_path($target_path) if $target_path and $target_path ne './';
# Then store it
$imager->write( file => $target, type => $target_filetype )
or die "Cannot write $target -file: ", Imager->errstr();
print "Done.\n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment