Dynamic Document Generation: PDF from DOCX - Unsatisfactory Font conversion

Hi,

We are using the Dynamic Document Generation plugin (version 1.5.1) to convert a DOCX to a PDF, but have noticed that the font is not being carried over as part of the conversion. The resultant PDF uses Times New Roman for the font, rather than using the same font as the source DOCX file (which is Arial).

Digging a bit further into the plugin, I see that it uses Apache FOP 2.1 - which has some documentation on Font conversion: https://xmlgraphics.apache.org/fop/2.1/fonts.html

When FOP does not have a specific font at its disposal (because it's not installed in the operating system or set up in FOP's configuration), the font is replaced with "any". "any" is internally mapped to the Base-14 font "Times"

Can missing fonts be installed onto an Appian Cloud server?

Does the plugin allow another font mapping to be specified?

  Discussion posts and replies are publicly visible

Parents
  • mikej117 As aloks176  mentioned XSLFO is the perfect option for you there you can get desired fonts, background colors, margins page numbers, footers etc. The below is the example code. Use this code and try to modify it to requirements.

    XML file:

    <?xml version="1.0" encoding="UTF-8"?>
    <!--Anagrafica del clienti del mercato-->
    <?xml-stylesheet type="application/xml" href="ElencoConSoluzioni.xslt"?>
    <anagrafica>
    	<testata>
    		<nomemercato id="007">Mercato di test</nomemercato>
    		<data>Giovedi 18 dicembre 2003 16.05.29</data>
    	</testata>
    	<record>
    		<codice_cliente>5</codice_cliente>
    		<rag_soc>Miami American Cafe</rag_soc>
    		<codice_fiscale>IT07654930130</codice_fiscale>
    		<indirizzo tipo="casa">Viale Carlo Espinasse 5, Como</indirizzo>
    		<num_prodotti>13</num_prodotti>
    		<sconto>si</sconto>
    	</record>
    	<record>
    		<codice_cliente>302</codice_cliente>
    		<rag_soc>Filiberto Gilardi</rag_soc>
    		<codice_fiscale>IT87654770157</codice_fiscale>
    		<indirizzo tipo="ufficio">Via Biancospini 20, Messina</indirizzo>
    		<num_prodotti>8</num_prodotti>
    	</record>
    	<record>
    		<codice_cliente>1302</codice_cliente>
    		<rag_soc>Eidon</rag_soc>
    		<codice_fiscale>IT887511231</codice_fiscale>
    		<indirizzo tipo="ufficio">Via Bassini 17/2, Milano</indirizzo>
    		<num_prodotti>18</num_prodotti>
    	</record>
    	<record>
    		<codice_cliente>202</codice_cliente>
    		<rag_soc>SkillNet</rag_soc>
    		<codice_fiscale>IT887642131</codice_fiscale>
    		<indirizzo tipo="ufficio">Via Chiasserini 11A, Milano</indirizzo>
    		<num_prodotti>24</num_prodotti>
    	</record>
    	<record>
    		<codice_cliente>12</codice_cliente>
    		<rag_soc>Eidon</rag_soc>
    		<codice_fiscale>04835710965</codice_fiscale>
    		<indirizzo tipo="casa">Via Cignoli 17/2, Roma</indirizzo>
    		<num_prodotti>1112</num_prodotti>
    	</record>
    </anagrafica>
    

     

    XSL file:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
    	<xsl:output encoding="UTF-8" indent="yes" method="xml" standalone="no" omit-xml-declaration="no"/>
    	<xsl:template match="anagrafica">
    		<fo:root language="IT">
    			<fo:layout-master-set>
    				<fo:simple-page-master master-name="A4-portrail" page-height="297mm" page-width="210mm" margin-top="5mm" margin-bottom="5mm" margin-left="5mm" margin-right="5mm">
    					<fo:region-body margin-top="25mm" margin-bottom="20mm"/>
    					<fo:region-before region-name="xsl-region-before" extent="25mm" display-align="before" precedence="true"/>
    				</fo:simple-page-master>
    			</fo:layout-master-set>
    			<fo:page-sequence master-reference="A4-portrail">
    				<fo:static-content flow-name="xsl-region-before">
    					<fo:table table-layout="fixed" width="100%" font-size="10pt" border-color="black" border-width="0.4mm" border-style="solid">
    						<fo:table-column column-width="proportional-column-width(20)"/>
    						<fo:table-column column-width="proportional-column-width(45)"/>
    						<fo:table-column column-width="proportional-column-width(20)"/>
    						<fo:table-body>
    							<fo:table-row>
    								<fo:table-cell text-align="left" display-align="center" padding-left="2mm">
    									<fo:block>
    										<xsl:value-of select="testata/nomemercato/@id"/>
    										<xsl:value-of select="testata/nomemercato"/>
    									</fo:block>
    								</fo:table-cell>
    								<fo:table-cell text-align="center" display-align="center">
    									<fo:block font-size="150%">
    										<fo:basic-link external-destination="http://dometec.homeip.net">LISTA PRODOTTI</fo:basic-link>
    									</fo:block>
    									<fo:block space-before="3mm"/>
    								</fo:table-cell>
    								<fo:table-cell text-align="right" display-align="center" padding-right="2mm">
    									<fo:block>
    										<xsl:value-of select="testata/data"/>
    									</fo:block>
    									<fo:block display-align="before" space-before="6mm">Pag <fo:page-number/> di <fo:page-number-citation ref-id="end-of-document"/>
    									</fo:block>
    								</fo:table-cell>
    							</fo:table-row>
    						</fo:table-body>
    					</fo:table>
    				</fo:static-content>
    				<fo:flow flow-name="xsl-region-body" border-collapse="collapse" reference-orientation="0">
    					<fo:block>Lista dei fornitori di cibo buono</fo:block>
    					<fo:table table-layout="fixed" width="100%" font-size="10pt" border-color="black" border-width="0.35mm" border-style="solid" text-align="center" display-align="center" space-after="5mm">
    						<fo:table-column column-width="proportional-column-width(20)"/>
    						<fo:table-column column-width="proportional-column-width(30)"/>
    						<fo:table-column column-width="proportional-column-width(25)"/>
    						<fo:table-column column-width="proportional-column-width(50)"/>
    						<fo:table-body font-size="95%">
    							<fo:table-row height="8mm">
    								<fo:table-cell>
    									<fo:block>Cod.Cliente</fo:block>
    								</fo:table-cell>
    								<fo:table-cell>
    									<fo:block>Ragione Sociale</fo:block>
    								</fo:table-cell>
    								<fo:table-cell>
    									<fo:block>Codice Fiscale/P.IVA</fo:block>
    								</fo:table-cell>
    								<fo:table-cell>
    									<fo:block>Indirizzo</fo:block>
    								</fo:table-cell>
    							</fo:table-row>
    							<xsl:for-each select="record">
    								<fo:table-row>
    									<fo:table-cell>
    										<fo:block>
    											<xsl:value-of select="codice_cliente"/>
    										</fo:block>
    									</fo:table-cell>
    									<fo:table-cell>
    										<fo:block>
    											<xsl:value-of select="rag_soc"/>
    										</fo:block>
    									</fo:table-cell>
    									<fo:table-cell>
    										<fo:block>
    											<xsl:value-of select="codice_fiscale"/>
    										</fo:block>
    									</fo:table-cell>
    									<fo:table-cell>
    										<fo:block>
    											<xsl:value-of select="indirizzo"/>
    										</fo:block>
    									</fo:table-cell>
    								</fo:table-row>
    							</xsl:for-each>
    						</fo:table-body>
    					</fo:table>
    					<fo:block id="end-of-document">
    						<fo:instream-foreign-object>
    							<svg width="200mm" height="150mm" version="1.1" xmlns="http://www.w3.org/2000/svg">
    								<path d="M153 334
    C153 334 151 334 151 334
    C151 339 153 344 156 344
    C164 344 171 339 171 334
    C171 322 164 314 156 314
    C142 314 131 322 131 334
    C131 350 142 364 156 364
    C175 364 191 350 191 334
    C191 311 175 294 156 294
    C131 294 111 311 111 334
    C111 361 131 384 156 384
    C186 384 211 361 211 334
    C211 300 186 274 156 274" style="fill:yellow;stroke:red;stroke-width:2"/>
    							</svg>
    						</fo:instream-foreign-object>
    					</fo:block>
    				</fo:flow>
    			</fo:page-sequence>
    		</fo:root>
    	</xsl:template>
    </xsl:stylesheet>
    

    Output Pdf:

