# Crop an image to a square

In this challenge, you will take an input image and crop it to make a square, leaving only the central part of the input image.

The answers must work with landscape, portrait, or square input images. The width of the output image should be equal to the shortest side of the input image e.g. the result of a 200x300 image should be a 200x200 image. An equal amount must be cropped from both ends of the input image e.g. for a 200x300 input image, 50 pixels should be cropped from each end of the image, leaving only the central part of the image. Where its not possible to crop an equal amount from both sides e.g. a 200x301 image, the extra 1 pixel may be cropped from either end of the image. For a square input image, the output should be identical to the input.

Input:

The input file should be read from the hard disk of the machine running the program. You may choose which of bmp, jpeg, png or pnm to support as the input image format.

Output

The output file should be written to the hard disk of the machine running the program. The format of the output image should be bmp, jpeg, png or pnm.

Win Criteria

This is code golf. Shortest code wins.

Notes:

1. The input/output file paths do not count towards the program size.
2. The standard libraries of your programming language may be used. Other libraries are disallowed.
3. Standard loopholes apply.

Example:

Input Image:

Expected Output:

Images by kirill777 - licenced CC-BY 3.0

• This seems to have a significant bias toward languages whose standard library contains BMP functions. For example, php.net/manual/en/function.imagecreatefromwbmp.php Aug 5 '14 at 23:08
• Thats true but allowing external libraries would bring its own set of potential issues and introduce too much scope for loopholes Aug 5 '14 at 23:39
• Can we at least choose the image format?
– Doorknob
Aug 5 '14 at 23:52
• @doorknob i updated the question to allow jpeg and png. If anyone wants to use another format, please request it in the comments. Aug 6 '14 at 0:10
• PNM? That allows languages with no standard library support for images to participate. Aug 6 '14 at 10:08

# Parsing the raw bytestream: Haskell (319 = 332 - 13)

Without any imports at all, this program crops P1 PBM images.

g _[]=[]
g z x=(\(a,b)->a:g z b).splitAt z$x q=map f=filter main=do c<-readFile"in.pbm";let(r:p)=tail.f((/='#').head).lines$c;(w:h:_)=(q read).words$r;m=min w h;t s=take m.drop((s-m)div2);k d=[[m,m]]++(q(t w)(t h d))in writeFile"out.pbm".("P1\n"++).unlines.q(unwords.(q show)).k.(q((q read).g 1)).take h.g w.f(elem"01").concat$p


## Special case: helpful formatting (214 = 227 - 13)

My first attempt at PBM (P1) was based on the example at Wikipedia and assumed spaces separated the pixels, and lines in the text correlated with lines in the image. Under those conditions, this shorter version works fine.

