[xep-support] Next CoolTool - Scale All to Fit

From: Kevin Brown <kevin@renderx.com>
Date: Mon Mar 08 2010 - 11:06:36 PST

As has been recently discussed in this forum, users need a way to scale down
images to fit within a constrained space in both dimensions. We discussed a
possible solution using the current technology and I have compiled that
discussion and associated files into a single solution set. All is available
for download here:

Just sample XML and XSL without images:

http://www.xportability.com/CoolTools/Scale.zip

The whole package with images:

http://www.xportability.com/CoolTools/ScaleWImages.zip (7MB)

Sample output in various sizes:

http://www.xportability.com/CoolTools/Landscape.pdf (7MB)

http://www.xportability.com/CoolTools/Portrait.pdf (7MB)

http://www.xportability.com/CoolTools/400Square.pdf (7MB)

The basic solution consists of running RenderX in a way to process only the
images and gather information on the actual image size from the XEP
Intermediate Format (XEPOUT). Then one can run RenderX again with the main
style sheet and use that information when formatting the document. This can
of course be done in a tool chain with two commands (instead of one) or
through the API and passing params.

We developed a simple text xml file that just had some paragraphs and
various images throughout the document. These images vary by size and by
type. In order to simplify things we added an attribute in our XML called
scale-all-to-fit. If this attribute was set to 'true', we would process the
image with this technique. Of course, you may do things differently. The
basic idea is to be able to selectively process images because you may have
some that you know the size and wish to process in a different way.

Now, as we had shown, the actual dimensions of images are carried in the
XEPOUT document. The trick here is to have no scaling happen for any reason
so we create a simple XSL that only lays down images without any scaling.
So, we set the page dimensions very large -- bigger than any expected image.
If you look at the "process-images.xsl", it has:

<fo:simple-page-master
        margin-top="0pt"
        margin-left="0pt"
        margin-bottom="0pt"
      margin-right="0pt"
        page-width="100in"
        page-height="100in"
        master-name="huge">

Thus, a 100in x 100in page. We assumed that none of our images would be
larger than this. Then we used a simple template:

    <xsl:template match="image[@scale-all-to-fit = 'true']">
        <fo:block line-height="0pt">
            <fo:external-graphic>
                <xsl:attribute name="src">
                    <xsl:text>url('</xsl:text>
                    <xsl:value-of select="@src"/>
                    <xsl:text>')</xsl:text>
                </xsl:attribute>
            </fo:external-graphic>
        </fo:block>
    </xsl:template>

This template outputs all images marked appropriately in natural size, no
scaling.

Running this against our sample XML would yield this in XEPOUT:

<?xml version="1.0" encoding="UTF-8"?>

<xep:document xmlns:xep="http://www.renderx.com/XEP/xep" producer="XEP
CURRENT build 20100226" creator="Unknown" author="Unknown" title="Untitled">
<xep:page width="7200000" height="7200000" page-number="1" page-id="1">
<xep:gray-color gray="0.0"/>
<xep:image
src="file:/C:/Users/kbrown01/Desktop/Scale-to-fit/product_goodflakes.gif"
type="image/gif" x-from="0" y-from="6835800" scale-x="1.0" scale-y="1.0"
width="225600" height="364200" role="none"/>
<xep:image
src="file:/C:/Users/kbrown01/Desktop/Scale-to-fit/big-peng_00001.jpg"
type="image/jpeg" x-from="0" y-from="4499800" scale-x="1.0" scale-y="1.0"
width="2336000" height="2336000" role="none"/>
<xep:image src="file:/C:/Users/kbrown01/Desktop/Scale-to-fit/circles.svg"
type="image/svg+xml" x-from="0" y-from="4139800" scale-x="1.0" scale-y="1.0"
width="360000" height="360000" role="none"/>
<xep:image src="file:/C:/Users/kbrown01/Desktop/Scale-to-fit/gradients.svg"
type="image/svg+xml" x-from="0" y-from="4079800" scale-x="1.0" scale-y="1.0"
width="60000" height="60000" role="none"/>
<xep:image src="file:/C:/Users/kbrown01/Desktop/Scale-to-fit/gradients2.svg"
type="image/svg+xml" x-from="0" y-from="4019800" scale-x="1.0" scale-y="1.0"
width="60000" height="60000" role="none"/>
<xep:image src="file:/C:/Users/kbrown01/Desktop/Scale-to-fit/4morpap0.png"
type="image/png" x-from="0" y-from="3094061" scale-x="1.0" scale-y="1.0"
width="1068028" height="925739" role="none"/>
<xep:image src="file:/C:/Users/kbrown01/Desktop/Scale-to-fit/clipimage.svg"
type="image/svg+xml" x-from="0" y-from="2909809" scale-x="1.0" scale-y="1.0"
width="340157" height="184252" role="none"/>
<xep:image
src="file:/C:/Users/kbrown01/Desktop/Scale-to-fit/blank-world-map.jpg"
type="image/png" x-from="0" y-from="2737009" scale-x="1.0" scale-y="1.0"
width="302400" height="172800" role="none"/>
<xep:image src="file:/C:/Users/kbrown01/Desktop/Scale-to-fit/380009505.jpg"
type="image/jpeg" x-from="0" y-from="2448259" scale-x="1.0" scale-y="1.0"
width="768000" height="288750" role="none"/>
</xep:page>
</xep:document>

As you can see, each image in here in an XML document with exact width and
height values. These are in units of XEPOUT ... each unit is 1/1000th of a
point (.001pt_). So the "big-peng_00001.jpg" above is 2336pt x 2336pt.

Now, this XEPOUT document is used as a map within the main XSL. We developed
a plug-in XSLT that with a template for scale-all-to-fit. The
"scale-all-to-fit.xsl" takes in the fit-size and the XEPOUT file and then
does some logic on what fits.

Using the document() function and simple XSLT on the structure, one can
extract real width and height for each image. Given a particular image
"src":

<xsl:variable name="image-width"
        select="($xepdoc//xep:image[contains(@src, $image-name)]/@width) div
1000"/>
<xsl:variable name="image-height"
        select="($xepdoc//xep:image[contains(@src, $image-name)]/@height)
div 1000"/>

Then it is a matter of determining:

1) Does the image fit both width and height?
2) Does the image fit height and not width?
3) Does the image fit width and not height?
4) Does the image not fit width nor height?