Reply
  • mikej117 As aloks176  mentioned XSLFO is the perfect option for you there you can get desired fonts, background colors, margins page numbers, footers etc. The below is the example code. Use this code and try to modify it to requirements.

    XML file:

    <?xml version="1.0" encoding="UTF-8"?>
    <!--Anagrafica del clienti del mercato-->
    <?xml-stylesheet type="application/xml" href="ElencoConSoluzioni.xslt"?>
    <anagrafica>
    	<testata>
    		<nomemercato id="007">Mercato di test</nomemercato>
    		<data>Giovedi 18 dicembre 2003 16.05.29</data>
    	</testata>
    	<record>
    		<codice_cliente>5</codice_cliente>
    		<rag_soc>Miami American Cafe</rag_soc>
    		<codice_fiscale>IT07654930130</codice_fiscale>
    		<indirizzo tipo="casa">Viale Carlo Espinasse 5, Como</indirizzo>
    		<num_prodotti>13</num_prodotti>
    		<sconto>si</sconto>
    	</record>
    	<record>
    		<codice_cliente>302</codice_cliente>
    		<rag_soc>Filiberto Gilardi</rag_soc>
    		<codice_fiscale>IT87654770157</codice_fiscale>
    		<indirizzo tipo="ufficio">Via Biancospini 20, Messina</indirizzo>
    		<num_prodotti>8</num_prodotti>
    	</record>
    	<record>
    		<codice_cliente>1302</codice_cliente>
    		<rag_soc>Eidon</rag_soc>
    		<codice_fiscale>IT887511231</codice_fiscale>
    		<indirizzo tipo="ufficio">Via Bassini 17/2, Milano</indirizzo>
    		<num_prodotti>18</num_prodotti>
    	</record>
    	<record>
    		<codice_cliente>202</codice_cliente>
    		<rag_soc>SkillNet</rag_soc>
    		<codice_fiscale>IT887642131</codice_fiscale>
    		<indirizzo tipo="ufficio">Via Chiasserini 11A, Milano</indirizzo>
    		<num_prodotti>24</num_prodotti>
    	</record>
    	<record>
    		<codice_cliente>12</codice_cliente>
    		<rag_soc>Eidon</rag_soc>
    		<codice_fiscale>04835710965</codice_fiscale>
    		<indirizzo tipo="casa">Via Cignoli 17/2, Roma</indirizzo>
    		<num_prodotti>1112</num_prodotti>
    	</record>
    </anagrafica>
    

     

    XSL file:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
    	<xsl:output encoding="UTF-8" indent="yes" method="xml" standalone="no" omit-xml-declaration="no"/>
    	<xsl:template match="anagrafica">
    		<fo:root language="IT">
    			<fo:layout-master-set>
    				<fo:simple-page-master master-name="A4-portrail" page-height="297mm" page-width="210mm" margin-top="5mm" margin-bottom="5mm" margin-left="5mm" margin-right="5mm">
    					<fo:region-body margin-top="25mm" margin-bottom="20mm"/>
    					<fo:region-before region-name="xsl-region-before" extent="25mm" display-align="before" precedence="true"/>
    				</fo:simple-page-master>
    			</fo:layout-master-set>
    			<fo:page-sequence master-reference="A4-portrail">
    				<fo:static-content flow-name="xsl-region-before">
    					<fo:table table-layout="fixed" width="100%" font-size="10pt" border-color="black" border-width="0.4mm" border-style="solid">
    						<fo:table-column column-width="proportional-column-width(20)"/>
    						<fo:table-column column-width="proportional-column-width(45)"/>
    						<fo:table-column column-width="proportional-column-width(20)"/>
    						<fo:table-body>
    							<fo:table-row>
    								<fo:table-cell text-align="left" display-align="center" padding-left="2mm">
    									<fo:block>
    										<xsl:value-of select="testata/nomemercato/@id"/>
    										<xsl:value-of select="testata/nomemercato"/>
    									</fo:block>
    								</fo:table-cell>
    								<fo:table-cell text-align="center" display-align="center">
    									<fo:block font-size="150%">
    										<fo:basic-link external-destination="http://dometec.homeip.net">LISTA PRODOTTI</fo:basic-link>
    									</fo:block>
    									<fo:block space-before="3mm"/>
    								</fo:table-cell>
    								<fo:table-cell text-align="right" display-align="center" padding-right="2mm">
    									<fo:block>
    										<xsl:value-of select="testata/data"/>
    									</fo:block>
    									<fo:block display-align="before" space-before="6mm">Pag <fo:page-number/> di <fo:page-number-citation ref-id="end-of-document"/>
    									</fo:block>
    								</fo:table-cell>
    							</fo:table-row>
    						</fo:table-body>
    					</fo:table>
    				</fo:static-content>
    				<fo:flow flow-name="xsl-region-body" border-collapse="collapse" reference-orientation="0">
    					<fo:block>Lista dei fornitori di cibo buono</fo:block>
    					<fo:table table-layout="fixed" width="100%" font-size="10pt" border-color="black" border-width="0.35mm" border-style="solid" text-align="center" display-align="center" space-after="5mm">
    						<fo:table-column column-width="proportional-column-width(20)"/>
    						<fo:table-column column-width="proportional-column-width(30)"/>
    						<fo:table-column column-width="proportional-column-width(25)"/>
    						<fo:table-column column-width="proportional-column-width(50)"/>
    						<fo:table-body font-size="95%">
    							<fo:table-row height="8mm">
    								<fo:table-cell>
    									<fo:block>Cod.Cliente</fo:block>
    								</fo:table-cell>
    								<fo:table-cell>
    									<fo:block>Ragione Sociale</fo:block>
    								</fo:table-cell>
    								<fo:table-cell>
    									<fo:block>Codice Fiscale/P.IVA</fo:block>
    								</fo:table-cell>
    								<fo:table-cell>
    									<fo:block>Indirizzo</fo:block>
    								</fo:table-cell>
    							</fo:table-row>
    							<xsl:for-each select="record">
    								<fo:table-row>
    									<fo:table-cell>
    										<fo:block>
    											<xsl:value-of select="codice_cliente"/>
    										</fo:block>
    									</fo:table-cell>
    									<fo:table-cell>
    										<fo:block>
    											<xsl:value-of select="rag_soc"/>
    										</fo:block>
    									</fo:table-cell>
    									<fo:table-cell>
    										<fo:block>
    											<xsl:value-of select="codice_fiscale"/>
    										</fo:block>
    									</fo:table-cell>
    									<fo:table-cell>
    										<fo:block>
    											<xsl:value-of select="indirizzo"/>
    										</fo:block>
    									</fo:table-cell>
    								</fo:table-row>
    							</xsl:for-each>
    						</fo:table-body>
    					</fo:table>
    					<fo:block id="end-of-document">
    						<fo:instream-foreign-object>
    							<svg width="200mm" height="150mm" version="1.1" xmlns="http://www.w3.org/2000/svg">
    								<path d="M153 334
    C153 334 151 334 151 334
    C151 339 153 344 156 344
    C164 344 171 339 171 334
    C171 322 164 314 156 314
    C142 314 131 322 131 334
    C131 350 142 364 156 364
    C175 364 191 350 191 334
    C191 311 175 294 156 294
    C131 294 111 311 111 334
    C111 361 131 384 156 384
    C186 384 211 361 211 334
    C211 300 186 274 156 274" style="fill:yellow;stroke:red;stroke-width:2"/>
    							</svg>
    						</fo:instream-foreign-object>
    					</fo:block>
    				</fo:flow>
    			</fo:page-sequence>
    		</fo:root>
    	</xsl:template>
    </xsl:stylesheet>
    

    Output Pdf:

