3
votes

I have a project that requires me to place a ID string under some underlined text in a passage of text.

Here is an example using an inline SVG object with a gray border to show the layout:

sample use of SVG inline to simulate inline

I can get close using an inline element with a baseline-shift and then use SVG to render the text. However this has the disadvantage (I think) that I have to manually put in the width of the SVG in pixels, which seems very complicated for such a simple layout.

Here is the XSL-FO markup for this:

<fo:block>
Normal text
<fo:inline baseline-shift="-100%">
    <fo:instream-foreign-object text-align="center" display-align="center" border="solid silver 1px">
        <svg xmlns="http://www.w3.org/2000/svg" height="25" width="120" viewport="0 0 120 25">
            <text x="60" y="10" fill="black" text-anchor="middle" text-decoration="underline" font-size="12pt">underlined text with id</text>
            <text x="60" y="25" fill="black" text-anchor="middle" font-size="12pt">123</text>
        </svg>
    </fo:instream-foreign-object>
</fo:inline>
normal text.
</fo:block>

So my question is: Can I perform this layout in Apache FOP XSL-FO without using instream-foreign-object and SVG? If I can not, is there some way to not have to put the width in the SVG in pixels? Or is there some way to calculate how many pixels the SVG will take to render?

I should also note inline-container is not supported in Apache FOP.

https://xmlgraphics.apache.org/fop/compliance.html

Thanks in advance! - Dan

1
There is not enough information in your question to provide an answer. Example: What happens if the text you are placing this within warps to multiple lines? What happens to the following lines of text ... specifically with the line spacing and the fact that what you are drawing impinges on it? You have not fully thought through this or if you have, you have certainly not given enough information for someone to even recommend solutions.Kevin Brown
I have no experience with what is supported by Apache FOP, but if I was using RenderX I would (1) format the fragments you request to the area tree format (called XEPOUT). From that, you can determine the fragment width and height. Then (2) would either (a) use that fragment as an image (that is supported in RenderX XEP) or (b) you could convert that area tree to SVG and you would know that pixel width you need. We do this is projects to apply SVG gradients to multi-line text that is formatted in the document.Kevin Brown
Hi Kevin, to answer your question the underlined text should work exactly like any other underlined text. It should wrap if it needs to. As I stated in my question, my goal is to do this layout with Apache FOP and without using SVG and without having to manually estimate the width of the text within the SVG. Thanks - DanDan McCreary
Could you use MathML?Christina
Just to clarify then using the example above, let's say the calculated line break occurs at the word "text" ... what does this look like? The words "underlined text" on one line, the words "with id" on the next line and where does the bottom part go? And what does the line spacing look like in all cases since the object you are drawing is larger than the height of a single line? Is the whole paragraph line spacing set to the highest height of this fragment or? Until all the requirements of the possible occurrences are understood, it is not possible to exactly answer.Kevin Brown

1 Answers

2
votes

Here is a sample done as I suggested with RenderX using the formatting tree. Sample Output

Format the desired fragments to the intermediate format ... something like this for a single one:

    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
        <fo:layout-master-set>
            <fo:simple-page-master margin="0mm" master-name="MASTERsite1" page-width="214mm" page-height="29pt">
                <fo:region-body margin="0mm"/>
            </fo:simple-page-master>
        </fo:layout-master-set>    
        <fo:page-sequence master-reference="MASTERsite1">
            <fo:flow flow-name="xsl-region-body">
                <fo:table>
                    <fo:table-body>
                        <fo:table-row>
                            <fo:table-cell><fo:block text-decoration="underline" text-align="center">This is Underlined Text with ID</fo:block></fo:table-cell>
                        </fo:table-row>
                        <fo:table-row>
                            <fo:table-cell><fo:block text-align="center">1234567</fo:block></fo:table-cell>
                        </fo:table-row>
                    </fo:table-body>  
                </fo:table>
            </fo:flow>
        </fo:page-sequence> 
    </fo:root>

The output of that would be this:

    <xep:document xmlns:xep="http://www.renderx.com/XEP/xep" producer="XEP 4.19 build 20110414" creator="Unknown" author="Unknown" title="Untitled">
        <xep:page width="162708" height="29000" page-number="1" page-id="1">
    <xep:word-spacing value="0"/>
    <xep:letter-spacing value="0"/>
    <xep:font-stretch value="1.0"/>
    <xep:font family="Helvetica" weight="400" style="normal" variant="normal" size="12000"/>
    <xep:gray-color gray="0.0"/>
    <xep:text value="This is Underlined Text with ID" x="0" y="18734" width="162708"/>
    <xep:line x-from="0" x-till="162708" y-from="17534" y-till="17534" thickness="600" style="solid"/>
    <xep:text value="1234567" x="58002" y="4334" width="46704"/>
    </xep:page>
    </xep:document>

Where you would modify the result to change the page width, but it's right in the text as the width of the text element of concern, that is change:

 <xep:page width="606614" height="29000" page-number="1" page-id="1">

so the width is from the text line of concern, programmatically pick up the x-till from xep:line or the xep:text line (changing as above). Note, this is exactly equivalent to your SVG example except you have the number programmatically to access right inside this file.

last, using this "file" as an image, one would then use:

 <fo:external-graphic src="test19.xep" content-type="application/xepout" alignment-baseline="central"/>

Now, while you say look at all those steps, this is a solution and all of the above could be automated into a single process chain. First loop through and format all of the objects of concern and make little files from them, then a second pass would instead of formatting those fragments, would use them as images.

Note: The line spacing shown in the attached image of the result cannot be done with FOP (I believe), I think that is a limitation of FOP.

Note #2: I am not a FOP expert and I know nothing of it's implementation, specifically using the area tree as an image in a document. If FOP is a must, I would suggest looking into it. You could just as easily convert the area tree to SVGs and use them as you would be able to use all their dimensions or better just read the area tree into the second transform and generate instream-foreign-object SVGs from it right inline.