Search code examples
imagemagick

Avoid double optimization of image


We have a storage of images where some images are optimized and some are not.

I'm working on 'script' that will go via every image in the storage and run optimize process.

I'm wondering:

  1. Is there a way to check if image has been optimized?
  2. Will I lose quality if image has been optimized with -quality 85% few times?

I have tried to run -quality 85% few times on same image and I could not see any lose in quality (after 3-th run the image's size was not changed). However I did not find a proof on official documentation.

Thanks!


Solution

  • You can check if the quality setting is already 75 before optimising:

    identify -format %Q fred.jpg
    92
    

    Then optimise and check again:

    convert fred.jpg -quality 75 optimised.jpg
    identify -format %Q optimised.jpg
    75
    

    If you are using bash, this is easy:

    q=$(identify -format %Q fred.jpg)
    [ $q -ne 75 ] && mogrify -quality 75 fred.jpg
    

    Another way to mark images as optimised might be to set a comment in the file to the word "optimised", like this:

    # Set comment
    mogrify -set comment "optimised" fred.jpg
    
    # Get comment
    identify -format %c fred.jpg 
    optimised
    

    So, you would test if an image comment contains the word "optimised", and if not, optimise the image and change the comment to show as much:

    [[ $(identify -format %c fred.jpg) != *optimised* ]] && { echo Optimising fred.jpg; mogrify -set comment "optimised" -quality 75 fred.jpg; }
    

    Another possibility might be to use Extended File Attributes to tag files (with setfattr) as you reduce their quality and then use getfattr to check their quality rather than doing them again.


    If you had hundreds or thousands of images to process, I would suggest GNU Parallel. Please try the example below on a small copy of a few files in a directory:

    parallel '[[ $(identify -format "%c" {}) != *optimised* ]] && { echo Optimising {}; mogrify -set comment "optimised" -quality 75 {}; }' ::: *jpg
    

    You will find it will process them all in parallel the first pass, and then do nothing on the second pass.

    If you have too many images, and get "ERROR: Too many args", you can pass the filenames in on stdin like this, instead of globbing after the ::::

    find /some/where -iname \*.jpg -print0 | parallel -0 ...