【问题标题】:How to use embedded Fonts to call the Graphics2D.drawString(...) with iText (DefaultFontMapper?)如何使用嵌入式字体通过 iText 调用 Graphics2D.drawString(...)(DefaultFontMapper?)
【发布时间】:2012-09-28 14:32:19
【问题描述】:

要生成有效的 PDF/X 文档,必须嵌入所有字体。不知何故,我无法在 Graphics2D 上下文中使用这些字体。

这个单元测试显示了问题(注释行是我做的一些测试):

import java.awt.Font;
import java.awt.Graphics2D;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Map.Entry;

import org.junit.Test;

import com.itextpdf.awt.DefaultFontMapper;
import com.itextpdf.awt.DefaultFontMapper.BaseFontParameters;
import com.itextpdf.awt.PdfGraphics2D;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfWriter;

public class TestFont
{

    @Test
    public void shouldBeAbleToAddFountsAndDrawOnCanvas() throws FileNotFoundException, DocumentException
    {
        final DefaultFontMapper mapper = new DefaultFontMapper();
        mapper.insertDirectory(".");

        final PrintStream out2 = new PrintStream(System.out);
        for (final Entry<String, BaseFontParameters> entry : mapper.getMapper().entrySet())
        {
            out2.println(String.format("%s: %s", entry.getKey(), entry.getValue().fontName));
        }
        out2.flush();

        final float width = 150;
        final float height = 150;

        final Document document = new Document(new Rectangle(width, height));
        final PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("fonts.pdf"));
        writer.setPDFXConformance(PdfWriter.PDFX32002);

        document.open();
        final Graphics2D g2d = new PdfGraphics2D(writer.getDirectContent(), width, height, mapper);

        g2d.setFont(new Font("Comicate", Font.PLAIN, 12));

        g2d.drawString("Hello world", 5, 24);

        g2d.dispose();

        document.close();
    }

}

它会抛出一个带有消息的PdfXConformanceException:“必须嵌入所有字体。这不是:Helvetica。

我已经浏览了PdfGraphics2D 类以检查setFont() 实现,并发现将使用FontMapper。我已经将它添加到上面的单元测试中。

public void setFont(Font f) {
    if (f == null)
        return;
    if (onlyShapes) {
        font = f;
        return;
    }
    if (f == font)
        return;
    font = f;
    fontSize = f.getSize2D();
    baseFont = getCachedBaseFont(f);
}

private BaseFont getCachedBaseFont(Font f) {
    synchronized (baseFonts) {
        BaseFont bf = (BaseFont)baseFonts.get(f.getFontName());
        if (bf == null) {
            bf = fontMapper.awtToPdf(f);
            baseFonts.put(f.getFontName(), bf);
        }
        return bf;
    }
}

单元测试基于 iText in Action 书中的this exampleHere 是关于 FontMapper 的一些其他示例。

要运行单元测试,您需要此依赖项:

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.3.2</version>
</dependency>

您可以找到here 的自定义字体(位于“.”中)。

控制台输出向我显示了这一点(以识别字体名称):

Comicate: ./COMICATE.TTF

