Text in a shape

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
badabou
Posts: 54
Joined: 2008-06-23T06:12:24-07:00

Text in a shape

Post by badabou » 2013-11-03T07:43:06-07:00

Hello,

Does the program imagemagick can put text in a form (eg a black and white mask) ?

I made a sketch to explain what I mean :
Image

Thank you for your answers.

snibgo
Posts: 11596
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Text in a shape

Post by snibgo » 2013-11-03T08:56:52-07:00

In theory, yes, from SVG input. See http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html
snibgo's IM pages: im.snibgo.com

User avatar
fmw42
Posts: 24931
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Text in a shape

Post by fmw42 » 2013-11-03T11:32:56-07:00

I cropped out your images.

Image

Image

Code: Select all

convert mask.png \( text.png -negate \) \( -clone 0 -negate \) -gravity center -compose over -composite text_in_heart.png
Image

badabou
Posts: 54
Joined: 2008-06-23T06:12:24-07:00

Re: Text in a shape

Post by badabou » 2013-11-04T02:08:22-07:00

This is not quite what I want to do.

I want the text to be inserted inside the shape and follow the edges of the shape.

User avatar
fmw42
Posts: 24931
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Text in a shape

Post by fmw42 » 2013-11-04T10:45:35-07:00

You will need to write your text over the heart image in a way that conforms to the shape of the heart. That will require you to use for example PANGO and trial and error. See http://www.imagemagick.org/Usage/text/#pango

snibgo
Posts: 11596
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Text in a shape

Post by snibgo » 2013-11-04T11:07:22-07:00

The job is easily done with SVG, using inkscape for the rasterization. For example, here is an SVG file with a simpler path. I use Inkscape directly. Doubtless it could be done by using IM to call Inkscape.

flow.svg:

Code: Select all

<svg xmlns:svg="http://www.w3.org/2000/svg" version="1.2"
     xmlns:xlink="http://www.w3.org/1999/xlink" 
  width="100%" height="100%" viewBox="0 0 300 310">
  <title>Basic textflow</title>
  <rect x="0" y="0" width="100%" height="100%" fill="yellow" fill-opacity="0"/>
  <flowRoot font-size="16" >
    <flowRegion fill="none" fill-opacity="0" stroke-opacity="1" stroke="red">
      <path d="M90,40L40,270L260,270L210,40z"/>
    </flowRegion>
    <flowPara fill="blue" fill-opacity="1" stroke-opacity="1" stroke="red">
The job is easily done with SVG, using inkscape for the rasterization. For example, here is an SVG file with a simpler path. I use Inkscape directly. Doubtless it could be done by using IM to call Inkscape.
    </flowPara>
  </flowRoot>
  <path d="M90,40L40,270L260,270L210,40z" fill="none" fill-opacity="0" stroke-opacity="1" stroke="red" stroke-width="2"/>
</svg>
Command:

Code: Select all

inkscape -f flow.svg -e flow.png -y 1
flow.png:
Image
snibgo's IM pages: im.snibgo.com

snibgo
Posts: 11596
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Text in a shape

Post by snibgo » 2013-11-04T20:07:23-07:00

Yeah, "convert flow.svg flow2.png" works fine, now I've put the Inkscape directory into my path.

Another example:

Code: Select all

convert heartWords.svg -trim heartWords.png
Where heartWords.svg is:

Code: Select all

<svg xmlns:svg="http://www.w3.org/2000/svg" version="1.2"
     xmlns:xlink="http://www.w3.org/1999/xlink" 
  width="100%" height="100%" viewBox="0 0 744 1052">
  <title>Basic textflow</title>
  <rect x="0" y="0" width="100%" height="100%" fill="yellow" fill-opacity="0"/>
  <path d="m 300,169.50504 c 0,0 -111.53096,-11.5113 -114.28571,140 -1.42858,78.57143 116.42857,275.28572 223.65747,328.46079 107.22895,-54.68207 225.08605,-251.39636 223.65755,-329.96779 -2.7548,-151.5113 -114.2858,-140 -114.2858,-140 0,0 -105.7142,5.71429 -109.37175,117.89636 C 405.71428,175.21933 300,169.50504 300,169.50504 z"
 fill="black" fill-opacity="1" stroke-opacity="0" stroke="red" stroke-width="2"/>
  <flowRoot font-size="33" text-anchor="middle" >
    <flowRegion>
      <path d="m 300,169.50504 c 0,0 -111.53096,-11.5113 -114.28571,140 -1.42858,78.57143 116.42857,275.28572 223.65747,328.46079 107.22895,-54.68207 225.08605,-251.39636 223.65755,-329.96779 -2.7548,-151.5113 -114.2858,-140 -114.2858,-140 0,0 -105.7142,5.71429 -109.37175,117.89636 C 405.71428,175.21933 300,169.50504 300,169.50504 z"