Children
  • Thanks , the sample code is useful to illustrate what would be required.

    Unfortunately, I don't think that my client would like to go down this path as it requires some fairly technical work to produce a template for the required PDF. They currently produce around 10 different PDF output files with quite different contents, so they want to keep the complexity to a minimum.
  • TL;DR: if you have a non-cloud environment, you have more options than DynamicDocGen. Aspose.Words is what eventually worked for us, but it is not free. The rest of this is here in case anyone gets the opportunity to take this further for the shared component.

    I took a stab at finding a DynamicDocGen solution for my current client since maintaining fonts (without potential security issues of closed-source 3rd-party libraries) was a big deal to them. Maintaining a XMLFO XML as the template is somewhat of a non-starter in this particular situation. So I had the opportunity to test changes to this shared component since they have a non-cloud environment. However, I was time-boxed to 3 days of development, and couldn't get a final working version of DynamicDocGen in time.

    There are 3 basic parts to the Docx --> PDF generation for this plugin.
    1- Ingest a word doc to POJOs
    2- Convert the ingested data to XMLFO format. Under the covers this uses Apache FOP, which is why the changes in v1.5.1 of DynamicDocGen (use v2.1 of FOP) are important.
    3- Use Apache FOP to generate the PDF (v2.1 of FOP).

    Following the instructions on the Apache FOP website, I was able to embed a FOP xml configuration into the deployed jar which included the system auto-detect flag. I then used the class loader's getAsResourceStream to find the XML configuration and pass it into steps 2 & 3 by adding the configuration to the fopFactory construction via the static{} block of the XMLFO utility class. I was able to verify that step 3 received the configuration and could detect the 200-something system fonts. (hint: you can set the logging levels of individual FOP classes via that static block).

    However, step 2 proved much trickier. I could verify that Docx4j properly parsed the fonts in Step 1 (they were in the Mapper object). Yet I couldn't get the FOP used in Step 2 to actually use the custom FOP configuration. The dev environment wasn't setup for remote debugging, so I didn't get an opportunity to dig deep into the stack traces. The logs for step 2 effectively showed that the FOUserAgent couldn't find associated font names wherever it was searching for them and was substituting them with 'Any'. Therefore Step 3 would always use Times New Roman. It should be noted that the FopFactory in Step 2 is NOT the same FopFactory used in Step 3, but rather, it is the fopFactory that Docx4j constructs itself.

    Hope this helps someone in the future!
    Regards,
    Jesse