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
Related
I have the magick absolute in a folder and in a sub-folder temp I have images. I need/want to process the images and write them to another sub-folder output.
folder (with magick)
temp sub-folder (with input files)
output sub-folder (where processed images are placed)
But I am unable to stop the variable i picking up the path temp/. How do I stop it? Do I have to strip the characters temp/ from i then use it? Or is there a simple way to do this?
for i in temp/*; do
./magick convert -resize 450 -strip -quality 90% temp/$i output/$i
done
Yes you can with parameter expansion:
shopt -s nullglob
for i in temp/*; do
./magick convert -resize 450 -strip -quality 90% "$i" "output/${i#temp/}"
done
The nullglob prevents 0 matches from expanding to the pattern.
Maybe you can also just change working directory to temp and use ... I'm just not sure if magick will still work if referred from a different directory.
cd temp || exit
for i in *; do
../magick convert -resize 450 -strip -quality 90% "$i" "../output/$i"
done
I have a directory with multi level sub-directories containing .jpg files that I want to change using ImageMagick.
To change a single file I do convert image0.jpg -resize x1000 -quality 82 small_image0.jpg
But how can I do the same but for all the jpgs in every directories, with a single command?
That is:
Apply -resize x1000 -quality 82 to every jpg in all of the directories.
Every output file should be in the same directory as its input file but with small_ prepended to the name.
With find and bash.
#!/usr/bin/env bash
path=("$#")
while IFS= read -ru9 -d '' pic; do
dirname=$(dirname "$pic")
basename=$(basename "$pic")
printf 'Converting %s to %s\n' "$pic" "$dirname/small_$basename"
convert "$pic" -resize x1000 -quality 82 "$dirname/small_$basename" || exit
done 9< <(find "${path[#]}" -type f -name '*.jpg' -print0)
Assuming you name your script myscript, execute it with the path to the pictures as the argument.
./myscript /path/to/pictures
Change /path/to/pictures with the correct path/directory, or add more path/directory separated by a space e.g. ./myscript path1 path2 anotherpath morepath
instead of just one directory.
The command sips has a great option to read information from files. The following command loops through all images and shows information on the width or height:
for i in *.jpg; do sips -g pixelWidth $i;done
for i in *.jpg; do sips -g pixelHeight $i;done
Now I would like to read this information and use it with mv to rename the images like so:
image-widthxheight.jpg
image-1600x900.jpg
The final thing I want accomplish is, to use sips to resize images and write the new information directly into the filename.
Has anybody an idea, how I can extract the information from width and height and use it together with mv?
I found it out myself. It's a nice bash script now. Maybe not so elegant, but it works – It's also available as a gist on GitHub.
NEW VERSION THANKS TO THE ADVICE – SEE COMMENTS
#!/bin/bash
#
# 1. This script copies all *.jpg-files to a new folder
# 2. Jumps into folder and resizes all files with sips
# 3. Renames all files and uses information from sips
#
folder="resized_and_renamed"
mkdir -p "$folder"
cp *.jpg "$folder"
cd "$folder"
# RESIZE ALL IMAGES TO MAXIMUM WIDTH/HEIGHT OF 360
sips -Z 360 *.jpg
# RENAME FILES WITH INFORMATION FROM SIPS
for i in *.jpg
do
pixelWidth=$(sips -g pixelWidth "$i" | awk '/pixelWidth:/{print $2}')
pixelHeight=$(sips -g pixelHeight "$i" | awk '/pixelHeight:/{print $2}')
# REMOVE EXTENSION
filename=${i%.jpg}
# NOW RENAME
mv $i ${filename##*/}-${pixelWidth}x${pixelHeight}.jpg
done
I'm trying to resize and rename several hundred subdirectories of images. The files that I need to be changed:
End with A.jpg
Need to be resized down to 400x400
Renamed to A#2x.jpg
Example:
images/**/A6919994719A#2x.jpg
I got the resizing bit down in one directory. I'm having some trouble finding a way to rename just the end of the file, not the extension, and executing it through the subdirectories.
Any help would be appreciated.
#!/bin/bash
for i in $( ls *A.jpg); do convert -resize 400x400 $i
You can do this:
#!/bin/bash
find . -name "*A.jpg" | while read f
do
newname=${f/A.jpg/A#2.jpg}
echo convert "$f" -resize 400x400 "$newname"
done
Remove the word echo if it looks correct, and run only on files you have backed up.
You can also do it in a one-liner, if you really want to:
find . -name "*A.jpg" -exec bash -c 'old="$0";new=${old/A.jpg/A#2.jpg};echo convert "$old" -resize 400x400 "$new"' {} \;
I use the script below to convert all pdf files in a directory to png files, and I want to run it only over the files that have yet to be converted.
#!/bin/bash
# Convert pdf to png
for f in *.pdf
do
echo "Converting $f"
gs -dNOPAUSE -dBATCH -sDEVICE=png256 -r480 -q -sOutputFile="png/$f.png" "$f"
done
rename -f 's/\.pdf\.png/\.png/' png/*.pdf.png
How do I modify the loop so that it is restricted to files where the corresponding png file either does not exist or is older than the pdf file?
A simple modification to your script:
#!/bin/bash
# Convert pdf to png
for f in *.pdf
do
png="png/${f%pdf}png"
if [ -e "$png" -a "$f" -nt "$png" ]; then
continue
fi
echo "Converting $f"
gs -dNOPAUSE -dBATCH -sDEVICE=png256 -r480 -q -sOutputFile="$png" "$f"
done
Firstly, we create a $png variable using in place editing. Basically the %pdf tells bash to remove the last occurrence of pdf, which is the extension. Then we can place this into a string that prefixes it with png/ and adds the png extension. This saves you the last rename command.
Now we have an if statement that continues the loop if a certain condition is met. Continue means go to the next iteration of the loop, without executing anything else for this iteration. The condition is "$png" exists (-e "$png") and (-a) "$f" is newer than "$png" ("$f" -nt "$png").
But I would suggest writing a Makefile:
PDFS := $(wildcard *.pdf)
PNGS := $(addprefix png/,$(PDFS:.pdf=.png))
all: $(PNGS)
png/%.png: %.pdf
gs -dNOPAUSE -dBATCH -sDEVICE=png256 -r480 -q -sOutputFile="$#" "$<"
And run it with make any time you want to generate newer PNGs.