Generating date stamp image in Imagemagick - imagemagick

I have a static html site where I post calendar events. I thought of using Imagemagick to generate date stamp image like this.
Can it be done in ImageMagick?

Assuming that image a.png contains the background (white rectangle with red band) you can use:
convert a.png -gravity Center -pointsize 24 -annotate +0+0 "16" -gravity North -fill white -pointsize 18 -annotate +0+0 "FEB" output.png
You'll probably have to tweak +0+0 coordinates to correctly fit your background image.
Also note that this is a static command that generates the example you posted (with month fixed to 'FEB' and day fixed to '16').

I may be a couple of years late to the party, but I felt like generating iPhone (or is that iCalendar) style datestamps - and it was raining anyway...
Here is a bash script, either call it with no parameters to get today's date, or with something like
DateStamp 12 Jan
to get a different stamp.
#!/bin/bash
################################################################################
# DateStamp
# Mark Setchell
#
# Generate a date stamp like on iPhone, either using the day and month supplied
# or, if not supplied, today's date
#
# Requires ImageMagick
################################################################################
# Get current day and month in case none supplied
mn=$(date +'%b')
dn=$(date +'%d')
# Pick up any day/month supplied and save in $d and $m
d=${1:-$dn}
m=${2:-$mn}
# Convert month name to upper case
m=$(tr [:lower:] [:upper:] <<< $m)
# Set colours for month background/foreground and day background/foreground
mbg="rgb(128,0,0)"
mfg="white"
dbg="rgb(240,240,240)"
dfg="rgb(128,0,0)"
# Generate stamp
convert -stroke none -gravity center \
\( -size 128x64! -background $mbg -fill $mfg label:"$m" \) \
-size 128x4! xc:gray40 -append \
\( -size 128x64! -background $dbg -fill $dfg label:"$d" \) -append \
-bordercolor white -border 8 \
-bordercolor gray70 -border 4 \
-bordercolor white -border 4 result.png

Yeah Imagemagick can do that. http://www.imagemagick.org/Usage/text/ has lots of examples. It might be best to write a small python script that takes month and date and supplies the proper arguments to Imagemagick once you figure out what you want.

Related

How to pass Imagemagick montage output and image properties to the convert command without using any temporary files?