【问题讨论】:

    标签: java itext


    【解决方案1】:

    我不确定纠正代码中错误的确切方法,但有一些简单的解决方法:

    解决方法 1) 创建一个 BufferedImage 来完成所有图形绘制。然后您可以使用所有普通的java.awt.Graphics 函数,例如drawStringsetColor,而不管iText,完成后只需将图像绘制为PDF。警告您在缩放时会降低文本质量,但这里有一个示例:

    //create doccument and writer    
    Rectangle pagesize = new Rectangle(200, 100);
    Document document= new Document(pagesize);
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("C:\\sample.pdf"));
    
    BufferedImage bf = new BufferedImage(BorderWidth, BorderHeight, BorderWidth);
    //Do all graphics code here, draw strings and images etc
        //Some code to set font (java.awt.Font)
        //Some code to draw string
        //Some code to draw image?
    
    //Convert BufferedImage to Image
    Image img = (Image)bf;
    //draw image to PDF using writer
    writer.getDirectContentUnder().addImage(img);
    

    解决方法 2)这使用 iText 功能来绘制字符串,无需创建任何图形对象,使用 BaseFont 处理字体如下:

    //create doccument and writer    
    Rectangle pagesize = new Rectangle(200, 100);
    Document document= new Document(pagesize);
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("C:\\sample.pdf"));
    
    document.open();
    //This sample uses the "GOTHIC.TTF" font file located in the "Template" package
    BaseFont bf = BaseFont.createFont(GUI.class.getClass().getResource("/Template/GOTHIC.TTF") + "", BaseFont.WINANSI, BaseFont.EMBEDDED);
    
    //set font type, size and color
    Font font = new Font(bf, 13.5f);
    
    PdfContentByte canvas = writer.getDirectContent();
    
    canvas.beginText();
    canvas.setFontAndSize(bf, 10);
    //Method Usage: showTextAligned(Align, String, x, y, rotation);
    canvas.showTextAligned(Element.ALIGN_TOP, "My Text Here", 75, 40, 0);
    canvas.endText();
    
    document.close();
    

    我知道这并不能给出您正在寻找的答案,但是如果您只是绘制少量文本,那么解决方法 2 效果很好,我之前使用过类似于解决方法 2 的东西。如果这没有帮助,那么我相信布鲁诺会得到答案。

    【讨论】:

    • 您好,感谢您的建议。可悲的是我不能利用你的解决方法:(。不是我调用 g2d.drawText(...),它是 JFreechart。
    • 你能看看这里的问题吗? stackoverflow.com/q/52736441/3169868
    【解决方案2】:

    通过定义新的BaseFont(s)并实现FontMapper()的接口>>> public BaseFont awtToPdf(java.awt.Font font)。这将应用嵌入到 pdf 中的 awt.font(s)。

    在下面的示例中,我“打印”g2D(包括“drawString”方法),在外部类中绘制。结果是导出的矢量 pdf,仅嵌入了“ArialMT”和“Arial-BoldMT”字体。

    preview img

        PdfWriter pdfWriter = null;
        try {
            pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(file));
            document.open();
            BaseFont fontRegular = BaseFont.createFont("C:\\Windows\\Fonts\\arial_0.ttf", "Cp1251", BaseFont.EMBEDDED);
            BaseFont fontBold = BaseFont.createFont("C:\\Windows\\Fonts\\arialbd_0.ttf", "Cp1251", BaseFont.EMBEDDED);
            FontMapper fontMapper = new FontMapper() {
    
                @Override
                public java.awt.Font pdfToAwt(BaseFont arg0, int arg1) {
                    // TODO Auto-generated method stub
                    return null;
                }
    
                @Override
                public BaseFont awtToPdf(java.awt.Font font) {
                    if (font.equals(Fonts.getFontRegular10()) || font.equals(Fonts.getFontRegular12())){
                        return fontRegular;
                    }
                    else {
                        return fontBold;
                    }
                }
            };
            PdfContentByte cb = pdfWriter.getDirectContent();
            PdfTemplate template = cb.createTemplate(MainFrame.getFRAME_WIDTH(), MainFrame.getFRAME_HEIGHT());
            Graphics2D g2D = new PdfGraphics2D(template, MainFrame.getFRAME_WIDTH(), MainFrame.getFRAME_HEIGHT(), fontMapper);
            MainFrame.getPanel().print(g2D);
            g2D.dispose();
            cb.addTemplate(template, 0, 0);
        }
        catch (Exception e1) {
            e1.printStackTrace();
        }
        finally {
            document.close();
        }
    

    【讨论】:

    • 使用 itext 创建 PDF 的唯一可行解决方案,将 .tff 文件放在可运行的 Jar 中
    猜你喜欢
    • 1970-01-01
    • 2016-08-29
    • 2015-12-04
    • 1970-01-01
    • 2010-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-12
    相关资源
    最近更新 更多