main=do c<-readFile"in.pbm";writeFile"out.pbm".("P1\n"++).unlines.q(unwords.(q show)).k.q((q read).words).tail.filter((/='#').head).lines$c k((w:h:_):d)=let m=min w h;t s=take m.drop((s-m)div2)in[[m,m]]++(q(t w)(t h d)) q=map  Bonus feature: strips out comments! Both of the above work in essentially the same manner as the original below, but with a simpler header, lower bit depth, and no padding, although the topmost program works harder to allow for a range of formatting options. # Also available in a wide range of colours: Haskell (545 = 558 - 13) No pre-existing image-handling functions were harmed in the making of this program. Uncompressed 24-bit RGB bitmaps have a fairly straight-forward header system but are complicated by the mod-4 padding for each row's byte array. This code grabs the bitmap offset, width, and height from the input header, calculates the row padding, and extracts the bitmap data into a list of lists (rows of columns, bottom-left corner first). Cropping is as simple as dropping half the excess and then taking the desired length from each list. The new file size is calculated as 3*(padded width)*height + 54 bytes (for the minimal required headers). The new header is constructed and the cropped image data appended. It's all mapped to characters and written back out to disk. Input: in.bmp (6 characters removed from total) Output: out.bmp (7 characters removed from total) I think there's still some redundancy still in there, but my brain hurts to look at it this way. import System.IO import Data.Char import Data.List.Split main=do k"in.bmp"ReadMode(\h->do i h u;c<-hGetContents h;let d=l(ord)c;w=s 18d;h=s 22d;p=o w;m=min w h;q=o m;j a b=y a(r b m)in k"out.bmp"WriteMode(\g->do i g u;hPutStr g$"BM"++l chr((z e[m*(3*m+q)+54,0,54,40,m,m,1572865,0,0,1,1,0,0])++((z((++(f q$cycle[0])).y(3*m)(3*r w m)).j m h$chunksOf(3*w+p)$n(s 10d)d))))) i=hSetBinaryMode k=withFile z=concatMap l=map v=div f=take n=drop u=True y t d=f t.n d s d=sum.zipWith(*)(l(256^)[0..3]).y 4d o=(mod4) r a b=v(a-b)2 e x=l((mod256).(xv).(256^))[0..3]  For comparison, an ungolfed version is over 8 times as long, at 4582 (4595 - 13) bytes: import System.IO import Data.Char import Data.List.Split main = readImage cropImageToSquare cropImageToSquare fileHandle = do hSetBinaryMode fileHandle True fileContents <- hGetContents fileHandle let inImageData = asBytes fileContents inImageBitmapOffset = getIntFromWordAt 10 inImageData inImageWidth = getIntFromWordAt 18 inImageData inImageHeight = getIntFromWordAt 22 inImageData inImageBitmapData = drop inImageBitmapOffset inImageData inImageBitmap = chunksOf (paddedBytesForWidth inImageWidth) inImageBitmapData outImageSideLength = min inImageWidth inImageHeight outFileHeader = fileHeader outImageSideLength outImageSideLength outImageHeader = imageHeader outImageSideLength outImageSideLength outHeaders = outFileHeader ++ outImageHeader outImageBitmap = crop outImageSideLength outImageSideLength inImageWidth inImageBitmap in writeImage "out.bmp" outHeaders outImageBitmap --- Read Image --------------------------------------------------------- readImage = withFile "in.bmp" ReadMode --------------------------------------------------------- Read Image --- --- Write Image -------------------------------------------------------- writeImage filename header imageBitmap = do withFile filename WriteMode write' where write' fileHandle = do hSetBinaryMode fileHandle True hPutStr fileHandle . ("BM"++) . map chr$ (concatMap wordFromInt header)
++ (concat imageBitmap)

-------------------------------------------------------- Write Image ---

--- Character-Integer Conversion ---------------------------------------

asBytes = map ord

getWordAt offset = take 4 . drop offset

getIntFromWordAt offset = intFromWord . getWordAt offset

intFromWord     = sum . zipWith (*) (map (256^) [0..3])

wordFromInt int = map((mod 256) . (int div) . (256^)) [0..3]

--------------------------------------- Character-Integer Conversion ---

fileHeader width height = [ fileSize
, reserved
, bitmapOffset
]
where
fileSize     = imageFileSize width height
reserved     = 0
bitmapOffset = 54

imageFileSize width height = 54 + height * (paddedBytesForWidth width)
rowPadding = (mod 4)

, width
, height
, planesAndBits
, compression
, bitmapSize
, horizontalImageResolution
, verticalImageResolution
, paletteSize
, coloursUsed
]
where
planesAndBits    = int32FromInt16s colourPlanes bitDepth
colourPlanes     = 1
bitDepth         = 24
compression      = 0
bitmapSize       = 0
horizontalImageResolution = pixelsPerMetreFromDPI 72
verticalImageResolution   = pixelsPerMetreFromDPI 72
paletteSize      = 0
coloursUsed      = 0

pixelsPerMetreFromDPI = round . (* (100/2.54))

int32FromInt16s lowBytes highBytes = lowBytes + shift 2 highBytes
shift bytesUp number  = (256 ^ bytesUp) * number

--- Crop Image ---------------------------------------------------------

crop toHeight toWidth fromWidth = cropWidth toWidth fromWidth
. cropHeight toHeight

cropHeight toHeight image = take toHeight
. drop ( halfExtra (length image) toHeight)
$image cropWidth toWidth fromWidth image = map ( padRow toWidth . take (3 * toWidth) . drop (3 * (halfExtra fromWidth toWidth)) )$ image

