21

I am trying to find all JPG images within a folder with subfolders that have either width or height below 300px.

This way I want to detect old thumbnails and delete them.

For sure I can find all images using find:

find . -iname "*.jpg" -type f | ...

But what follows after the pipe? Which package can I use to detect picture attributes?

Zanna
  • 69,223
  • 56
  • 216
  • 327
mcbetz
  • 3,009
  • 7
  • 28
  • 40

4 Answers4

23

You can use identify from imagemagick, and you can use the following command:

find . -iname "*.jpg" -type f -exec identify -format '%w %h %i' '{}' \; | awk '$1<300 || $2<300'

the use of -exec <command> '{}' \; makes sure that your filename can have spaces in them, alternatively you can use

find . -iname "*.jpg" -type f | xargs -I{} identify -format '%w %h %i' {} | awk '$1<300 || $2<300'

where the -I{} takes care of the same thing.

What I like about identify is that you can specify the output format; in this case '%w %h %i' which gives the width, height and full pathname of the image. Then the awk expression only keeps those lines for which the image is smaller than the desired size.

Example of the output:

64 64 ./thumbsup.jpg
100 150 ./photomin.jpg

Edit: If you want the filenames only (for piping to rm for instance), simply change $line in the awk statement to $3, then it will only print the third column.

Gerhard Burger
  • 9,359
  • 5
  • 41
  • 59
  • 3
    The awk part can be made shorter: `| awk '$1<300||$2<300'` or `| awk '$1<300||$2<300{print $3}'` (when only the 3rd column is needed). – alephreish Oct 06 '14 at 18:21
  • @har-wradim Thanks, nice suggestion! – Gerhard Burger Oct 29 '14 at 13:17
  • 12
    I had to add a newline (`'%w %h %i\n'`) to get it to work for me. – qwr Jul 24 '17 at 21:15
  • Sorry for write in a 6 years question, but this is the only result I find on google that partially asnwers my question, basically what I want is find images with or within specific dimensions and then copy them to another directory. I know that cp is used to copy, but I fail at integrate this command with cp. – GhostOrder Jan 01 '20 at 19:17
  • 1
    @GhostOrder follow the suggestion of @har-wradim to only print the 3rd column, then add another pipe with something like this `| xargs -I {} mv {} /destination/directory/` – Gerhard Burger Jan 02 '20 at 16:07
  • @Gerhard Burger Thanks for the help, I think my problem is that the command outputs the names joining them, is like this `1663 2495 ./0001.jpg2495 1663 ./0072.jpg1663`... and so on, so when I add `| xargs -I {} mv {} /destination/directory/` I get the error `mv: cannot stat './0001.jpg2495': No such file or directory`. How can I output the file names in a correct way? – GhostOrder Jan 02 '20 at 21:52
  • Use @qwr suggestion to add a new line :) – Gerhard Burger Jan 03 '20 at 23:16
  • @GerhardBurger i need to set if $1 greater than 1280 convert it to 1280 , that's possible ? – Mikel Tawfik Oct 28 '21 at 14:37
  • @MikelTawfik Sure, just use https://stackoverflow.com/questions/40007722/resize-with-imagemagick-with-a-maximal-width-height (it will leave the smaller files alone) – Gerhard Burger Oct 29 '21 at 15:13
2

This worked for me:

find . -iname "*.png" -type f -exec identify -format '%i %wx%h\n' '{}' \; | grep '75x75'

This is the output sample:

./2520161636481000.png 75x75
./2620160819191100.png 75x75
./2420181545550700.png 75x75
Zanna
  • 69,223
  • 56
  • 216
  • 327
osroflo
  • 21
  • 1
1

I think the accepted answer is very good, but I wanted to add another possible solution ...

Although I use ImageMagick tools most often now myself, netpbm is an old friend for processing images. You can see the size of any format of image with the command:

anytopnm file | pamfile

This will generate output that looks like:

stdin:  PPM raw, 1650 by 1275  maxval 255

To answer the question of "what follows after the pipe?", I use while read more often than I use xargs because it is more flexible. My netpbm answer to the question looks like this:

find -iname \*.jpg | while read img; do \
  anytopnm "$img" | pamfile | \
    perl -ane 'exit 1 if $F[3]<300 || $F[5]<300' || rm -v "$img"; \
done
NateT
  • 79
  • 4
0

The identify command from the imagemagick package does what you want:

$ identify abc.jpg
abc.jpg JPEG 1952x3264 1952x3264+0+0 8-bit DirectClass 1.111MB 0.000u 0:00.000

Again, you would need to then use grep to sort out the image size.

However, I suspect that unless you have a very wide range of image sizes, it would be easier just to use find to remove JPEG files below a given size:

find -iname '*.jpg' -size -10k -delete

(Worth running without -delete first to check it doesn't find things you want to keep - it won't prompt you before deletion otherwise).

chronitis
  • 12,197
  • 2
  • 43
  • 32