In case 4, the image fit and actual dimensions are evaluated to determine
which ratio is larger and the dimension with the largest ratio of (actual
size/fit size) is used for the scale to fit.

Calling this template from the main XSL is easy. You do have to determine
what your fit dimensions are. You can of course guess larger but in the
simplest of cases you should know. In our simple document, we even added a
keep for the caption that has a height (of course) and ensured the fit space
would always keep the caption on the page with the image. The call to the
template is:

    <xsl:template match="image[@scale-all-to-fit = 'true']">
        <fo:block line-height="0pt" text-align="center"
background-color="silver">
        <xsl:call-template name="scale-image-to-fit">
            <xsl:with-param name="xepdoc" select="$xepdoc"/>
            <xsl:with-param name="fit-height">
                <xsl:value-of select="$page-height - $margin-top -
$margin-bottom - $caption-height"/>
            </xsl:with-param>
            <xsl:with-param name="fit-width">
                <xsl:value-of select="$page-width - $margin-left -
$margin-right"/>
            </xsl:with-param>
            <xsl:with-param name="image-name" select="@src"/>
        </xsl:call-template>
        </fo:block>
        <fo:block space-before="3pt" text-align="center"
keep-with-previous.within-column="always" font-size="10pt"
font-weight="bold" font-style="italic">
            <xsl:value-of select="@caption"/>
        </fo:block>
    </xsl:template>

All of this was executed from a simple bat file. In the case of some users
who are dynamically generating PDFs, certainly the XEPOUT file can be
generated in memory and passed as a param to the second transformation. A
simple .bat file for this would be:

@echo off
set CP=C:\Program Files (x86)\RenderX\XEP\lib\xep.jar;C:\Program Files
(x86)\RenderX\XEP\lib\saxon.jar;C:\Program Files
(x86)\RenderX\XEP\lib\xt.jar
"C:\Program Files (x86)\Java\jre6\bin\java" -Xmx1024M -classpath "%CP%"
com.renderx.xep.XSLDriver "-DCONFIG=C:\Program Files
(x86)\RenderX\XEP\xep.xml" -xml %1 -xsl %2 -xep image.xep
"C:\Program Files (x86)\Java\jre6\bin\java" -Xmx1024M -classpath "%CP%"
com.renderx.xep.XSLDriver "-DCONFIG=C:\Program Files
(x86)\RenderX\XEP\xep.xml" -xml %1 -xsl %3 -pdf
del image.xep

where:

%1 is the XML file ("test.xml")
%2 is "process-images.xsl"
%3 is the main XSL file ("test.xsl")

The XEPOUT file is generated automatically as "image.xep", used in the
second transformation and then deleted. The "extra" first transformation to
XEPOUT take 0.1 secs for this document.

Hope this helps out some folks on their issues. We've added the
scale-*-to-fit into the marketing requirements planning and we'll see where
they fall into development and release. But as you can see from the
examples, this can be implemented today to yield great results.

Kevin Brown
RenderX

-------------------
(*) To unsubscribe, send a message with words 'unsubscribe xep-support'
in the body of the message to majordomo@renderx.com from the address
you are subscribed from.
(*) By using the Service, you expressly agree to these Terms of Service http://www.renderx.com/terms-of-service.html
Received on Mon Mar 8 11:27:15 2010

This archive was generated by hypermail 2.1.8 : Mon Mar 08 2010 - 11:27:23 PST