Search code examples
makefileimagemagick-convert

convert images to jpg in a makefile which have various extensions


I have image files in a folder which may have different ways of spelling the extension (tiff, tif, TIF, gif, GIF etc.).

I want all images being converted to jpg (via magick mogrify). The un-converted image files should be deleted afterwards.

Everything needs to be done with a makefile.

My attempt so far:

RASTERFORMATS = tiff TIFF tif Tif TIf png PNG gif Gif
IMGPATH  = workfiles/inserts/figures

figures2jpg: cleanfigures
    cd $(IMGPATH) && \
    for format in {$(RASTERFORMATS)} ;\
    do \
    magick mogrify -background white -flatten *.$$format ; \
    magick mogrify -quiet -colorspace CMYK  -format jpg  *.$$format ; \
    magick mogrify -quiet -colorspace CMYK -density 1200  -format jpg *.$$format ; \
    done
    rm $(IMGPATH)/*.{$(RASTERFORMATS)}

Solution

  • I would rather go with a separate rule for every file that needs to be converted as this helps in finding out whether there was an error or not and act accordingly. When doing everything in a loop like above a) any error is missed (and the source file gets deleted even when conversion failed) and b) it always regenerates all files no matter if it was needed or not.

    My approach would be to get all the files with interesting extensions, generate target names and use a static pattern rule for each target file. I would also generate a warning if there are two or more input files that would result in the same target file as it was not clearly stated what should be done in this situation.

    For example:

    $ cat Makefile
    RASTERFORMATS := [Pp][Nn][Gg] [GgTt][Ii][Ff]
    IMGPATH := images
    
    IMAGES_TO_CONVERT := $(foreach format,$(RASTERFORMATS),$(wildcard $(IMGPATH)/*.$(format)))
    $(info Images to convert: $(IMAGES_TO_CONVERT))
    
    IMAGES := $(sort $(addsuffix .jpg,$(basename $(IMAGES_TO_CONVERT))))
    $(info Target images: $(IMAGES))
    
    percent := %
    
    .SECONDEXPANSION:
    .DELETE_ON_ERROR:
    
    $(IMAGES): %.jpg: $$(filter $$*$$(percent), $(IMAGES_TO_CONVERT))
            $(if $(word 2,$^),$(warning Multiple sources for $@, generating from $<))
            @echo "$< -> $@"
            gm mogrify -background white -colorspace CMYK -density 1200 -format jpg $<
            echo rm -f $<     # Drop echo if really want to remove input file
    
    .PHONY: figures2jpg
    figures2jpg: $(IMAGES)
    

    Given the following:

    $ ls images/
    image1.png  image2.PNG  image2.png  image3.gif
    

    Sample output is:

    $ make figures2jpg
    Images to convert: images/image2.png images/image2.PNG images/image1.png images/image3.gif
    Target images: images/image1.jpg images/image2.jpg images/image3.jpg
    images/image1.png -> images/image1.jpg
    gm mogrify -background white -colorspace CMYK -density 1200 -format jpg images/image1.png
    echo rm -f images/image1.png
    rm -f images/image1.png
    Makefile:16: Multiple sources for images/image2.jpg, generating from images/image2.png
    images/image2.png -> images/image2.jpg
    gm mogrify -background white -colorspace CMYK -density 1200 -format jpg images/image2.png
    gm mogrify: Improper image header (images/image2.png).
    Makefile:16: recipe for target 'images/image2.jpg' failed
    make: *** [images/image2.jpg] Error 1
    

    Note the warning for image2.jpg. It also demonstrates that an error will prevent from deleting input file. Another invocation will retry, but image1.jpg will not be generated again since it's already up to date.

    $ make figures2jpg
    Images to convert: images/image2.png images/image2.PNG images/image1.png images/image3.gif
    Target images: images/image1.jpg images/image2.jpg images/image3.jpg
    Makefile:16: Multiple sources for images/image2.jpg, generating from images/image2.png
    images/image2.png -> images/image2.jpg
    gm mogrify -background white -colorspace CMYK -density 1200 -format jpg images/image2.png
    gm mogrify: Improper image header (images/image2.png).
    Makefile:16: recipe for target 'images/image2.jpg' failed
    make: *** [images/image2.jpg] Error 1