$xs ++ (repeat 0) halfExtra fromLength toLength = (fromLength - toLength) div 2 --------------------------------------------------------- Crop Image ---  • Very nice answer. I'm having a little trouble getting it to work with my test images. see dl.dropboxusercontent.com/u/141246873/crop/bg1ascii.pbm and dl.dropboxusercontent.com/u/141246873/crop/bg1raw.pbm These images are pbm versions of the example image in the question. They were generated using GIMP. One is ascii and the other is raw. Please could you try it with either one of the files. Thanks. Aug 6 '14 at 22:00 • On the first version, some characters can be saved by shortcutting map to an infix function (like (#)=map) instead of q. Maybe on the second version too, i haven't checked. Aug 7 '14 at 8:41 • P4 PBMs are out, sorry. As for the P1 image, I followed the Wikipedia example too closely and assumed spaces between pixels and matching line lengths. The new (longer) program I just added handles bg1ascii.pbm, though, and still manages it without importing functionality. Aug 7 '14 at 11:38 • Tested and its working well with the GIMP generated images Aug 7 '14 at 18:22 ## Mathematica 52 Spaces not needed: ImageCrop[#, {#, #} &@Min@ImageDimensions@#] &@Import@"c:\\test.png"  • Sorry this is one of the standard loopholes: meta.codegolf.stackexchange.com/a/1078/21713 Aug 8 '14 at 21:23 • @Ryan Sorry, but not this time. The OP (you) wrote "The standard libraries of your programming language may be used. Other libraries are disallowed.".I'm using only the standard Mathematica statements - NO LIBRARIES AT ALL Aug 8 '14 at 21:36 # Rebol, 165 92 (105 - 13) i: load %in.bmp s: i/size m: min s/1 s/2 c: to-pair reduce[m m]save %out.bmp copy/part skip i s - c / 2 c  At its simplest if you have a image file (in.bmp) of 300x200 then it can be cropped and saved to file (out.bmp) like so: save %out.bmp copy/part skip load %in.bmp 50x0 200x200  Rebol comes with a spatial coordinates datatype called Pair! Here are some examples of this datatype (using Rebol console): >> type? 300x200 == pair! >> first 300x200 == 300.0 >> second 300x200 == 200.0 >> 300x200 - 200x200 == 100x0 >> 300x200 - 200x200 / 2 == 50x0  The last example shows how the skip coordinates were worked out for balanced cropping. NB. This solution was tested using latest version of Rebol 3 (see http://rebolsource.net/) on OS X. BMP is currently supported on all platforms. PNG, Jpeg & other formats are only partially implemented (across platforms) at this time. # C# - 250271265 229 (incl. 26 for file names) Forgot about the import for it to work. using System.Drawing; class P{static void Main(string[] a){var b=new Bitmap(@"C:\Dev\q.jpg",true);int h=b.Height,w=b.Width,s=h<w?h:w,d=(h-w)/2;b.Clone(new Rectangle(d>0?0:d*-1,d>0?d:0,s,s),b.PixelFormat).Save(@"C:\Dev\q2.jpg");}}  De-golfed (or what you call it). using System.Drawing; class Program { static void Main(string[] a) { var b = new Bitmap(@"C:\Dev\q.jpg",true); int h=b.Heightw=b.Width,s=h<w?h:w,d=(h-w)/2; b.Clone(new Rectangle(d>0?0:d*-1,d>0?d:0,s,s),b.PixelFormat).Save(@"C:\Dev\q2.jpg"); } }  Thanks (again) to w0lf for pointing out different declaration style. • this can be reduced significantly by erasing extra whitespace and using the int x=..., y=... declaration style: pastie.org/9454985 Aug 8 '14 at 6:34 • also, you can drop the spaces around equal signs and most line breaks. See the link in my previous comment. It's 232 chars. Aug 8 '14 at 8:32 • Thanks! I guess it is better to actually look at the link :) Aug 8 '14 at 8:44 • Yes. Well, at both links because I just realized thsi can be shortened even more. :) Aug 8 '14 at 9:14 • Well, according to the rules the image-reference don't count, but yeah, nice! Aug 8 '14 at 9:17 # Java, 373348342336 322 import java.awt.image.*;import java.io.*;import javax.imageio.*;class M{public static void main(String[]a)throws Exception{BufferedImage i=ImageIO.read(new File(a[0]));int[]d={i.getWidth(),i.getHeight()},o={0,0};int s=d[0]>d[1]?1:0;o[1-s]=(d[1-s]-d[s])/2;ImageIO.write(i.getSubimage(o[0],o[1],d[s],d[s]),"bmp",new File("out.bmp"));}}  Ungolfed: import java.awt.image.*; import java.io.*; import javax.imageio.*; class M{ public static void main(String[] args) throws Exception{ // read file as argument, instead of args[0] the path to the file could hardcoded. // Since the path to the input file don't count towards the character count, I'm not counting args[0] BufferedImage i = ImageIO.read(new File(args[0])); int[] dimension = { i.getWidth(), i.getHeight() }, origin = { 0, 0 }; int smaller = dimension[0] > dimension[1] ? 1 : 0; // 1-smaller is the index of the bigger dimension origin[1-smaller] = (dimension[1-smaller] - dimension[smaller]) / 2; // again, path to output file don't count ImageIO.write(i.getSubimage(origin[0], origin[1], dimension[smaller], dimension[smaller]), "bmp", new File("out.bmp")); } }  Usage: java M image.type Should be able to read jpg, png, bmp, wbmp and gif. Writes a bmp called "o". Who said you couldn't use Java for golf? Edit: Just realised that file paths don't count towards the character count. • You can use * for imports.. Like import java.io.* etc ;) Aug 6 '14 at 17:50 • I'm so used to eclipse handling the imports that I didn't even think of that. There was other stuff that could be removed, too. E: Oops, forgot an import. Aug 6 '14 at 18:02 • You can cut 9 by removing public  from the class and the two spaces in String[] a) throws. You should add a golfed (no whitespace) version so it's easier for others to count/verify, though. Aug 6 '14 at 18:55 • @Geobits done. Also apparently I counted too many characters. Should be fixed now. Aug 6 '14 at 19:29 • Works nicely for portrait/landscape images but doesn't seem to produce any output for square images? Aug 6 '14 at 20:35 # Bash, 115 with ImageMagic, hard to say if you can count it as a standard lib :) #!/bin/bash convert$1 -set option:size '%[fx:min(h,w)]x%[fx:min(h,w)]' xc:red +swap -gravity center -composite _$1  • I'm not counting it as a standard lib sorry :) Aug 6 '14 at 20:21 # Clojure, 320 (333 - 13 for filenames) Deciding to sidestep types, this P1 (ASCII) PBM cropper is written in Clojure. With function names like interpose, read-string, and clojure.string/replace, it's not exactly golf friendly, and I'm not sufficiently experienced to know if I can compile without a namespace declaration. (Leiningen puts it in automatically, and Leiningen is nice to me, so I'm going to leave it there, though I did eject .core.) On the plus side, however, file access and string concatenation are short. (ns a(:gen-class))(defn -main[](let[[[_ r p]](re-seq #"(^\s*\d+\s+\d+)([\s\S]*$)"(clojure.string/replace(slurp"in.pbm")#"(P1)|(#.*\n)"""))[w
str"P1\n"c" "c"\n"(flatten(interpose"\n"(take
c(partition c w(drop(+(*(quot(- h c)2)w)(quot(- w c)2))(re-seq #"\S"p))))))))))


The function at the heart of the program is ungolfed below.

(defn crop-pbm [in out]
(let [         filestream (slurp in)
image-data (clojure.string/replace (str filestream "\n") #"(P1)|(#.*\n)" "")
[[_ resolution pixels]] (re-seq #"(^\s*\d+\s+\d+)([\s\S]*$)" image-data) pixels (re-seq #"\S" pixels) [width height] (map read-string (re-seq #"\d+" resolution)) crop (min width height) drop-width (- width crop) drop-height (- height crop) initial-drop-width (quot drop-width 2) initial-drop-height (quot drop-height 2) initial-drop (+ (* initial-drop-height width) initial-drop-width) cropped-pixels (take crop (partition crop width (drop initial-drop pixels))) cropped-image (apply str "P1\n" crop " " crop "\n" (flatten (interpose "\n" cropped-pixels)))] (spit out cropped-image)))  Rather than constructing a two-dimensional array to represent the image, this program calculates the number of pixels to the new top-left corner and drops them, then jumps original-width pixels at a time, taking cropped-side-length pixels from as many steps. The regular expression function re-seq does much of the heavy lifting, stripping out whitespace and forming arrays simultaneously, which leads me to suspect that Perl could follow this approach and yield a shorter program. # Perl, 276 287 (289 300 - 13) ## Regex to the Rescue! Who needs dedicated image functions when you have regular expressions? (And 1-bit images to crop.) local$/;open I,"in.pbm";$_=<I>;s/(P1)|(#.*\n)//g;/^\s*(\d+)\s+(\d+)([\s\S]*)$/;($w,$h,$_)=($1,$2,$3);$c=$w<$h?$w:$h;s/\D//g;$d=$w-$c;while($z++<$w*int(($h-$c)/2)+int($d/2)){s/^\d//};while($i++<$c){/^(\d{$c})(\d{$d})(.*)/;$p.=$1."\n";$_=$3."0"x$w}open O,'>',"out.pbm";print O"P1\n$c$c\n$p"  That's the golfed version of: use strict; use warnings; # Read in the image file local$/ = undef;

open IMAGEIN, '<', "in.pbm" or die "Can't read 'in.pbm': $!"; my$image_data = <IMAGEIN>;
close IMAGEIN;

$_ =$image_data;
s/(P1)|(#.*\n)//g;

# Divide into width, height, and pixels
/^\s*(\d+)\s+(\d+)([\s\S]*)$/; (my$width, my $height,$_) = ($1,$2, $3); # Remove anything that isn't a number from the pixel data s/\D//g; my$pixels = $_; # Determine the new dimensions my$crop = $width <$height ? $width :$height;

# Calculate total to remove along each axis
my $drop_width =$width  - $crop; my$drop_height = $height -$crop;

# Calculate how much to remove from the first side along each axis
my $initial_drop_width = int($drop_width  / 2);
my $initial_drop_height = int($drop_height / 2);

# Calculate total pixels to the new top-left corner
my $initial_drop =$width * $initial_drop_height +$initial_drop_width;

# Remove the pixels preceding the corner
$_ =$pixels;
while (32760 < $initial_drop) # Stay under regex limit { s/^\d{32760}//;$initial_drop -= 32760;
}
s/^\d{$initial_drop}//; # Take *crop* rows of *crop* pixels$pixels = "";
for (my $i=0;$i<$crop;$i++)
{
/^(\d{$crop})(\d{$drop_width})(.*)/;
$pixels .=$1 . "\n";
$_ =$3 . "0"x$width; # Add some 0s to ensure final match } # Construct the new, cropped image my$cropped_image = "P1\n$crop$crop\n$pixels"; # Write out the image file open IMAGEOUT, '>', "out.pbm" or die "Can't write 'out.pbm':$!";
print IMAGEOUT \$cropped_image;
close IMAGEOUT;


There's a limit to the length of a string the substitution functions will handle, which necessitates a bothersome while loop for taller images. Even so, finally under 300!

# C#, 420

If the image is portrait it gets rotated while cropping and then cropped image is rotated to correct orientation.

Edit: now crop centre of the image. Run in terminal as crop.exe a.jpg

class P
{
static void Main(string[] a)
{
if (a.Length > 0)
{
Bitmap b = (Bitmap)Image.FromFile(a[0]);
int w = b.Width;
int h = b.Height;
int d = Math.Abs(w - h) / 2;
if (h > w) { b.RotateFlip(RotateFlipType.Rotate270FlipNone); }
Bitmap c = new Bitmap(h, h);
for (int x = d; x < (h+d); x++)
{
for (int y = 0; y < h; y++)
{
c.SetPixel(x-d, y, b.GetPixel(x, y));
}
}
if (h > w) { c.RotateFlip(RotateFlipType.Rotate90FlipNone); }
c.Save("Q.jpg");
}
}
}

• Unfortunately this throws an exception on an image with portrait orientation. It also outputs the left side of the input image and not the central part. To see what I mean, try it with the example image in the question and compare your result. Aug 6 '14 at 19:05

# C++/Qt 146

This might technically break rule #2 as Qt is not part of standard C++.

The first argument will be the input filename and the second will be the output filename.

#include<QtGui>
main(int c,char**v){QApplication a(c,v);QPixmap p(v[1]);int w=p.width(),h=p.height(),m=qMin(w,h);p.copy(w-m,h-m,m,m).save(v[2]);}

• This answer is not valid due to the use of a non standard library, but thanks for taking part :) Aug 6 '14 at 19:25

# Io, 103 bytes (excluding file path)

i := Image open("img.png");e := (i width) min(i height);i crop(((i width)-e)/2,((i height)-e)/2,e,e) save("crop.png")


You can use Io for CG!

• This can be heavily 'golfed' even further Aug 27 '15 at 6:01

# Matlab, 116 (130 with file names)

Pretty straightforward.

I=imread('a.jpg');[m,n]=size(I);z=min(m,n);c=m<n;r=[1,ceil((m-z)/2)]*~c+c*[ceil((n-z)/2),1];imwrite(imcrop(I,[r,z-1,z-1]),'z.jpg')


# APL (dzaima/APL), 66 bytes

i←P5.img p
P5.size←2⍴a←⌊/s←i.sz
P5.draw←{i P5.G.img⍨.5×a-s⋄i.save}


Try it online!