I have a set of images, and I can use the Imagemagick montage command on them to produce a montage image file with transparent background (let's call this fgimg). Now I have another existing image (let's call this bgimg) that I'd like to use (after some special processing with the convert command) as the background for fgimg, which can be achieved within the same convert command. At this point it seems trivial to avoid writing the temporary fgimg to disk, simply by piping the standard output of montage to the standard input of convert.
My problem is that the special processing I'm applying to bgimg will require some knowledge of the image properties of fgimg (e.g., resizing bgimg to have the same size as fgimg), which I don't know in advance. How can this information be retrieved and used in the convert command?
Note: I'm using Imagemagick version 6.9.7-4 on Linux.
I'll include some commands below to further illustrate the problem in detail.
The following command produces the montage image fgimg from a set of input images. The output is in the 'special' miff format (which seems best for temporary output to be worked on later), and has transparent background so that the actual background can be applied later. Most of the other options here are not important, but the point is that the output size (dimensions) cannot be determined in advance.
montage input_*.jpg -tile 5x -border 2 -geometry '200x200>+20+20' \
-gravity center -set label '%f\n%G' -background none -fill white \
-title 'Sample Title' miff:fgimg
Next, I have another input image bgimg.jpg. I want to perform some processing on it before using it as background to fgimg. The processing can be quite complex in general, but in this example, I want to:
resize bgimg.jpg to fit inside the dimensions of fgimg without any cropping;
apply a fade-to-black effect around the edges;
make it the same size as fgimg, with a black background;
combine this with fgimg to produce the final output.
Notice that I need the size of fgimg in two places. I can first extract this into a shell variable:
size=$(identify -format '%G' miff:fgimg)
Then I can do all the steps above in one convert command (note that $size is used twice):
convert "bgimg.jpg[$size]" -gravity center \
\( +clone -fill white -colorize 100% -bordercolor black \
-shave 20 -border 20 -blur 0x20 \) -compose multiply -composite \
-background black -compose copy -extent $size \
miff:fgimg -compose over -composite final_out.jpg
Now here is the problem: I want to avoid writing the temporary file fgimg to disk.
I could replace miff:fgimg with miff:- in both the montage and convert commands and then just pipe one to the other: montage ... | convert .... But how do I deal with the $size?
I tried to use file descriptors (miff:fd:3) but this does not seem to work, which is confirmed by the comments to this question.
Is there a way to do this (in Imagemagick v6) without creating a temporary file?
This example command uses ImageMagick v6 on a bash shell. Instead of "montage" it starts by using "convert" to create a "logo:", one of IM's built-in sample images, then pipes it out as a MIFF and into the "convert" command that follows. You can pipe the output of "montage" just as easily. And it uses another IM built-in image "rose:" as your "bgimg.jpg"...
convert logo: miff:- | convert - rose: \
+distort SRT "%[fx:t?min(u.w/v.w,u.h/v.h):1] 0" \
-shave 1 +repage -gravity center -bordercolor black \
\( -clone 1 -fill white -colorize 100 -shave 6 -border 6 \
-blur 0x6 -clone 1 -compose multiply -composite \) -delete 1 \
\( -clone 0 -alpha off -fill black -colorize 100 \
-clone 1 -compose over -composite \) -delete 1 \
+swap -composite final_out.jpg
That reads the piped image "-" and the background image "rose:".
Then it uses "+distort" with an FX expression to scale "rose:" to the maximum dimensions that still fit within the original piped input image. That operation adds a pixel all around so we use "-shave 1" to get rid of that.
Next inside parentheses it clones that re-scaled background image, makes an edge blur mask, and composites them to make the fade-to-black edge on the background image. Right after the parentheses it deletes the non-edged background image.
In the next parentheses it clones the input image, makes it black, clones the modified background image, and composites it centered over the black one. Again the non-extended background image is discarded after the parentheses with "-delete 1".
Finally the modified background and the input image are put in the proper order with "+swap" and composited for the final output. Run this command without the last "-composite" to see the two images that result from the prior parts of the command.
Both the main input image and background image can be any size, any dimensions, and any aspect ratio. This works for me on v6.8.9 on a bash shell. It should work on any ImageMagick newer. It should work on Windows by removing all the backslashes that escape parentheses and changing the continued-line backslashes "\" to carets "^".
EDITED TO ADD:
You can use that FX expression to find the scaling amount, save it as a variable, then isolate the background image inside parentheses and use that variable to do the scaling and shaving there. That way it only affects the background image. There may be a rounding error with that, but the main image, which determines the exact final output dimensions, will be unaffected. Note the difference in the first few lines of this command...
convert logo: miff:- | convert - rose: \
-set option:v1 "%[fx:min(u.w/v.w,u.h/v.h)]" \
\( -clone 1 +distort SRT "%[v1] 0" -shave 1 \) -delete 1 \
+repage -gravity center -bordercolor black \
\( -clone 1 -fill white -colorize 100 -shave 6 -border 6 \
-blur 0x6 -clone 1 -compose multiply -composite \) -delete 1 \
\( -clone 0 -alpha off -fill black -colorize 100 \
-clone 1 -compose over -composite \) -delete 1 \
+swap final_out.jpg

Is there anyway to batch create 30+ logos but change text on each one?

