Perfect! Minor changes - use SVG12BridgeContext, and catch DomException when checking the width and height of the SVGTextPositioningElement (getExtentOfChar does not return null even if the last character has overflowed).

In the interest of making others' lives easier (pay it forward), here's the complete solution to not only detect overflow in a flowText region, but also resize the font-size automatically to maximize the size of the displayed text.

The code:
---
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;

import org.apache.batik.bridge.svg12.SVG12BridgeContext;

import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.dom.svg.SVGOMElement;
import org.apache.batik.dom.svg.SVGTextContent;

import org.apache.batik.gvt.GraphicsNode;

import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;

import org.apache.batik.transcoder.image.JPEGTranscoder;

import org.apache.batik.util.XMLResourceDescriptor;

import org.w3c.dom.DOMException;
import org.w3c.dom.Element;

import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGRect;
import org.w3c.dom.svg.SVGTextPositioningElement;

public class Test
{
        public static void main(String[] args)
        {
                try
                {
                        // Open the SVG template.
                        String parser = 
XMLResourceDescriptor.getXMLParserClassName();
                        SAXSVGDocumentFactory f = new 
SAXSVGDocumentFactory(parser);
SVGDocument doc = f.createSVGDocument(new File("test.svg").toURI().toString());
                        Element testElement = doc.getElementById("test");
                        UserAgent userAgent = new UserAgentAdapter();
                        DocumentLoader loader = new DocumentLoader(userAgent);
                        SVG12BridgeContext ctx = new 
SVG12BridgeContext(userAgent, loader);
                        GVTBuilder builder;
                        GraphicsNode rootGN;
        
                        // Boot the CSS and DOM interfaces.
                        ctx.setDynamicState(SVG12BridgeContext.DYNAMIC);
                        builder   = new GVTBuilder();
                        rootGN    = builder.build(ctx, doc);

        

                        while (overflows(testElement))
                        {
int fontSize= Integer.parseInt(testElement.getAttribute("font- size"));
                                
                                
testElement.setAttribute("font-size", (new Integer(fontSize *= 0.5)).toString());
                        }
int pointSize1 = Integer.parseInt(testElement.getAttribute("font- size"));
                        
                        while (!overflows(testElement))
                        {
int fontSize= Integer.parseInt(testElement.getAttribute("font- size"));
                                
                                
testElement.setAttribute("font-size", (new Integer(fontSize *= 2)).toString());
                        }
int pointSize2 = Integer.parseInt(testElement.getAttribute("font- size"));
                        int pointSize = pointSize2;
                        float divider = pointSize2 - pointSize1;
                        
                        while (true)
                        {
                                if (divider < 0.01) { break; }
                                
                                if (!overflows(testElement))
                                {
                                        pointSize = pointSize += divider;
testElement.setAttribute("font-size", (new Integer(pointSize)).toString());
                                        divider = divider/2;
                                }
                                else
                                {
                                        pointSize = pointSize -= divider;
testElement.setAttribute("font-size", (new Integer(pointSize)).toString());
                                        divider = divider/2;
                                }
                        }

                        while (overflows(testElement))
                        {
                                pointSize = 
Integer.parseInt(testElement.getAttribute("font-size"));
                                pointSize -= divider;
testElement.setAttribute("font-size", (new Integer(pointSize)).toString());
                        }
                        
                        // Render the rasterized output file.
                JPEGTranscoder t = new JPEGTranscoder();
        
                // Set the transcoding hints.
t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new Float(. 8));
        
                // Create the transcoder input.
                TranscoderInput input = new TranscoderInput(doc);
        
                // Create the transcoder output.
                OutputStream ostream = new FileOutputStream("output.jpg");
                TranscoderOutput output = new TranscoderOutput(ostream);
        
                // Save the image.
                t.transcode(input, output);
        
                // Flush and close the stream.
                ostream.flush();
                ostream.close();
                
                }
                catch (IOException ex)
                {
                        System.out.println("Unable to read the template SVG 
file!");
                }
                catch (TranscoderException te)
                {
System.out.println("Unable to render the template SVG file to an image!");
            System.exit(1);
                }
        }

        private static boolean overflows(Element textElement)
        {
SVGTextPositioningElement positioning = (SVGTextPositioningElement) textElement; int numberOfChars = ((SVGTextContent) ((SVGOMElement)textElement).getSVGContext()).getNumberOfChars(); SVGRect textBounds = positioning.getExtentOfChar(numberOfChars - 1);
        
        try
        {
                textBounds.getWidth();
                textBounds.getHeight();

                return false;
        }
        catch (DOMException e)
        {
                return true;
        }
        }
}
---

