Scaling Multi-Line Text to Fit

Discuss SVG code, accessible via the XML Editor.
BillBinko
Posts: 6
Joined: Mon Aug 24, 2009 3:42 pm

Scaling Multi-Line Text to Fit

Postby BillBinko » Wed May 13, 2015 2:20 am

Hi folks,

I'd like to be able to have text shrink to fit a multi-line text box. The box will have a default font (say 20px Sans) and if the text fits in the box it will not adjust the font. However, if the text would overflow, it will reduce the font-size until it no longer overflows.

Just to be clear, I know Inkscape (and SVG in general) doesn't do this by default. However, since I am generating the SVG programatically and then using Inkscape as a converter (to PDF), I believe this is possible if I know the algorithm that Inkscape uses for text flow and how it calculates font-metrics, etc.

So, I suppose my first question is: has anyone done this? I've seen approaches online that use the browser's DOM to do it in Javascript, and I've seen how to do it with ImageMagick. I know that it can be inefficient, but that's not a huge deal for me. Has anyone done something like this Inkscape?

Here's a simple FlowRoot that hold a full alphabet across and is three lines high. Adding even a space to the first line would cause it to wrap to four lines and therefore need to shrink fonts. To make this work, I THINK I would need to do the following:

  • Grab the height and widthof the box (applying any scaling in the transform on the FlowRoot, there is none in this example)
  • Calculate the number of rows that currently fit with the default font (74.483658 / (20 * 1.25) ~= 3 (oddly, it's just BELOW 3 which means it should wrap... but doesn't - WHY?)
  • Count the number of <flowPara> elements in the <flowRoot> since that is the minimum number of rows I'll need.
  • For each <flowPara> follow Inkscape's text-wrapping algorithm using the same fontMetrics that it uses [HELP] figuring out how many MORE rows I'll need.
  • If that total number of rows is > the number of rows that fit, adjust the font size and re-calculate the split <flowPara>s until it does fit (I will use a Binary Search here starting with the default font and shrinking it.
So, the key things I need to do this are:
  • Documentation (or a pointer to code) for Inkscape's Text Wrapping code
  • Descriptions of how to calculate the FontMetrics. Specifically, can I use ImageMagick's FontMetrics (which I have in PHP) and get equivalent information? If not, I'd like ideas (fontserver?)
  • Explanation of why the text didn't wrap in the example below even though it says it will hold < 3 rows (do I not count line spacing at the top and bottom?)

I'd really appreciate any help on this matter - this would make a huge difference in my project.

Thank you!
Bill

Sample Code

Code: Select all

<flowRoot
       xml:space="preserve"
       id="flowRoot2985"
       style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
       transform="translate(-80.257425,41.559833)"><flowRegion
         id="flowRegion2987"><rect
           id="rect2989"
           width="359.05862"
           height="74.483658"
           x="154.28572"
           y="198.07646"
           style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans" /></flowRegion><flowPara
         id="flowPara2991">ABCDEFGHIJKLMNOPQRSTUVWXYZ</flowPara><flowPara
         id="flowPara2993">Line 2</flowPara><flowPara
         id="flowPara2995">Line 3</flowPara></flowRoot>

Return to “SVG / XML Code”