I need to create 30+ logos in a similar style to this:
http://www.manchestertaxicomparison.co.uk/wp-content/themes/ilfordtaxis/images/logo.png
Only thing that changes will be the top text, i.e Manchester -> Newcastle
I have to do this many time and as such would love to know if there is anyway to automate it.
Kind regards,
Jack
Personally, I would do it with ImageMagick at the command line like this:
convert -pointsize 72 -background none -fill "rgb(254,203,54)" \
label:"LEEDS" -resize 170x30! base.png +swap \
-geometry +40+0 -composite result.png
And then do all 30 of them in a simple loop:
#!/bin/bash
for city in LEEDS LIVERPOOL EDINBURGH CARDIFF; do
convert -pointsize 72 -background none -fill "rgb(254,203,54)" label:"$city" -resize 170x30! base.png +swap -geometry +40+0 -composite "$city.png"
done
Note that there are other words not necessarily visible on StackOveflow's white background.
ImageMagick is installed on most Linux distros and is available for macOS and Windows.

Practical Imagemagick stack (combined) complex commands

I want a combined command that can perform the following task in single execution. I searched the internet, but hardly found any tutorial that guide us to write any stack command. I can found single command for each operation, such as -composite, -blur, etc, and I know I can pipe the command as such
convert ... mpr:- | convert ... mpr:- | ... | convert ... png:-
However, I want a combined command that use \( ... \) and mpr:{label} since this will increase the performance as all operations are executed in single process (pipeline in shell can degrade the performance, and the process sequence is required to be in order).
The process sequence as such:
put flower.png on top of the frame.png -> mpr:framedFlower
put mpr:framedFlower on top of the background.png -> mpr:out2
blur the heart.png, right-gradient-transparent the smiley.png and put both image on top of mpr:out2 -> mpr:out3
annotate the mpr:out3 with "Hello world" (placement=bottom) -> png:-
I don't include the commands that I have tried because they are too messy and it will be an insult to those users who read it. I tried for many hours, but can't get it done. Please advise.
I haven't spent ages futzing with the exact coordinates as I am only using sample pictures, but this one-liner contains every technique you need to do what you are asking.
There is basically one line of code per element in the final image:
convert frame.png -resize 500x400\! \( flower.png -resize 400x300\! \) -gravity center -composite \
background.png +swap -gravity northwest -geometry +100+150 -composite \
\( heart.png -resize 200x200 -blur 0x8 \) -geometry +1200+250 -composite \
-gravity south -pointsize 72 -fill red -annotate +0+60 'Hello world' \
\( emoji.png -resize 250x250 -channel a -fx "u.a*(1-(i/w))" \) -gravity northwest -geometry +1200+500 -composite result.png
The first line reads in the picture frame and the flower and resizes them each independently because of the parentheses and then composites the flower into the frame.
The next line loads the background and then uses +swap to put it behind the framed picture from the previous line. It then sets -gravity to northwest as the origin for the ensuing -geometry before compositing the framed picture onto the background.
The next line loads the heart and resizes and blurs just the heart before compositing that onto the main picture at your specified position.
Next up is the annotation - the only interesting thing is that I set the -geometry to south which means that the offsets to -annotate are relative to the bottom centre of the background.
Finally, I load the emoji-thing and resize just it in parentheses before compositing over the main image. The only interesting thing is that I use -fx to alter the alpha channel (-channel a) and I multiply the existing transparency (u.a) by the fraction of the inverse of the distance we are across the image, namely (1-(i/w)).
Hope that is fairly clear!
Start Images

Start path relative to corner of image

