convert images to jpg in a makefile which have various extensions - makefile

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)}

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

Related

How do I rename images when using mogrify with Image Magick?

I am trying to automate the converting images to specified tif formats. I have it converting just fine, but am also needing to add "_GS" at the end of the file name and before the extension to each file converted. Below is what I have but have had no luck finding a solution to add "_GS" to the file name. Thanks in advance for any help.
for f in "$#"
do
echo "$f"
/usr/local/bin/mogrify -density 300 -resize 1000x1000 -type grayscale -define tiff:endian=msb -compress LZW -format tif "$f" [0]
done
Item 1: With Image Magick, to create a new file instead of overwriting an existing one, use convert, not mogrify (magick convert with newer versions of IM).
Item 2: You can use shell parameter expansion to remove the extension, and then build the new filename from that and the new suffix:
for f in "$#"
do
echo "$f"
/usr/local/bin/convert "$f" -density 300 -resize 1000x1000 -type grayscale \
-define tiff:endian=msb -compress LZW -format tif "${f%.*}_GS.tiff"
done
${variable%pattern} returns the expansion of variable with the shortest match of pattern removed from the end.

Multiple png files to multiple ico files: Strange behavior

There are 2 png images in a directory: a.png and b.png. I'm trying to convert them to a.ico and b.ico with a single command.
Doesn't work as I want, only a.ico is created:
magick.exe *.png -define icon:auto-resize="256,128,96,64,48,32,16" -set filename:f %t %[filename:f].ico
However, the same approach works fine when I convert the images from PNG to JPG:
magick.exe *.png -set filename:f %t %[filename:f].jpg
What's wrong here?

Convert entire folder to greyscale using image magick?

I am trying to convert an entire folder to grayscale, using image magick.
convert *.jpg -colorspace Gray -separate -average
is met with this error :
convert: `-average' # error/convert.c/ConvertImageCommand/3290.
What is the correct command for this?
If you have lots of files to process, use mogrify:
magick mogrify -colorspace gray *.jpg
If you have tens of thousands of images and a multi-core CPU, you can get them all done in parallel with GNU Parallel:
parallel -X magick mogrify -colorspace gray ::: *.jpg
Also, the following can be used in a script - for the context menu of file managers like Dolphin, Nautilus, Nemo, Thunar etc:
for filename in "${#}"; do
name="${filename%.*}"
ext="${filename##*.}"
cp "$filename" "$name"-grayscale."$ext"
mogrify -colorspace gray "$name"-grayscale."$ext"
rm "$name"-grayscale."$ext"~
done

How to have different rules for the same target depending on the input extension?

I want to use make to convert images into the right format for a book I'm writing. Input images are in the figure directory and can have different file formats, e.g. PNG, SVG or JPG. Depending on the file extension, I want to run a different conversion command. The results should land in output and always be of type PNG.
FIGURES := $(patsubst figure/%.svg,output/%.png,$(wildcard figure/*.svg))
figures: $(FIGURES)
output/%.png: figure/%.svg
convert -density 600 -background none -resize 2500x $< $#
This is what I have so far, it works for SVG inputs only. How can I collect all files from the figure directory regardless of the file extension and apply different rules depending on the file extension?
Something like
sources := $(wildcard $(addprefix figure/*,.png .svg .jpg))
targets := $(patsubst figure/%, output/%.png, $(basename $(sources)))
.PHONY: all
all: $(targets)
output/%.png: figure/%.png
# whatever
output/%.png: figure/%.svg
convert -density 600 -background none -resize 2500x $< $#
output/%.png: figure/%.jpg
# blah

Bash script - How to skip pictures that are already in the folder?

I've got a bash script that uses ImageMagick to make thumbnail pictures from folder /pictures/ and puts them to folder /thumbnails/:
#!/bin/sh
cd /pictures/
for pic in *.jpg;
do
convert $pic -strip -quality 80 -thumbnail 225x150 /thumbnails/$pic;
done
But I would like that script to skip pictures that are already in /thumbnails/ folder. How could I do that?
#!/bin/sh
cd /pictures/
for pic in *.jpg;
do
if [ ! -f /thumbnails/$pic ]; then
convert $pic -strip -quality 80 -thumbnail 225x150 /thumbnails/$pic;
fi
done
In the if statement, the -f flag checks for the existence of the file, and the ! negates the condition. So altogether, the if statement verifies that the file doesn't already exist.
Since the world needs more Makefiles, put the following into a file called Makefile, where "↹" is a literal tab character:
SRC := /pictures/
DEST := /thumbnails/
PICTURES := $(wildcard $(SRC)*.jpg)
THUMBNAILS := $(patsubst $(SRC)%,$(DEST)%,$(PICTURES))
thumbnails: $(THUMBNAILS)
$(DEST)%.jpg: $(SRC)%.jpg
↹convert $< -strip -quality 80 -thumbnail 225x150 $#
You can then invoke it as:
make thumbnails
And if you want it to use more than one core you can tell it to do so with the -j flag.
make -j4 thumbnails

Resources