2011-03-13 36 views
7

Tengo una clase abstracta con un método abstracto draw (Graphics2D g2) y los métodos print(), showPreview(), printPDF(). Para cada documento en mi programa Java, implemento draw(), así que puedo imprimir, mostrar vista previa y crear un archivo PDF para cada documento. Mi problema es cómo crear un PDF con múltiples páginas desde ese objeto Graphics. Lo resolví creando un archivo PDF para cada página, y luego fusioné los archivos en un archivo nuevo. Pero debe haber una mejor manera. He siguiente código para crear PDF con una página:Cómo crear un PDF con varias páginas desde un objeto Graphics con Java e itext

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()); 
    } 
} 

Respuesta

9
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(); 

Así que usted está haciendo que todo su interfaz de N veces, y sólo muestra una rebanada con tamaño de página de la misma en diferentes lugares. Eso se llama "striping" en el mundo impreso IIRC. Inteligente, pero podría ser más eficiente en PDF.

Render toda la interfaz en una enorme PdfTemplate (con g2d), una vez. A continuación, dibuje esa plantilla en todas sus páginas para que la parte que desea esté visible dentro de los márgenes de la página actual ("cuadro de medios").

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(); 
} 

El espacio de coordenadas de PDF establece 0,0 en la esquina inferior izquierda, y esos valores aumentan a medida que se sube y hacia la derecha. PdfGraphis2D hace una buena cantidad de magia para ocultar esa diferencia, pero todavía tenemos que lidiar con ella un poco aquí ... por lo tanto, las coordenadas negativas en el cuadro delimitador y las ubicaciones de dibujo.

Esta es toda la codificación de "la parte de atrás de la servilleta", y es muy posible que haya cometido un error o dos ahí ... pero esa es la idea.

+0

Muchas gracias, funciona con los siguientes cambios. – Jan

+0

¿Qué cambios? PD: esta es la parte donde haces clic en esa marca hueca junto a la respuesta correcta, para que otras personas sepan quién tenía la razón (y darle cierta reputación a esa persona). "Yo" en este caso. Además, si hace varias preguntas y nunca las marca, otras personas verán su porcentaje de respuestas pobres y será menos probable que se molesten, ya que saben que no les darán rep a pesar de que tengan razón. –

+0

Lo siento Mark, trato de entender cómo funciona este sitio web. No me di cuenta de que el PdfContentByte se puede reutilizar para cada página. Hice los cambios: PdfTemplate template = cb.createTemplate (_pageWidth, entireHeight); g2 = template.createGraphics (_pageWidth, entireHeight); ..... for (int curPg = 1; curPg <= _numberOfPages; ++ curPg) { cb.addTemplate (hugeTempl, 0, -_pageHeight * (_numberOfPages - curPg)); document.newPage(); } – Jan

0

Tuve problemas para seguir el código anterior (algunos de los métodos parecen haber cambiado en la versión itextpdf actual). Aquí está mi solución:

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(); 
    } 
Cuestiones relacionadas