I have written the following script which uses the ImageMagick* convert utility to append axis labels to an existing image.
LEFT_="l -30,0 +2,+2 -6,-2 +6,-2 -2,+2 z"
RIGHT_="l 30,0 -2,+2 +6,-2 -6,-2 +2,+2 z"
convert -size 240x160 pattern:SMALLFISHSCALES \
-pointsize 16 -fill black -background white \
-gravity SouthEast -splice 0x20 \
-draw "translate 40,0 text 0,0 'Time' stroke red path 'm 5,2 $RIGHT_'" \
-gravity NorthWest -splice 20x0 \
-draw "rotate +90 translate 40,-10 text 0,0 'Value' path 'm -5,2 $LEFT_'" \
example.png
Which produces the following image:
This is almost exactly what I am after, except that the red arrow is out of place. I expected the red arrow to appear next to the Time label, since its start point is specified as a relative position in the same draw command. Unfortunately, it looks like the -gravity option is affecting the text primitive, but not the path primitive.
Is there a way to reference the SouthEast corner, or the Time text label when specifying the start position of the red arrow? I can't use absolute coordinates, because the size of the image varies.
*ImageMagick 6.7.8-9 on CentOS 7
Updated Answer
Maybe you can make Unicode text arrows like this then they will be affected by gravity...
perl -e 'binmode(STDOUT,":utf8"); print "Time ... \x{2192}\x{2191}";'|
convert -font TimesNewRoman -pointsize 36 label:#- arrows.png
Depending on your OS, the following may do as a replacement for the Perl above...
printf "%b" "\u2192" | convert ...
Original Answer
I am not at all familiar with paths, but I can suggest a way to achieve what you want that doesn't use gravity at all, and maybe that will help.
Rather than use -splice, you can clone your original image and crop it to the size you planned to splice on, and then -append the strips that label the axes. It is easier to show you the command than explain it!
convert -size 240x160 pattern:SMALLFISHSCALES \
\( +clone -crop x20+0+0 -fill blue -colorize 100% \) \
-append \
\( +clone -crop 20x+0+0 -fill red -colorize 100% \) \
+swap +append result.png
I have filled the x-axis blue, but remove that and add whatever labelling and arrows you need, and I filled the y-axis red, but likewise remove that and add labelling and arrows - rotating as necessary.
Two tricky things to note...
-append will append the second image below the first
+append will append the second image to the right of the first, so I +swap beforehand to put it on the left side.

Overlaying an image's filename using ImageMagick (or similar)

I know ImageMagick's annotate command can superimpose some text over an image, but can it use the image's filename as this text? I would've assumed so, but can't seem to find direct documentation that confirms this.
No doubt some combination of parameters can manage this, or is there a better way of doing this in a script?
Eric L.'s answer is correct -- +1 from me for it! -- but -annotate doesn't give you much control over the appearance of the text.
If you look for prettyness, then rather go for something that uses -composite. You can use an IM command to construct an overlay image first (which uses a semi-transparent background) and then overlay it over the original image.
Here is an example how to do it with -composite instead of -annotate, using a scripted approach that processes every PNG file in the current directory. This one even automatically adapts the font size and fits it into the available "width * 90%" -- it is a Bash script (see comments for Win equivalent):
for img in *.png; do
width=$(identify -format %W ${img})
width=$(( ${width} * 9 / 10 ))
convert \
-background '#0008' \
-gravity center \
-fill white \
-size ${width}x100 \
caption:"${img}" \
"${img}" \
+swap \
-gravity south \
-composite \
"with-caption-${img}"
done
An example illustration for one original and the respective output are below:
!
Here is a command that uses -annotate, trying to set a few things beyond the default parameters:
for img in so#12231624-right.png; do
convert \
"${img}" \
-fill red \
-undercolor '#0008' \
-pointsize 24 \
-gravity south \
-annotate +0+5 "${img}" \
"with-annotate-${img}"
done
It's a very old entry but I find it each time I search for this topic, and it doesn't work (for me at least). Here something that works for me:
convert input.jpg -gravity South -annotate 0 '%f' output.jpg
Hope this helps someone...
You can also use mogrify to add text to bunch of images at once.
mogrify -gravity South -annotate 0 '%f' -pointsize 24 -fill white *.png
This will overwrite existing images, so make sure you have a backup before you execute this.
Building on Steve Czetty's solution, it looks like you can set the text size and color of the annotation, using -pointsize and -fill, respectively.
Here's an example:
convert input.jpg -gravity south -pointsize 24 -fill yellow -annotate 0 '%f' output.jpg
Obviously, you can change the text size from 24 points to something else, as well the color, from 'yellow' to some other color, as per your preference.

Resources