A pretty basic question but I'm new to
Imagemagick (and bash) and I'm having trouble batch cropping images in a folder. I've tried using a loop:
for image in '/home/donald/Desktop/New Folder'*.jpg; do
convert "$image" -gravity center -crop 95X95% "${image%.jpg}"-modified.jpg
done
but it returns:
convert.im6: unable to open image `/home/donald/Desktop/New Folder/*.jpg': No such file or directory # error/blob.c/OpenBlob/2638.
convert.im6: no images defined `/home/donald/Desktop/New Folder/*-modified.jpg' # error/convert.c/ConvertImageCommand/3044."
What would be the proper way of doing this?
Edit: Apparently a space in the folder name was causing problems I deleted it and things seem to be working.Apparently if you want to use a folder with a space name in bash you need to escape the space.
I believe you have no jpg files in the /home/donald/Desktop/New Folder/ directory. The shell will interpret it as the literal string /home/donald/Desktop/New Folder/*.jpg if there are no files matching the wildcard-ed string.
See this example:
$ for f in *.jpg*; do echo $f; done
file.jpg
file2.jpg
$ for f in *.jpgg; do echo $f; done
*.jpgg
See how that last one is the literal string and not a real file? It should have been displayed the first time too if it was (notice the trailing asterix symbol in *.jpg*).
You can fix this by checking if the file exists before executing the command, using [ -f "${file}" ]. For instance:
for image in '/home/donald/Desktop/New Folder'*.jpg; do
[ -f "${image}" ] && convert "$image" -gravity center -crop 95X95% "${image%.jpg}"-modified.jpg
done
This will check if the file image exists (-f) and execute the following statement only if true is returned &&. Had you written || instead of && then the following statement would be executed when false was returned.
Note that bash doesn't return true or false but it's the easiest way to explain and comprehend the notation.
Related
This question already has answers here:
How to convert all png files to pdf in Bash?
(2 answers)
Closed 2 years ago.
for f in find *.png; do convert "$f" "$f".pdf; done
This is what I have to find the png files in the directory and convert them to pdf, but I get errors. What is a better way to do this in Bash?
convert: unable to open image `find': No such file or directory # error/blob.c/OpenBlob/2705.
convert: no decode delegate for this image format `' # error/constitute.c/ReadImage/504.
convert: no images defined `find.pdf' # error/convert.c/ConvertImageCommand/3257.
If you're working in just one directory and not requiring find, you can do the following:
for i in *.png; do convert "$i" "${i%.png}.pdf"; done
which uses the shell globbing to find your files. Note the variable substitution to convert from a png to a pdf extension.
Otherwise it's more complicated. I think your find args are not correct. I would try:
find . -name \*.png
Note that I specify the starting directory (.) and then the name pattern (via -name). You need to escape the glob (asterisk) such that the shell doesn't expand it, and instead passes it directly to find.
Now, you can then execute find in a subshell, and then use the results.
e.g.
for f in $(find . -name \*.png); do convert "$f" "$f".pdf; done
Note the $(...) which executes the subshell and makes the output available.
If your filenames contain whitespace, the shell may split on this and cause you further problems. If this is the case there are a number of options presented here
I have a folder of images. I want to iterate through the folder, apply the same ImageMagick convert function to each file, and save the output to a separate folder.
The way I'm doing it currently is this:
#!/bin/bash
mkdir "Folder2"
for f in Folder1/*.png
do
echo "convert -brightness-contrast 10x60" "Folder1/$f" "Folder2/"${f%.*}"_suffix.png"
done
Then I copy and paste that terminal output into a new bash script that ends up looking like this:
#!/bin/bash
convert -brightness-contrast 10x60 Folder1/file1.png Folder2/file1_suffix.png
convert -brightness-contrast 10x60 Folder1/file2.png Folder2/file2_suffix.png
convert -brightness-contrast 10x60 Folder1/file3.png Folder2/file3_suffix.png
I tried to write a single bash script for this task but there was some weirdness with the variable handling, and this two-script method got me what I needed ...but I suspect there's an easier/simpler way and possibly even a one-line solution.
It's enough to change your first script, not to just echo the commands, but to execute them.
#!/bin/bash
mkdir "Folder2"
for f in Folder1/*.png
do
convert -brightness-contrast 10x60 "Folder1/$f" "Folder2/${f%.*}_suffix.png"
done
Crystal ball is telling me that there are spaces in filenames causing "some weirdness with the variable handling". In that case you need a workaround for the spaces. For example, you may try the following script:
#!/bin/bash
hasspaces="^(.+[^\'\"])([ ])(.+)$"
function escapespaces {
declare -n name=$1
while [[ $name =~ $hasspaces ]] ; do
name=${BASH_REMATCH[1]}'\'${BASH_REMATCH[2]}${BASH_REMATCH[3]}
echo 'Escaped string: '\'$name\'
done
}
mkdir Folder2
while read -r entry; do
echo "File '$entry'"
escapespaces entry
echo "File '$entry'"
tmp=${entry#Folder1}
eval "convert -brightness-contrast 10x60" "$entry" "Folder2/"${tmp%.*}"_suffix.png"
done <<<"$(eval "ls -1 Folder1/*.png")"
If this does not work, by all means let me know so I can request a refund for my crystal ball! Also, if you can give more details on the "weirdness in variable handling", we could try to help with those other weirdnesses :-)
Check this answer (and the few in the question) out:
You can use it in your example :
find Folder1 -name "*.png" | sed -e 'p;s/Folder1/Folder2/g' -e 's/.png/_suffix.png' | xargs -n2 convert -brightness-contrast 10x60
note : the p in the first sed makes the trick.
find will list you all the files in Folder1 with a name that matches the *.png expression
sed -e 'p;/Folder1/Folder2/g' will (a) print the input line and (b) replace Folder1 by Folder2
-e 's/.png$/_suffix.png' replaces the .png suffix with the _suffix.png suffix
xargs -n2 tells the shell that xargs should take two arguments max (the first one being printed by sed 'p' and the second one going through all the -e)
convert ... is your command, taking two inputs.
I need to write a shell script to convert the image format from .png to .tif. The script is as follows:
#!/bin/sh
for f in `ls *.png`
do
convert $f $f.tif
done
But doing this will append the .tif format to the existing filename. ie if the image is abc.png the $f will have abc.png and after converting the filename becomes abc.png.tif. This is not what I want. I need it to be abc.tif. How do I manipulate $f to remove .png?
This should work for you:
#!/bin/bash
for file in *.png
do
filename=$(basename "$file")
filename=${filename%.*}
convert $file $filename.tif
done
A line-by-line walkthrough of how this works:
for file in *.png - you don't need command substitution ls *.png to get the list of files with png extension. The wildcard * will auto-expand in shell to match the list of files in cwd; and in this case the list of files ending in .png.
filename=$(basename "$file") - this is only for defensive programming; it gets the actual name of the file
filename=${filename%.*} - this removes the extension from filename
convert $file $filename.tif - runs your actual convert command
My friend is asking this question, he is using Mac and cannot get PdfLatex working (having no dev CD, related here). Anyway my first idea:
$ pdftk 1.pdf 2.pdf 3.pdf cat output 123.pdf [only pdfs]
$ convert 1.png 2.png myfile.pdf [only images]
Now I don't know without LaTex or iPad's Notes Plus how to combine images and PDF -files. So how can I combine pdf -files and images in Unix?
You could run a loop, identifying PDF and images, and converting images to PDF with ImageMagick. When you're done, you assemble it all with pdftk.
This is a Bash-only script.
#!/bin/bash
# Convert arguments into list
N=0
for file in $*; do
files[$N]=$file
N=$[ $N + 1 ]
done
# Last element of list is our destination filename
N=$[ $N - 1 ]
LAST=$files[$N]
unset files[$N]
N=$[ $N - 1 ]
# Check all files in the input array, converting image types
T=0
for i in $( seq 0 $N ); do
file=${files[$i]}
case ${file##*.} in
jpg|png|gif|tif)
temp="tmpfile.$T.pdf"
convert $file $temp
tmp[$T]=$temp
uses[$i]=$temp
T=$[ $T + 1 ]
# Or also: tmp=("${tmp[#]}" "$temp")
;;
pdf)
uses[$i]=$file
;;
esac
done
# Now assemble PDF files
pdftk ${uses[#]} cat output $LAST
# Destroy all temporary file names. Disabled because you never know :-)
echo "I would remove ${tmp[#]}"
# rm ${tmp[#]}
I am gathering here some info.
Unix Commandline
More about Pdftk here.
Merging png images into one pdf file
Combine all files in a folder as pdf
Mac
Because the moderator in Apple SE removed the useful thread "Merge PDF files and images to single PDF file in Mac?"
here
-- I collect the tips here for Mac -- sorry but the moderator is very intolerant about collecting Newbie -things.
https://apple.stackexchange.com/questions/16226/what-software-is-available-preferably-free-to-create-and-edit-pdf-files-on-mac
https://apple.stackexchange.com/questions/812/how-can-i-combine-two-pdfs-in-preview
https://apple.stackexchange.com/questions/11163/how-do-i-combine-two-or-more-images-to-get-a-single-pdf-file
https://apple.stackexchange.com/questions/69659/ipad-pdf-software-to-edit-merge-annotate-etc-well-pdf-documents-like-in-deskto
I have a bash script:
#!/bin/bash
convert "$1" -resize 50% "$2"
Instead of passing two arguments while the script is run I want to mention just the source (or input file name) and the output file name should be auto-genarated from the source file name. Something like this "$1" | cut -d'.' -f1".jpg". If the input file name was myimage.png, the output name should be myimage.jpg. .jpg should be appended to the fist part of the source file name. It should also work if the argument is: *.png. So how can I modify my script?
The expansion ${X%pattern} removes pattern of the end of $X.
convert "$1" -resize 50% "${1%.*}.jpg"
To work on multiple files:
for filename ; do
convert "$filename" -resize 50% "${filename%.*}.jpg"
done
This will iterate over each of the command line arguments and is shorthand for for filename in "$#". You do not need to worry about checking whether the argument is *.png - the shell will expand that for you - you will simple receive the expanded list of filenames.
convert "$1" -resize 50% "${1%.*}.jpg"
The magic is in the %.* part, which removes everything after the last dot. If your file is missing an extension, it will still work (as long as you don't have a dot anywhere else in the path).
OUTFILE=`echo $1|sed 's/\(.*\)\..*/\1/'`.jpg
convert "$1" -resize 50% "$OUTFILE"