1

I need to crop a number of images in jpeg format by 20 pixels on the right side losslessly on Linux.

I checked jpegtran, but it needs the file size in pixels before cropping, and I don't know how to build a batch file with that.

How can I losslessly crop 20 pixels from the right side of images programmatically?

Ian Campbell
  • 23,484
  • 14
  • 36
  • 57

2 Answers2

2

My shell scripting is a little rusty so please make a backup of your images before trying this script.

#!/bin/bash
FILES=/path/to/*.jpg

for f in $FILES
do
    identify $f | awk '{ split($3, f, "x"); f[1] -= 20; cl = sprintf("jpegtran -crop %dx%d+0+0 %s > new_%s", f[1], f[2], $1, $1); system(cl); }'
done

Points to note:

  • Adjust the path to the correct value
  • Do you need *.jpeg?
  • identify is an ImageMagick command
  • awk will grab the pixel dimensions from identify to use as a parameter (with the width reduced by 20px) for jpegtran to crop the image
  • The new image is saved as new_[old_name].jpg
  • jpegtran might adjust the cropping region so that it can perform losslessly. Check that the resulting images are the correct size and not slightly larger.
acfrancis
  • 3,569
  • 25
  • 21
  • identify prints out the image dimensions which is what you need (adjusted) as a parameter for jpegtran – acfrancis Nov 08 '13 at 00:40
  • Yeah your explanation gave me the idea that something else was changing the image size *before* passing it to jpegtran, but reading the commands clarified that. – Havenard Nov 08 '13 at 00:40
  • Coincidently this week I came across a situation where I was searching for backgrounds to a new prototype website, I found one that was perfect if I flipped it upside down but had the frustration of seeing the file multiply in size. This program did the trick and even reduced the file size, pretty neat thing. – Havenard Nov 08 '13 at 00:50
2

Very similar to the accepted answer, the following would also work with file names containing spaces. And it is arguably simpler, using identify's built-in -format option instead of parsing the output with awk.

#!/bin/bash

X=0; Y=0   # offset from top left corner

for f in /path/to/*.jpg; do
    read -r W H < <(identify -format '%w %h' "$f") # get width and height
    (( W -= 20 ))                                  # substract 20 from width
    out="${f%%.jpg}-crop-20.jpg"                   # add "-crop-20" to filename
    jpegtran -crop ${W}x$H+$X+$Y "$f" > "$out"     # crop
done
mivk
  • 13,452
  • 5
  • 76
  • 69