The test svg:
---
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.2" xmlns="http://www.w3.org/2000/svg"; x="0px" y="0px" width="500px" height="500px" viewBox="0 0 500 500"> <flowText xml:space="preserve" xmlns="http://xml.apache.org/batik/ ext" overflow="hidden">
                <flowRegion vertical-align="middle">
                        <rect x="0" y="0" width="500" height="500"/>
                </flowRegion>

                <flowDiv>
<flowPara><flowLine id="test" font-size="72">This is a test paragraph.</flowLine></flowPara>
                </flowDiv>
        </flowText>
</svg>
---

The result will be a 500x500px area that has the text maximized in the flowText region.

Brendon

On Dec 15, 2009, at 2:43 AM, [email protected] wrote:

Hi Brendon,

"Brendon J. Wilson" <[email protected]> wrote on 12/14/2009 09:16:07 PM:

> Interesting, so I've taken your advice but it appears the
> SVGTextPositioningElement.getExtentOfChar method throws a
> NullPointerException [...].

> Is there some other initialization I need to do before
> I attempt to use this method?

   Yes you must boot the SVG & CSS DOM before you
try and use them:
        http://wiki.apache.org/xmlgraphics-batik/BootSvgAndCssDom

>          // Open the SVG template.
> String parser = XMLResourceDescriptor.getXMLParserClassName(); > SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser); > SVGDocument doc = f.createSVGDocument(new File("test.svg").toURI().toString());

    Insert the Initialization code here...

>          Element testElement = doc.getElementById("test");
> SVGTextPositioningElement positioning = (SVGTextPositioningElement)
> testElement;
>              SVGRect testBounds = positioning.getExtentOfChar(3);
>
>
>          if (testBounds != null)
>          {
>             System.out.println("No overflow!");
>              }
>              else
>              {
>             System.out.println("Overflow!");
>          }
>       }
>       catch (IOException ex)
>       {
> System.out.println("Unable to read the template SVG file!");
>       }
>    }
> }
>
> ---
>
> Thanks in advance,
>
> Brendon
>
>
> On Dec 14, 2009, at 5:30 AM, [email protected] wrote:
>
> > Hi Brendon,
> >
> > "Brendon J. Wilson" <[email protected]> wrote on 12/13/2009
> > 11:24:25 PM:
> >
> > > The Desired Result: An area of text that uses the largest font size
> > > possible while still fitting into a given rectangle.
> > >
> > > The Proposed Solution: Use the 'flowroot' element, check for
> > overflow,
> > > and iteratively adjust the font size of the text.
> > >
> > > The Problem: Based on emails from this list dating from 2006, it
> > does
> > > not appear overflow events are implemented, and my alternative
> > > attempts to formulate my own overflow detection mechanism have been
> > > unsuccessful.
> >
> > I haven't checked the recently but my recollection is that there > > were some issues with the way those events were specified that made
> > it problematic to implement them.
> >
> >
> > > but a similar call to attempt to get the bounding box for the laid
> > out
> > > text (I presume, I'm actually shooting in the dark at this point)
> > > results in an uncaught exception:
> > >
> > > ---
> > > SVGElement svgElement = (SVGElement) doc.getElementById("title");
> > > SVGLocatable locatable = (SVGLocatable) svgElement;
> > > SVGRect altbounds = locatable.getBBox();
> >
> >    The problem is that the flowDiv/flowPara/flowSpan implement the
> > SVG Text positioning interface rather than SVG Locatable. You should > > be able to detect overflow by checking if the 'getExtentOfChar' for
> > the last 'printing char' is empty (i.e. the flow text hid it).
> >
> > > Is there another, easier way to figure out the actual dimensions of
> > > the laid out text in a flowDiv, or check the flowRoot for
> > overflow? Or
> > > are overflow events still not implemented?
> >
> > The layout code actually tracks if overflow occurs but it isn't
> > exposed anywhere.  In 'FlowTextPainter.getTextRuns' the 'textWrap'
> > function called at the end returns true if there was overflow, but
> > that return value is propagated anywhere.
> >
>
> Thanks,
>
> Brendon
> ---
> Brendon J. Wilson
> www.brendonwilson.com
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>


Thanks,

Brendon
---
Brendon J. Wilson
www.brendonwilson.com


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to