/>
    </flowRegion>
    <flowPara fill="white" fill-opacity="1" stroke-opacity="0" stroke="red">The job is easily done with SVG, using inkscape for the rasterization. For example, here is an SVG file with a heart path. I can use Inkscape directly, or by using IM to call Inkscape.</flowPara>
  </flowRoot>
</svg>
And the resulting heartWords.png is:
Image
I found the best font-size by trial and error.
snibgo's IM pages: im.snibgo.com

User avatar
fmw42
Posts: 24931
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Text in a shape

Post by fmw42 » 2013-11-04T20:22:38-07:00

pretty neat!

how did you create the heart shape and get it vectorized?

One option would be to get a binary heart image, get its boundary (edge) and vectorize with autotrace, something like at http://www.imagemagick.org/Usage/transform/#edge_vector, but starting with the edge image.

Did you do something like that or just create it by hand?

snibgo
Posts: 11596
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Text in a shape

Post by snibgo » 2013-11-04T22:01:22-07:00

I just created it by hand in Inkscape. A heart shape, roughly symmetrical, with four points on the curve and eight control points. I wrote the result to an SVG file, and copied the path from there to my own file.

The result works, but I don't much like the solution, so I then simplified it.

A heart needs only two points on the curve, with four control points, two of which coincide. In Inkscape, I edited the points, then used a text editor to remove the fractional values and ensure it was exactly symmetrical. I also reorganised my SVG file so the path needs to be specified once even though it is used twice (once for the black shape, and once as a path in which to fit the text). So here is a simpler version:

Code: Select all

<svg xmlns:svg="http://www.w3.org/2000/svg" version="1.2"
     xmlns:xlink="http://www.w3.org/1999/xlink" 
  width="100%" height="100%" viewBox="0 0 900 650">
  <title>Text in a heart</title>
  <defs>
    <path id="heartPath"
       d="M 434,638
          C 868,183 434,72 434,287
            434,72 0,183 434,638
          z"
       />
  </defs>
  <use xlink:href="#heartPath"
       fill="black" stroke="none"
       fill-opacity="1" stroke-opacity="0" />
  <flowRoot font-size="30" text-anchor="middle" >
    <flowRegion>
      <use xlink:href="#heartPath" />
    </flowRegion>
    <flowPara fill="white" fill-opacity="1"
              stroke-opacity="0">The job is easily done with SVG,
 using Inkscape for the rasterization.
 For example, here is an SVG file with a heart path.
 I can use Inkscape directly, or call Inkscape via IM.</flowPara>
  </flowRoot>
</svg>
snibgo's IM pages: im.snibgo.com

snibgo
Posts: 11596
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Text in a shape

Post by snibgo » 2013-11-05T08:34:44-07:00

Just for fun, we can define the heart-shape in SVG, rasterise that in IM (delegating to Inkscape), vectorise the result with Potrace, rasterise that, and compare the two raster images.

heart0.svg:

Code: Select all

<svg xmlns:svg="http://www.w3.org/2000/svg" version="1.2"
     xmlns:xlink="http://www.w3.org/1999/xlink" 
  width="900.000000pt" height="650.000000pt"  viewBox="0 0 900 650">
  <title>Text in a heart</title>
  <defs>
    <path id="heartPath"
       d="M 434,638
          C 868,183 434,72 434,287
            434,72 0,183 434,638
          z"
       />
  </defs>
  <use xlink:href="#heartPath"
       fill="black" stroke="none"
       fill-opacity="1" stroke-opacity="0" />
</svg>
Potrace needs PNM input.

Commands:

Code: Select all

convert -verbose -density 72 -depth 16 heart0.svg h0.pnm
c:\potrace\potrace.exe -s -o h1.svg h0.pnm
convert -verbose -density 72 -depth 16 h1.svg h1.pnm

compare -metric RMSE h0.pnm h1.pnm NULL:
The difference is ...

Code: Select all

769.815 (0.0117466)
... which is okay, and just visible. Potrace reports 18 points on the curve, rather than the elegant 2 that are actually needed.
snibgo's IM pages: im.snibgo.com

badabou
Posts: 54
Joined: 2008-06-23T06:12:24-07:00

Re: Text in a shape

Post by badabou » 2013-11-05T11:52:19-07:00

