How to use itext to span 2 columnns of a page?

2019-06-03 14:34发布

问题:

I am trying to do the following using itext and java through eclipse.I need to create a PDF which will consist of a no of multiple choice questions retrieved from database.The data retrieved is in the form of html tags hence for that i am using xml worker to parse it.I am able to retrieve the questions one by one from the database and add it to the pdf.But the problem is that it occupies only one side of a page while i need the questions to cover 2 columns of a page.

When the end of the first PDF page is reached it should utilize the right hand corner of the first PDF page to add questions.Only when both left and right sides of a page are fully used it should move on to the next PDF page.

Now i managed to get the html data in 2 columns using ColumnText.But the problem i face now is that the questions retrieved from database do not appear in the format as intended.Each question is getting displayed on one line.

I entered the questions is this format:

1)What is 2+2=?

a)2

b)4

c)8

d)15

I want that the output on pdf should be as above.

However i get the following as output:

1)What is2+2=?a)2b)4c)8d)15

How do i preserve the html formatting ?????????

This is my code so far:

 import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;

import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.List;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.LineSeparator;
import com.itextpdf.tool.xml.ElementHandler;
import com.itextpdf.tool.xml.ElementList;
import com.itextpdf.tool.xml.Pipeline;
import com.itextpdf.tool.xml.Writable;
import com.itextpdf.tool.xml.XMLWorker;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.itextpdf.tool.xml.html.Tags;
import com.itextpdf.tool.xml.parser.XMLParser;
import com.itextpdf.tool.xml.pipeline.WritableElement;
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;

public class ColumnTextExample {
    public static final float[][] COLUMNS = {
         { 36, 36, 224, 579 } , { 230, 36, 418, 579 }

        };
public static void main(String[] args)throws IOException, DocumentException, ClassNotFoundException, SQLException {
        // TODO Auto-generated method stub
        Document document = new Document(PageSize.A4.rotate());

        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("C:\\columns.pdf"));

        document.open();


        Class.forName("com.mysql.jdbc.Driver");
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test3", "root", "root");
        Statement st=con.createStatement();
        ResultSet rs=st.executeQuery("select * from exam2");
        int size=0;
        while (rs.next()){
        size++;
        };

        ResultSet rs1=st.executeQuery("select * from exam2");
        String[] myStringArray = new String[size];
        int i=0;
        while (rs1.next()){
           myStringArray[i]=rs1.getString("paper");
           i++;
     }

        ColumnText ct = new ColumnText(writer.getDirectContent());
        for (String article : myStringArray) {

           ct.addElement(createPhrase(article,writer,document));

            ct.addElement(Chunk.NEWLINE);
            document.add(Chunk.NEWLINE);
     }
        ct.setAlignment(Element.ALIGN_CENTER);
        ct.setExtraParagraphSpace(55);
        ct.setLeading(0, 1.2f);
        ct.setFollowingIndent(27);
        int linesWritten = 0;
        int column = 0;
        int status = ColumnText.START_COLUMN;
        while (ColumnText.hasMoreText(status)) {
            ct.setSimpleColumn(
                    COLUMNS[column][0], COLUMNS[column][1],
                    COLUMNS[column][2], COLUMNS[column][3]);
            ct.setYLine(COLUMNS[column][3]);
            status = ct.go();
            linesWritten += ct.getLinesWritten();
            column = Math.abs(column - 1);
            if (column == 0)
                document.newPage();
        }

        ct.addElement(new Phrase("Lines written: " + linesWritten));
        ct.go();
        document.close();
    }
 public static  Phrase createPhrase(String myString, PdfWriter writer, Document document) throws IOException, DocumentException {
        Phrase p = new Phrase();
        String myString2=myString+"<html><body><br></br></body></html>";
        String k="<br></br>";
        XMLWorkerHelper xwh = XMLWorkerHelper.getInstance();
        InputStream is = new ByteArrayInputStream(myString.getBytes());
        ElementList myList = new ElementList();
        ElementList myList1 = new ElementList();
      xwh.parseXHtml(myList,new StringReader(myString2));

      p.addAll(myList);

  return p;
}
    }

When i use XMLWorkerHelper.getInstance().parseXHtml(writer, document, new StringReader(name1)); i am able to preserve the html formatting such as new line.

The below code helps me retrieve html data from DB and parse it while preserving the formatting.However it prints to the pdf in a single column

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.StringReader;

import com.itextpdf.text.Document;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import  com.itextpdf.tool.xml.XMLWorkerHelper;
import java.io.ByteArrayInputStream;
import java.sql.*;


public class GeneratePDF {
    public static void main(String[] args) {
        try {
             OutputStream file = new FileOutputStream(new File("C:\\Test.pdf"));
            Document document = new Document();
            PdfWriter writer = PdfWriter.getInstance(document, file);
            document.open();

                 Class.forName("com.mysql.jdbc.Driver");
                   Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test3", "root", "root");
                   Statement st=con.createStatement();

                   ResultSet rs=st.executeQuery("select paper from exam2 ");
                   String name1="";
                   while (rs.next()){
                       String name = rs.getString("paper");
                       //out.println(name);
                       name1=name;


            /*String k="<h1 style='text-align: center;'><strong>Maths&nbsp;Question2 Paper</strong></h1>"+
"<pre><strong>1)What is the sum of 2+2??<br /></strong><strong>a)3<br /></strong><strong>b)5<br /></strong><strong>c)4<br /></strong><strong>d)1</strong></pre>"+
"<pre><strong>2)What is the sum of 5+2??<br /></strong><strong>a)3<br />b)5<br />c)7<br />d)1</strong></pre>"+
"<pre>&nbsp;</pre>";*/
                   System.out.println(name1);

            //InputStream is = new ByteArrayInputStream(name1.getBytes());
            XMLWorkerHelper.getInstance().parseXHtml(writer, document, new StringReader(name1));
                   }


            document.close();
            file.close();
        } catch (Exception e) {
            e.printStackTrace();
}}} 

回答1:

You're parsing the HTML to a Document. This means you want iText to organize all content on one page, using one column defined by the page size (in your case A4) and the page margins (in your case 36pt on each side).

If you want to organize the content differently, you should use the parseXHTML() method that takes an ElementHandler as parameter and pass an ElementList object. This list will then contain a List of Element objects that you can feed to a ColumnText object. With the ColumnText class, you can define multiple rectangles on a page, and use the go() method to fill these rectangles with the content from the ElementList.



标签: itext