【问题标题】:How to create a PDF with multiple pages from a Graphics object with Java and itext如何使用 Java 和 itext 从 Graphics 对象创建具有多个页面的 PDF
【发布时间】:2011-07-14 11:59:40
【问题描述】:

我有一个带有抽象方法 draw(Graphics2D g2) 和方法 print()、showPreview()、printPDF() 的抽象类。对于我的 Java 程序中的每个文档,我实现了 draw(),因此我可以打印、显示预览并为每个文档创建一个 PDF 文件。 我的问题是如何从该 Graphics 对象创建具有多个页面的 PDF。 我通过为每一页创建一个 PDF 文件来解决它,然后将这些文件合并到一个新文件中。但必须有更好的方法。 我有以下代码来创建一页 PDF:

public void printPDF1(){
    JFileChooser dialog = new JFileChooser();
    String filePath = "";
    int dialogResult = dialog.showSaveDialog(null);
    if (dialogResult==JFileChooser.APPROVE_OPTION){
        filePath = dialog.getSelectedFile().getPath();
    }
    else return;
    try {
        Document document = new Document(new Rectangle(_pageWidth, _pageHeight));
        PdfWriter writer = PdfWriter.getInstance(document,
                new FileOutputStream(filePath));
        document.open();

        PdfContentByte cb = writer.getDirectContent();
        g2 = cb.createGraphics(_pageWidth, _height);
        g2.translate(0, (_numberOfPages - _pageNumber) * _pageHeight);
        draw(g2);
        g2.dispose();
        document.close();
    } 
    catch (Exception e2) {
        System.out.println(e2.getMessage());
    }
}

【问题讨论】:

    标签: java pdf itext


    【解决方案1】:
        document.open();
    
        // the same contentByte is returned, it's just flushed & reset during
        // new page events.
        PdfContentByte cb = writer.getDirectContent();
    
        for (int _pageNumber = 0; _pageNumber < _numberofPages; ++_numberOfPages) {
          /*******************/
          //harmless in first pass, *necessary* in others
          document.newPage(); 
          /*******************/
    
          g2 = cb.createGraphics(_pageWidth, _height);
          g2.translate(0, (_numberOfPages - _pageNumber) * _pageHeight);
          draw(g2);
          g2.dispose();
        }
    
        document.close();
    

    因此,您将整个界面渲染 N 次,并且仅在不同位置显示页面大小的一部分。这在印刷世界 IIRC 中称为“条带化”。聪明,但它在 PDF 中可能更有效。

    一次将您的整个界面渲染成一个巨大的 PdfTemplate(使用 g2d)。然后将该模板绘制到您的所有页面中,以便您想要的部分在当前页面的边距内可见(“媒体框”)。

    PdfContentByte cb = writer.getDirectContent();
    float entireHeight = _numberOfPages * _pageHeight;
    PdfTemplate hugeTempl = cb.createTemplate( 0, -entireHeight, pageWidth, _pageHeight );
    g2 = hugeTempl.createGraphics(0, -entireHeight, _pageWidth, _pageHeight ); 
    draw(g2);
    g2.dispose();
    
    for (int curPg = 0; curPg < _numberOfPages; ++curPg) {
      cb.addTemplateSimple( hugeTempl, 0, -_pageHeight * curPg );
    
      document.newPage();
    }
    

    PDF 的坐标空间在左下角设置为 0,0,这些值会随着您向上和向右而增加。 PdfGraphis2D 做了相当多的魔法来隐藏你的差异,但我们仍然需要在这里处理它......因此边界框和绘图位置中的负坐标。

    这都是“餐巾纸背面”的编码,我完全有可能在其中犯了一两个错误……但就是这样。

    【讨论】:

    • 有哪些变化? PS:这是您单击正确答案旁边的空心复选标记的部分,让其他人知道谁是对的(并给那个人一些声誉)。在这种情况下是“我”。此外,如果您提出多个问题并且从未将它们标记为已回答,那么其他人会看到您的回答率很低并且不太可能打扰,因为他们知道即使他们是对的也不会给他们代表。
    • 对不起,马克,我试图了解这个网站是如何运作的。我没有意识到 PdfContentByte 可以重复用于每一页。我做了这些更改: PdfTemplate template = cb.createTemplate(_pageWidth, wholeHeight); g2 = template.createGraphics(_pageWidth, wholeHeight); ..... for (int curPg = 1; curPg
    • 不用担心。我会将您的“评论中的代码”标记为更多相同的内容。欢迎来到 SO。 Ignorance is curable, but stupid is forever. 总是乐于治愈一些无知。
    • @MarkStorer 我正在使用您在此答案中提供的第二个代码 sn-p。不知何故,我得到的只是最后一页的内容。有什么解决办法吗?
    • 您只是一遍又一遍地看到最后一页,还是只有最后一页有内容?
    【解决方案2】:

    我在执行上述代码时遇到了问题(当前 itextpdf 版本中的某些方法似乎已更改)。这是我的解决方案:

    import com.itextpdf.awt.PdfGraphics2D;
    import com.itextpdf.text.Document;
    import com.itextpdf.text.PageSize;
    import com.itextpdf.text.pdf.PdfContentByte;
    import com.itextpdf.text.pdf.PdfTemplate;
    import com.itextpdf.text.pdf.PdfWriter;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics2D;
    import java.awt.event.WindowEvent;
    import java.io.FileOutputStream;
    import java.io.OutputStream;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import net.miginfocom.swing.MigLayout;
    
    public class PanelToPDF {
    
        private static JFrame frame= new JFrame();
        private static JPanel view= new JPanel();
        private static float pageWidth= PageSize.A4.getWidth();
        private static float pageHeight= PageSize.A4.getHeight();
    
        public static void main(String[] args) throws Exception {
            System.out.println("Page width = " + pageWidth + ", height = " + pageHeight);
    
            initPane();
            createMultipagePDF();
    
            frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
        }
    
    
        private static void initPane() {
            view.setLayout(new MigLayout());
            view.setBackground(Color.WHITE);
    
            for (int i= 1; i <= 160; ++i) {
                JLabel label= new JLabel("This is a test! " + i);
                label.setForeground(Color.BLACK);
                view.add(label, "wrap");
    
                JPanel subPanel= new JPanel();
                subPanel.setBackground(Color.RED);
                view.add(subPanel);
            }
    
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(new Dimension(Math.round(pageWidth), Math.round(pageHeight)));
            frame.add(view);
            frame.setVisible(true);
        }
    
        private static void createMultipagePDF() throws Exception {
            // Calculate the number of pages required. Use the preferred size to get
            // the entire panel height, rather than the panel height within the JFrame
            int numPages= (int) Math.ceil(view.getPreferredSize().height / pageHeight); // int divided by float
    
            // Output to PDF
            OutputStream os= new FileOutputStream("test.pdf");
            Document doc= new Document();
            PdfWriter writer= PdfWriter.getInstance(doc, os);
            doc.open();
            PdfContentByte cb= writer.getDirectContent();
    
            // Iterate over pages here
            for (int currentPage= 0; currentPage < numPages; ++currentPage) {
                doc.newPage(); // not needed for page 1, needed for >1
    
                PdfTemplate template= cb.createTemplate(pageWidth, pageHeight);
                Graphics2D g2d= new PdfGraphics2D(template, pageWidth, pageHeight * (currentPage + 1));
                view.printAll(g2d);
                g2d.dispose();
    
                cb.addTemplate(template, 0, 0);
            }
    
            doc.close();
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-04
      • 1970-01-01
      • 2015-03-25
      • 2013-11-28
      相关资源
      最近更新 更多