snibgo wrote:Yeah, "convert flow.svg flow2.png" works fine, now I've put the Inkscape directory into my path.

Another example:

Code: Select all

convert heartWords.svg -trim heartWords.png
Where heartWords.svg is:

Code: Select all

<svg xmlns:svg="http://www.w3.org/2000/svg" version="1.2"
     xmlns:xlink="http://www.w3.org/1999/xlink" 
  width="100%" height="100%" viewBox="0 0 744 1052">
  <title>Basic textflow</title>
  <rect x="0" y="0" width="100%" height="100%" fill="yellow" fill-opacity="0"/>
  <path d="m 300,169.50504 c 0,0 -111.53096,-11.5113 -114.28571,140 -1.42858,78.57143 116.42857,275.28572 223.65747,328.46079 107.22895,-54.68207 225.08605,-251.39636 223.65755,-329.96779 -2.7548,-151.5113 -114.2858,-140 -114.2858,-140 0,0 -105.7142,5.71429 -109.37175,117.89636 C 405.71428,175.21933 300,169.50504 300,169.50504 z"
 fill="black" fill-opacity="1" stroke-opacity="0" stroke="red" stroke-width="2"/>
  <flowRoot font-size="33" text-anchor="middle" >
    <flowRegion>
      <path d="m 300,169.50504 c 0,0 -111.53096,-11.5113 -114.28571,140 -1.42858,78.57143 116.42857,275.28572 223.65747,328.46079 107.22895,-54.68207 225.08605,-251.39636 223.65755,-329.96779 -2.7548,-151.5113 -114.2858,-140 -114.2858,-140 0,0 -105.7142,5.71429 -109.37175,117.89636 C 405.71428,175.21933 300,169.50504 300,169.50504 z"
/>
    </flowRegion>
    <flowPara fill="white" fill-opacity="1" stroke-opacity="0" stroke="red">The job is easily done with SVG, using inkscape for the rasterization. For example, here is an SVG file with a heart path. I can use Inkscape directly, or by using IM to call Inkscape.</flowPara>
  </flowRoot>
</svg>
And the resulting heartWords.png is:
Image
I found the best font-size by trial and error.
Hi snibgo,

Thank you so much for your examples, it's almost exactly what I want to do.

I did the test with your svg file :

Code: Select all

convert heartWords.svg -trim heartWords.png
but I is not the same result (the text is not displayed):
Image

My imagemagick version :

Code: Select all

# convert -version
Version: ImageMagick 6.5.9-2 2010-02-03 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2010 ImageMagick Studio LLC
Features: OpenMP
I have another question: Is it possible that the text size is adjusted automatically according to the number of characters depending on the space available in the vector form (as with the "caption" option imagemagick program)?

snibgo
Posts: 11596
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Text in a shape

Post by snibgo » 2013-11-05T18:34:02-07:00

My tests were on IM v6.8.7-0, Inkscape 0.48 (the current version), on Windows 7.

Your version of IM is very old. I suggest you upgrade. What version of Inkscape are you on? That's more likely to make a difference. Is the Inkscape directory on your path? What happens when you run the Inkscape command?

A script could be written that could guess the best font-size, based on the proportion of the heart within the rectangle, and automated trial-and-error. But it wouldn't be easy. I can't see a simple test for the text being clipped.
snibgo's IM pages: im.snibgo.com

badabou
Posts: 54
Joined: 2008-06-23T06:12:24-07:00

Re: Text in a shape

Post by badabou » 2013-11-06T00:52:18-07:00

My imagemagick version is old because when I update it, I have compatibility problems with php-imagick library (version 2.3.0) and all my scripts are written with it.

There's something I do not understand: In your second example, you seem not to use Inkscape to create the heart in PNG. So I simply used imagemagick "convert -trim heartWords.svg heartWords.png" with your heartWords.svg file, is it a mistake?

snibgo
Posts: 11596
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Text in a shape

Post by snibgo » 2013-11-06T01:11:54-07:00

My tests were done with the directory containing inkscape.exe on my PATH variable. This means that ImageMagick will use Inkscape to rasterise the SVG.

You could, instead, call inkscape directly.
snibgo's IM pages: im.snibgo.com

badabou
Posts: 54
Joined: 2008-06-23T06:12:24-07:00

Re: Text in a shape

Post by badabou » 2013-11-06T04:42:41-07:00

It's good it works perfectly.

I must now find a way to adjust the text size in the vector shape.
I do not know how to know if the text out of the vector shape or not. If I knew that I could do more tests and derive the best font size.

Post Reply