Why is text truncated in PDF with Linux?

2020-02-14 05:18发布

问题:

I try to format a Date in Jasper Reports and it works with Windows but not with Linux. With Linux the resulting text is truncated.

Code:

JRXML:

<parameter name="timestamp" class="java.util.Date"/>
[...]
<textField>
    <reportElement x="0" y="0" width="50" height="16" uuid="0007846a-26f1-457a-a198-67a2f7c8417c">
        <property name="local_mesure_unitwidth" value="pixel"/>
        <property name="com.jaspersoft.studio.unit.width" value="px"/>
        <property name="local_mesure_unitx" value="pixel"/>
        <property name="com.jaspersoft.studio.unit.x" value="px"/>
        <property name="local_mesure_unity" value="pixel"/>
        <property name="com.jaspersoft.studio.unit.y" value="px"/>
        <property name="local_mesure_unitheight" value="pixel"/>
        <property name="com.jaspersoft.studio.unit.height" value="px"/>
    </reportElement>
    <box padding="2"/>
    <textElement textAlignment="Left" verticalAlignment="Top">
        <font size="8" pdfFontName="Helvetica" pdfEncoding="Cp1250" isPdfEmbedded="true"/>
    </textElement>
    <textFieldExpression><![CDATA[DATEFORMAT($P{timestamp},"dd.MM HH:mm")]]></textFieldExpression>
</textField>

Maven dependencies:

<dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports</artifactId>
    <version>5.6.0</version>
</dependency>
<dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports-functions</artifactId>
    <version>5.6.0</version>
</dependency>

Java:

private byte[] createPdf() {

    try {
        InputStream is = getClass().getResourceAsStream("MyReport.jasper");
        JasperReport jasperReport = (JasperReport) JRLoader.loadObject(is);
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("timestamp", new Date());
        JRDataSource jrDataSource = new JRBeanCollectionDataSource(new Vector(), false);
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, jrDataSource);
        byte[] pdf = JasperExportManager.exportReportToPdf(jasperPrint);
        return pdf;
    } catch (JRException e) {
        throw new RuntimeException("Could not create PDF.", e);
    }
}

Results:

Result with Windows:

Result with Linux:

PDF properties:

Both generated PDF files have the same font properties in Acrobat Reader for Windows:

As you can see, the font is not embedded. (Second font "Helvetica" disappears if I add dependency jasperreports-fonts and remove attributes pdfFontName, pdfEncodingand isPdfEmbedded).

Research:

I read:

  • PDF generated with jasperreport not showing well on Linux but yes on Mac, could the os be related?
  • http://community.jaspersoft.com/questions/527138/pdf-text-truncated-linux-fine-windows
  • http://community.jaspersoft.com/questions/803503/why-text-filed-value-will-be-truncated-if-application-running-linux

and the solution seems to be to embed the font, but it doesn't work.

I use font "Helvetica" which is one of the default fonts and that's the reason, see Wikipedia:

These fonts, or suitable substitute fonts with the same metrics, must always be available in all PDF readers and so need not be embedded in a PDF

and https://stackoverflow.com/a/27345103/5277820:

If you use these fonts in iText, iText will ignore the embedded parameter, because it is safe to assume that Adobe Reader and other viewers can render these fonts correctly.

Question:

Why have the same font different widths with Windows and Linux? Or why is the text truncating and/or line wrapping different?

回答1:

To calculate the font-metrics correctly, the font needs to be available to the java virtual macchine.

See this historical question: Font is not available to the JVM with Jasper Reports, that show various solution to the old error launched

However the correct solution with jasper-reports is to use font-extensions

If you use the distributed jasperreports-font.jar it contains these fonts:

DejaVu Sans
DejaVu Serif
DejaVu Sans Mono

You need to use one of these in font name example fontName="DejaVu Sans", there is no automatic mapping to other fonts, the jar physically contains only these .ttf and no other (open jar and verify for different version of jasper-reports).

Hence only font installed on the pc or included in font-extension are available for the JVM.

If you need other fonts, the best solution is to generate your own font-extension including a valid .ttf font this can be done from within the IDE.



回答2:

Never assume a particular font is available on a client system – gone are the days when there were only a couple of desktop operating systems on the market, available in a handful of western languages, with well-known lists of fonts that were stable for decades.

It's now much easier to create new fonts, users access content in their own language (with language-specific fonts), the industry launches new form factors every few years (with new vanity fonts), Unicode.org releases new specifications (that require overhauling existing fonts) and as a result the actual fonts present on different systems vary widely.

OSX and Windows still function somewhat in the old "fixed font list" mode, but newer entrants don't.

For PDFs, that means you have to embed fonts in the documents. For the web, that means flexible site design that does not depend on exact pixel letter dimensions.

Trying to use an old legacy font like Helvetica or Arial is a pathologic case: either the client won't have it installed at all, and will alias it to something with different glyph metrics, or it will have an ancient version, that is lacking all the codepoints added since ASCII went out of favour, and won't be able to render modern international text. Arial is a bit more likely to work due to long windows dominance, but that's eroding quickly.