How to add watermarks to images via command line - Hopefully using Irfanview - image-processing

I have done a bit of digging and i havn't been able to find any feasible way of adding watermarks to my 1000+ images automatically. Is this possible with irfanview?? What im looking for is just some basic transparent text overlaying across each image. Can this be done using command line? Is it possible to go one step further and add a logo watermark?
Can you recommend any other programs rather than irfanview to do this, if its not possible to do it in this program.

I recommend using ImageMagick, which is open source and quite standard for manipulating images on the command line.
Watermarking with an image is as simple as
composite -dissolve 30% -gravity south watermark.jpg input-file.jpg output-file.jpg
With text, it's a little more complicated but possible.
Using the above command as an example, a Bash command for doing this to all files in folder would be:
for pic in *.jpg; do
composite -dissolve 30% -gravity south watermark.jpg $pic ${pic//.jpg}-marked.jpg
done
For more information about watermarking with ImageMagick, see ImageMagick v6 Examples.

Here's a quick python script based on the ImageMagik suggestion.
#!/usr/bin/env python
# encoding: utf-8
import os
import argparse
def main():
parser = argparse.ArgumentParser(description='Add watermarks to images in path')
parser.add_argument('--root', help='Root path for images', required=True, type=str)
parser.add_argument('--watermark', help='Path to watermark image', required=True, type=str)
parser.add_argument('--name', help='Name addition for watermark', default="-watermark", type=str)
parser.add_argument('--extension', help='Image extensions to look for', default=".jpg", type=str)
parser.add_argument('--exclude', help='Path content to exclude', type=str)
args = parser.parse_args()
files_processed = 0
files_watermarked = 0
for dirName, subdirList, fileList in os.walk(args.root):
if args.exclude is not None and args.exclude in dirName:
continue
#print('Walking directory: %s' % dirName)
for fname in fileList:
files_processed += 1
#print(' Processing %s' % os.path.join(dirName, fname))
if args.extension in fname and args.watermark not in fname and args.name not in fname:
ext = '.'.join(os.path.basename(fname).split('.')[1:])
orig = os.path.join(dirName, fname)
new_name = os.path.join(dirName, '%s.%s' % (os.path.basename(fname).split('.')[0] + args.name, ext))
if not os.path.exists(new_name):
files_watermarked += 1
print(' Convert %s to %s' % (orig, new_name))
os.system('composite -dissolve 30%% -gravity SouthEast %s "%s" "%s"' % (args.watermark, orig, new_name))
print("Files Processed: %s" % "{:,}".format(files_processed))
print("Files Watermarked: %s" % "{:,}".format(files_watermarked))
if __name__ == '__main__':
main()
Run it like this:
./add_watermarks.py --root . --watermark copyright.jpg --exclude marketplace
To create the watermark I just created the text in a Word document then did a screen shot of the small area of the text to end up with a copyright.jpg file.

Related

How can I merge images from two folders into a together side-by-side with imagemagick?

I have two folders, A and B, with image files that have corresponding names.
For example, each contain files labelled 01.png, 02.png, 03.png, etc.
How can I merge the corresponding files such that I have a third folder C that contains all merged photos so that both of the originals are side by side.
I am on Linux, if that changes anything.
I am not near a computer to thoroughly test, but this seems easiest to me:
#!/bin/bash
# Goto directory A
cd A
# For each file "f" in A
for f in *.png; do
# Append corresponding file from B and write to AB
convert "$f" ../B/"$f" +append ../AB/"$f"
done
Or use GNU Parallel and do them all at once!
cd A
parallel convert {} ../B/{} +append AB/{} ::: *.png
Using ImageMagick version 6, if your images are all the same dimensions, and if your system memory can handle reading all the input images into a single command, you can do that with a command like this...
convert FolderA/*.jpg -set filename:f "%[f]" \
-set option:distort:viewport %[fx:w*2] -distort SRT 0 null: \
FolderB/*.jpg -gravity east -layers composite FolderC/"%[filename:f]"
That starts by reading in all the images from FolderA and extending their viewport to double their width to the right.
Then it adds the special built-in "null:" to separate the lists of images before reading in the second list. Then it reads in all the images from FolderB.
Then after setting the gravity to "east", it composites each image from FolderB over the extended right half of each corresponding image from FolderA. That creates the effect of appending the images side by side.
The command sets a variable at the beginning to hold the filenames of the first list of input files, then uses those as the names of the output files and writes them to FolderC.
If you're using ImageMagick version 7, use the command "magick" instead of "convert".
You can do that with some bash scripting code. Assume you have two folders A and B with the corresponding image names in them. Also you have an empty folder AB to hold the results. Then using ImageMagick with the bash looping code, you can do something like this:
Collect the names of all the files in folder A and put into an array
Collect the names of all the files in folder B and put into an array
Loop over the number of images in the folders
Process them with ImageMagick +append and save to folder AB
outdir="/Users/fred/desktop/AB"
aArr=(`find /Users/fred/desktop/A -type f -iname "*.jpg" -o -iname "*.png"`)
numA="${#aArr[*]}"
bArr=(`find /Users/fred/desktop/B -type f -iname "*.jpg" -o -iname "*.png"`)
numB="${#bArr[*]}"
if [ $numA -eq $numB ]; then
for ((i=0; i<numA; i++)); do
nameA=`basename "${aArr[$i]}"`
nameA=`convert "$nameA" -format "%t" info:`
nameB=`basename "${bArr[$i]}"`
nameB=`convert "$nameB" -format "%t" info:`
convert "${aArr[$i]}" "${aArr[$i]}" +append ${outdir}/${nameA}_${nameB}.jpg
done
fi

Combine multiple images with same name

I have a folder called "Images" and one called "Mask". In the "Image" folder there are 200 images and in the "Mask" folder there are 200 images (with transparent background) with the same name. I now want to combine always the two pictures with the same name, so the image form the "Image" folder is in the background. The image are the same size.
Example Background image:
Example Mask:
I guess it should be quite easily doable with imagemagick, but i don't really now this program and the examples I found are all way more sophisticated.
I tried something like that:
convert Images/*.png -draw "image over x,y 0,0 Mask/*.png" combined/*.png
Did it not work because of the path? Do I have to to a loop, or is there a easy way?
Thanks
As you have lots of images, and it will do all the loops and filename/directory splitting for you, I would use GNU Parallel like this:
mkdir -p combined
parallel 'convert {} Mask/{/} -composite combined/{/}' ::: Images/*png
Be very careful with parallel and test what you plan to do with:
parallel --dry-run ...
first to be sure.
{} means "the current parameter"
{/} means "the current parameter stripped of the directory part"
::: indicates the start of the parameters.
Or, you can use a loop like this:
#!/bin/bash
mkdir -p combined
cd Images
for f in *png; do
convert "$f" ../Mask/"$f" -composite ../combined/"$f"
done
I finally find a way with a small bash script:
#!/bin/bash
for entry in Images/*
do
name="$(cut -d'/' -f2 <<<"$entry")"
convert Cells/$name Mask/$name -composite combined/$name
done

ImageMagick Batch Montage

In my first trial with Cygwin, I managed a simple montage of 2 image files into a final one.
However, I would like to batch montage all .jpg files in a directory so to combine them Two by Two, and thus have like half the original number of images.
Could you help?
I generally try to avoid Windows, but you can do it something like this:
GO.BAT
DIR /B *.JPG | CSCRIPT /NOLOGO PAIRIMAGES.VBS
PAIRIMAGES.VBS
cnt=1
Do
' Read in first image name
Im1 = WScript.StdIn.ReadLine()
If WScript.StdIn.AtEndOfStream Then
Wscript.Echo "WARNING: Unpaired file left over."
Exit Do
End If
' Read in second image name
Im2 = WScript.StdIn.ReadLine()
' Work out ImageMagick command, something like:
' convert im1.jpg im2.jpg +append result1.png
cmd="convert " & Im1 & " " & Im2 & " +append " & result & cnt & ".png"
' Show user the command, for debug purposes
WScript.echo cmd
' Now execute it
Set objShell = wscript.createobject("wscript.shell")
Set oExec = objShell.Exec(cmd)
If WScript.StdIn.AtEndOfStream Then
Wscript.Echo "Done"
Exit Do
End If
cnt = cnt + 1
Loop
Sample Output
E:\>DIR /B *.JPG | CSCRIPT /NOLOGO PAIRIMAGES.VBS
convert 1.jpg 2.jpg +append 1.png
convert 3.jpg 4.jpg +append 2.png
Done
If you want to align the tops of images with dissimilar sizes, use:
convert -gravity North ...
and change North to East if you want the centres aligned and to -South if you want the bottoms aligned.

Add ken burn effect on video from list of images

I have created video from list of images using ffmpeg
system("ffmpeg -framerate 1 -pattern_type glob -i '*.jpg' -c:v libx264 out.mp4")
Now i want to add Ken burn effect, can i do it with ffmpeg or imagemagic or any command line tool on linux.
I can't speak of ruby-on-rails, linux, or ffmpeg technologies. But if you would like to create a panning effect made popular by Ken Burn, you would extract regions of an image, and animate them together.
#!/bin/bash
# A 16:10 ratio
WIDTH=64
HEIGHT=40
# Extract parts of an image with -extent operator
for index in $(seq 40)
do
TOP=$(expr 120 + $index)
LEFT=$(expr 150 + $index)
FILENAME=$(printf /tmp/wizard-%02d.jpg $index)
convert wizard: -extent "${WIDTH}x${HEIGHT}+${TOP}+${LEFT}" $FILENAME
done
# Replace this with your ffmpeg script
SLICES=$(ls /tmp/wizard-*.jpg)
RSLCES=$(ls /tmp/wizard-*.jpg | sort -rn)
convert $SLICES $RSLCES -set delay 15 -layers Optimize /tmp/movie.gif
Edited by Mark Setchell beyond this point... (just trying to help out)
Much as I hate editing other people's posts, the first part of Eric's code can equally be written this way if you find that easier to understand:
# Extract parts of an image with -extent operator
for index in {1..40}
do
((TOP=120 + $index))
((LEFT=150 + $index))
FILENAME=$(printf /tmp/wizard-%02d.jpg $index)
convert wizard: -extent "${WIDTH}x${HEIGHT}+${TOP}+${LEFT}" $FILENAME
done

ImageMagick pdf to black and white pdf

I would like to convert a pdf file to a Black and White PDF file with ImageMagick. But I've got two problems:
I use this command:
convert -colorspace Gray D:\in.pdf D:\out.pdf
But this command convert only the FIRST page... How to convert all pages?
After use this command the resolution is terrible... but if I use -density 300 option the file size has increased more than double. So I would like to use the same DPI setting, but how to use?
Thanks a lot
Assuming you have all the necessary command line tools installed you can do the following:
Split and join PDF using pdfseparate and pdfunite (Poppler tools).
Extract the original density using pdfinfo plus grep/egrep and, for instance, sed. This will not guarantee the same size of the PDF file, just the same DPI.
Putting it all together you can have a series of bash commands as following:
pdfseparate in.pdf temp-%d.pdf; for i in $(seq $(ls -1 temp-*.pdf | wc -l)); do mv temp-$i.pdf temp-$(printf %03d $i).pdf; done
for f in temp-*.pdf; do convert -density $(pdfinfo $f | egrep -o 'Page size:[[:space:]]*[0-9]+(\.[0-9]+)?[[:space:]]*x[[:space:]]*[0-9]+(\.[0-9]+)?' | sed -e 's/^Page size:\s*//'| sed -e 's/\s*x\s*/x/') -colorspace Gray {,bw-}$f; done
pdfunite bw-temp-*.pdf out.pdf
rm {bw-,}temp-*.pdf
Note 1: there as a dirty workaround (for/wc/seq/printf) for a proper ordering of 10-999 pages PDFs (I did not figure out how to put leading zeros in pdfseparate).
Note 2: I guess ImageMagick treats PDFs as just another binary image file so for instance for mainly text files this will result in huge PDFs. Thus, this is a very bad method to convert text-based PDFs to B&W.

Resources