Page 1 of 1

[SOLVED]: IM6, Pango, creating text overlays

Posted: 2018-10-05T03:21:11-07:00
by squiddy
ImageMagick 6.9.10-13 Q16 i686 (Linux, 32bit)

I'm trying to overlay text onto existing images.

Each text is unique and <= 402 characters, each image is also unique and are frequently different geometries (rarely bigger than 500x500), and can be colour or monochrome, with a variety of predominant colours or tones.
I want the text to be as visible as possible on each image as the final composite images will be uploaded to social media programmatically (I'm using Python3). There are about 3500 images to deal with.

I'm using pango because it seemed the easiest way to wrap text to lots of different sized images.

So far I've got close to what I want by creating an "overlay" with the text, and compositing that over an existing image, as follows:

Code: Select all

convert -define pango:wrap=word -background white -transparent white -size www x hhh pango:"some text here up to 400ch" overlay.png

composite overlay.png image.png final_image.png
(I'm actually passing the values for -size and the pango text from variables, and the text is pango'd to set font & size using PML)

Example of my output here.

As you can see, this is not entirely satisfactory. I don't in truth really understand graphics and image structures at all well, so I'd like some help.

I'd like the text to be a single solid black or white, and to be able to vary that based on whether the underlying image is broadly light or dark. I realise that this means not every final image is going to perfect.

Hope I've been clear

Re: IM6, Pango, creating text overlays

Posted: 2018-10-05T09:04:05-07:00
by fmw42
You can test the mean value of the image beforehand. Then if less than 50%, make your text white. If greater than 50% make your text black.

convert image -format "%[fx:100*mean]" info:

will return a value between 0 and 100.

Your whole process could be done in one command with Imagemagick 7.

In IM 6 or 7, you can combine your two command into one:

Unix syntax:

Code: Select all

convert image.png \( -define pango:wrap=word -background white -transparent white -size www x hhh pango:"some text here up to 400ch" \) -compose over -composite final_image.png
For window, remove the \s

Re: IM6, Pango, creating text overlays

Posted: 2018-10-05T10:08:13-07:00
by snibgo
I wrote the reply below, but forgot to post it. Sorry.


We can write the text in black on a transparent background. Then, if the main image is dark (mean is less than 0.5) we invert the text colour with "-level 100%". Otherwise we leave the text unchanged ("-level 0%").

bash script for v6:

Code: Select all

MYLEV=`convert toes.png -format "%[fx:mean>0.5?0:100]" info:`

echo MYLEV=$MYLEV

convert \
  toes.png \
  \( \
     -define pango:wrap=word \
     -background none \
     -size 200x200 \
     pango:"blah some text here up to 400ch blah blah some text here up to 400ch blah blah blah some text here up to 400ch " \
     -channel RGB -level $MYLEV% +channel \
  \) \
  -gravity Center \
  -compose Over -composite \
  out.png
The v7 version can be more flexible, and in a single command:

Code: Select all

magick \
  toes.png \
  -evaluate Multiply 0.5 \
  -set option:MYSIZE %[fx:w-20]x%[fx:h-30] \
  -set option:LEVPC "%[fx:mean>0.5?0:100]" \
  \( \
     -define pango:wrap=word \
     -background none \
     -size %[MYSIZE] \
     pango:"blah some text here up to 400ch blah blah some text here up to 400ch blah blah blah some text here up to 400ch " \
     -channel RGB -level %[LEVPC]% +channel \
  \) \
  -gravity Center \
  -compose Over -composite \
  out.png

Re: IM6, Pango, creating text overlays

Posted: 2018-10-06T03:34:13-07:00
by squiddy
Ah thank you both!
I've been using IM for years and years, but just for odds and bits of trimming, cropping and montaging, and have never really wanted or needed to explore it further.

@snigbo your script works beautifully, it'll probably be exactly what I use.

The only question that pops up for me is, if I wanted to vary the typeface colour to a dark grey instead of black (or a pale grey instead of white), what would I need to modify in this set of parameters? (I'll obviously have a tinker myself but if you feel so inclined and have the time to answer, that'd be great :))

thanks again.

PS The cool kids (or even deeply uncool middle-aged blokes like me) use "$(command)" in Bash now rather than the backtick construction - it really helps with the escaping problems that can crop up.

Re: IM6, Pango, creating text overlays

Posted: 2018-10-06T04:30:41-07:00
by snibgo
Just before "pango:", insert a line like:

Code: Select all

-fill "#f00" \
This can be any valid colour, such as "gray(25%)" or a named colour as listed in "magick -list color".

I used to use $(), and for some reason switched to backticks. Thanks for the hint.

Re: IM6, Pango, creating text overlays

Posted: 2018-10-06T05:25:18-07:00
by squiddy
Thanks again.
I'm set to go now.

Your IM pages at snigbo.com are amazing, btw, but I expect I'm not the first to tell you that ...

Re: [SOLVED]: IM6, Pango, creating text overlays - ADDENDUM

Posted: 2019-02-05T07:12:48-07:00
by squiddy
ADDENDUM

Just a quick note to say that I recently made a small mod to the script that has made it work even better for my purposes.

By design, the text is always positioned in (roughly) the top one-third of the image, but for some images, the text tone (lighter or darker) was not quite right - for instance, in an image with a lot of sky but a very dark foreground, the text might appear very pale & difficult to read.

I realised in the end that this was because the "mean value" was being evaluated over the whole original image area. In an image with a large area of very dark or very light, this pushed the weighting too far over to one side when the text tone value was applied.

Example of too light a text tone here

Instead, I now evaluate the mean from the part of the image over which the text will appear, giving a cleaner, more consistent & more readable result.

Example of improved result here

So, for reference, I ended up using a script pretty much like this one:

Code: Select all

#!/bin/bash
#some other stuff 
#...
#
WW=$(identify -format "%w" $INPUT_FILE)
HH=$(identify -format "%h" $INPUT_FILE)
TOP=$(($HH/3))
convert \
  $INPUT_FILE \
  \( \
     -define pango:wrap=word \
     -background none \
     -size  $WW"x"$HH \
     -fill 'gray(5%)' \
     pango:"$INPUT_TEXT" \
     -channel RGB -level $(convert $INPUT_FILE -crop $WW"x"$TOP -format "%[fx:mean>0.5?0:100]" info:)% +channel \
  \) \
  -gravity East \
  -compose Over -composite \
  $OUTPUT_FILE