#!/usr/bin/perl # crop # ==== # # (C) 2003 by Till Kamppeter # Released under the terms of the GPL (see www.gnu.org). # # "crop" crops JPEG images to a user-specified width/height ratio without # JPEG recompression, so without quality loss. Also EXIF data is conserved. # # It uses the "jpegtran" utility which is part of libjpeg # (http://www.ijg.org/). "jpegtran" needs the patches in either # croppatch.tar.gz or droppatch.tar.gz from http://jpegclub.org/ # (statically linked binary of patched "jpegtran" in both tarballs). # Also "jhead" from http://www.sentex.net/~mwandel/jhead/ and # ImageMagick from http://www.imagemagick.org/ is needed. # # The program simplifies the process by calculating the correct parameters # for "jpegtran" from a user-supplied ratio and by processing multiple # images with one command line. # Check for command line options use Getopt::Std; getopts("r:h"); # Usage info if ($opt_h) { my $prog = $0; $prog =~ s!^.*?([^/]+)$!$1!; print STDERR "\n\"$prog\" crops JPEG images to a user-specified\n"; print STDERR "width/height ratio without JPEG recompression, so without\n"; print STDERR "quality loss.\n\n"; print STDERR "Usage: $prog [ -r ratio ] file1.jpg [ file2.jpg ... ]\n\n"; print STDERR " -r ratio: Width/height ratio or page size.\n"; print STDERR " Ratio: 3:2, 4x6, 8x10, 1:1.414, ...\n"; print STDERR " Page sizes: A1, A2, A3, A4, ...,\n"; print STDERR " Letter, Legal\n"; print STDERR " Photo (3:2), Screen (4:3)\n"; print STDERR " file1.jpg ...: Images to be cropped, more than one\n"; print STDERR " can be specified, must be JPEG\n\n"; } # Default is the ratio for standard 4x6inch/10x15cm photos my $ratiox = 3.0; my $ratioy = 2.0; # Did the user give a ratio via the "-r" option? if (my $ratio = $opt_r) { if ($ratio =~ /^\s*([\d\.]+)\s*[:x\/]\s*([\d\.]+)\s*$/i) { # Explicitly given ratio ("16:9", "8x10", ...) $ratiox = $1; $ratioy = $2; # None of the two values should be zero or negative if (($ratiox <= 0.0) || ($ratioy <= 0)) { die "Invalid ratio: $ratiox:$ratioy!\n"; } # $ratiox must always be greater than $ratioy if ($ratioy > $ratiox) { ($ratiox, $ratioy) = ($ratioy, $ratiox); } } elsif ($ratio =~ /^\s*A\d+\s*$/i) { # European "A" paper format $ratiox = sqrt(2.0); $ratioy = 1.0; } elsif ($ratio =~ /^\s*letter\s*$/i) { # US Letter paper format $ratiox = 11.0; $ratioy = 8.5; } elsif ($ratio =~ /^\s*legal\s*$/i) { # US Legal paper format $ratiox = 14.0; $ratioy = 8.5; } elsif ($ratio =~ /^\s*photo\s*$/i) { # Standard 4x6inch/10x15cm photo format $ratiox = 3.0; $ratioy = 2.0; } elsif ($ratio =~ /^\s*screen\s*$/i) { # The camera does 3:2, but you want to use the photo as desktop # wallpaper $ratiox = 4.0; $ratioy = 3.0; } } # Process all supplied files for my $file (@ARGV) { # Does the file exist and is readable and writable if ((! -r $file) or (! -w $file)) { print STDERR "Cannot process $file, skipping!\n"; next; } my $portrait = 0; # Portrait orientation? # Get dimensions of image file my $width = `identify -format %w $file 2>/dev/null` * 1.0; my $height = `identify -format %h $file 2>/dev/null` * 1.0; # Skip non-image files if (($width <= 0) or ($height <= 0)) { print STDERR "$file is not an image, skipping!\n"; next; } if ($width < $height) { # Portrait orientation, change dimensions $portrait = 1; ($width, $height) = ($height, $width); } my $ratio = $width/$height; # X/Y ratio of current image my $newratio = $ratiox/$ratioy; # Desired X/Y ratio my $r = $ratio/$newratio; next if ($r < 1.01) and ($r > 0.99); # Skip image with desired X/Y ratio if ($r > 1.0) { # We need to crop the short edges, so proceed as with a portrait- # oriented image, but with the reciprocal of the ratio $portrait = 1 - $portrait; ($width, $height) = ($height, $width); $r = 1.0 / $r; } # Calculate new dimensions, store as integer my $newwidth = $width; my $newheight = sprintf("%d", $height*$r); my $xoffset = 0; my $yoffset = sprintf("%d", $height*(1-$r)/2.0); if ($portrait) { # Portrait orientation, change back the dimensions ($width, $height) = ($height, $width); $newwidth = $newheight; $newheight = $height; $xoffset = $yoffset; $yoffset = 0; } # Do a loss-less JPEG cropping to the new dimensions system("jhead -cmd \"jpegtran -crop ${newwidth}x${newheight}+$xoffset+$yoffset &i > &o\" $file"); }