首页 文章

如何使用Java和itext从Graphics对象创建包含多个页面的PDF

提问于
浏览
8

我有一个抽象类,抽象方法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());
    }
}

2 回答

  • 0
    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做了相当多的魔术来隐藏与你的区别,但我们仍然需要在这里处理它...因此在边界框和绘图位置中的负坐标 .

    这完全是“背面的卫生巾”编码,我完全有可能在那里犯了一两个错误......但这就是主意 .

  • 9

    我在遵循上面的代码时遇到了麻烦(某些方法在当前的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();
        }
    

相关问题