莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

          iText操作PDF問題總結

          Posted on 2007-04-02 15:52 dennis 閱讀(12826) 評論(9)  編輯  收藏 所屬分類: java
              這個星期我的任務就是處理一些報表的打印問題,因為我算項目組里對jasperreport比較熟悉的了,這個東東也是我引進到這個項目。ireport畫報表,使用struts的action輸出PDF到瀏覽器,這是我們目前的解決方案。今天遇到一個ireport解決不了的要求——合并單元格。類似下面這樣的表結構:
          ----------------------------------------------
                    |          |__c_____________
             dept   | value    |__b_____________
                    |          |  a
          --------------------------------------------------------
          也就是需要跨行,跨列!-_-。在html表格中解決這個很簡單,只要設置單元格的colspan和rowspan即可。我在ireport沒有找到解決方案,如果您知道,請不吝賜教。查找資料弄了兩個小時沒進展,決定自己用iText寫吧,通過google、baidu資料順利達到了我的要求,僅在此記錄下遇到的問題和解決方法。

          一。一個HelloWorld實例:
          package com.lowagie.examples.general;

            
          import java.io.FileOutputStream;
            
          import java.io.IOException;

            
          import com.lowagie.text.*;
            
          import com.lowagie.text.pdf.PdfWriter;

            
          /**
             * Generates a simple 'Hello World' PDF file.
             *
             * 
          @author blowagie
             
          */

            
          public class HelloWorld {

              
          /**
               * Generates a PDF file with the text 'Hello World'
               *
               * 
          @param args no arguments needed here
               
          */
              
          public static void main(String[] args) {

                System.out.println(
          "Hello World");

                
          // step a: creation of a document-object
                Document document = new Document();
                
          try {
                  
          // step b:
                  
          // we create a writer that listens to the document
                  
          // and directs a PDF-stream to a file
                  PdfWriter.getInstance(document,new FileOutputStream("HelloWorld.pdf"));

                  
          // step c: we open the document
                  document.open();
                  
          // step d: we add a paragraph to the document
                  document.add(new Paragraph("Hello World"));
                } 
          catch (DocumentException de) {
                  System.err.println(de.getMessage());
                } 
          catch (IOException ioe) {
                  System.err.println(ioe.getMessage());
                }

                
          // step e: we close the document
                  document.close();
                }
              }
          可以看到一個PDF文件的輸出,總共只需要5個步驟
          a.創(chuàng)建一個Document實例
            Document document = new Document();
          b.將Document實例和文件輸出流用PdfWriter類綁定在一起
            PdfWriter.getInstance(document,new FileOutputStream("HelloWorld.pdf"));
          c.打開文檔
            document.open();
          d.在文檔中添加文字
            document.add(new Paragraph("Hello World"));
          e.關閉文檔
            document.close();
          這樣5個步驟,就可以生成一個PDF文檔了。

          二。如何使用jsp、servlet輸出iText生成的pdf?
            如果每次都在服務端生成一個PDF文件給用戶,不僅麻煩,而且浪費服務器資源,最好的方法就是以二進制流的形式輸送到客戶端。
          1)JSP輸出:
          <%@ page import="java.io.*,java.awt.Color,com.lowagie.text.*,com.lowagie.text.pdf.*"%>

          <%
          response.setContentType
          "application/pdf" );
          Document document 
          = new Document();
          ByteArrayOutputStream buffer
          = new ByteArrayOutputStream();
          PdfWriter writer
          =
          PdfWriter.getInstance( document, buffer );
          document.open();
          document.add(
          new Paragraph("Hello World"));
          document.close();
          DataOutput output 
          =
          new DataOutputStream
          ( response.getOutputStream() );
          byte[] bytes = buffer.toByteArray();
          response.setContentLength(bytes.length);
          forint i = 0;
          < bytes.length;
          i
          ++ )
          {
          output.writeByte( bytes[i] );
          }
          %>

          2)servlet輸出,稍微改造下就可以使用在struts中:
          import java.io.*;
          import javax.servlet.*;
          import javax.servlet.http.*;
          import com.lowagie.text.*;
          import com.lowagie.text.pdf.*;
          public void doGet
          (HttpServletRequest request,
          HttpServletResponse response)
          throws IOException,ServletException
          {
          Document document 
          =
          new Document(PageSize.A4, 36,36,36,36);
          ByteArrayOutputStream ba
          = new ByteArrayOutputStream();
          try
          {
          PdfWriter writer 
          =
          PdfWriter.getInstance(document, ba);
          document.open();
          document.add(
          new
          Paragraph(
          "Hello World"));
          }
          catch(DocumentException de)
          {
          de.printStackTrace();
          System.err.println
          (
          "A Document error:" +de.getMessage());
          }
          document.close();
          response.setContentType
          (
          "application/pdf");
          response.setContentLength(ba.size());
          ServletOutputStream out
          = response.getOutputStream();
          ba.writeTo(out);
          out.flush();
          }


          三。如何輸出中文?
              首先需要下載iTextAsian.jar包,可以到iText的主站上下,ireport也是需要這個包的。然后定義中文字體:
              private static final Font getChineseFont() {
                  Font FontChinese 
          = null;
                  
          try {
                      BaseFont bfChinese 
          = BaseFont.createFont("STSong-Light",
                              
          "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                      FontChinese 
          = new Font(bfChinese, 12, Font.NORMAL);
                  } 
          catch (DocumentException de) {
                      System.err.println(de.getMessage());
                  } 
          catch (IOException ioe) {
                      System.err.println(ioe.getMessage());
                  }
                  
          return FontChinese;
              }

          我將產(chǎn)生中文字體封裝在方法內(nèi),自定義一個段落PDFParagraph繼承自Paragraph,默認使用中文字體:
          class PDFParagraph extends Paragraph {
                  
          public PDFParagraph(String content) {
                      
          super(content, getChineseFont());
                  }
              }

          使用的時候就可以簡化了:

          Paragraph par = new PDFParagraph("你好");

          四。如何設置PDF橫向顯示和打印?

          Rectangle rectPageSize = new Rectangle(PageSize.A4);// 定義A4頁面大小
          rectPageSize = rectPageSize.rotate();// 加上這句可以實現(xiàn)A4頁面的橫置
          Document doc = new Document(rectPageSize,50,50,50,50);//4個參數(shù),設置了頁面的4個邊距

          五。如何設置跨行和跨列?

          使用PdfPTable和PdfPCell 是沒辦法實現(xiàn)跨行的,只能跨列,要跨行使用com.lowagie.text.Table和com.lowagie.text.Cell類,Cell類有兩個方法:setRowspan()和setColspan()。

          六。如何設置單元格邊界寬度?

          Cell類的系列setBorderWidthXXXX()方法,比如setBorderWidthTop(),setBorderWidthRight()等

          七。如何設置表頭?
          希望每一頁都有表頭,可以通過設置表頭來實現(xiàn)。對于PdfPTable類來說,可以這樣設置:
          PdfPTable table = new PdfPTable(3);
          table.setHeaderRows(
          2); // 設置了頭兩行為表格頭

          而對于om.lowagie.text.Table類,需要在添加完所有表頭的單元格后加上一句代碼:
          table.endHeaders();

          八。如何設置列寬?

          Table table = new Table(8);
          float[] widths = { 0.10f0.15f0.21f0.22f0.08f0.08f0.10f,
                              
          0.06f };
          table.setWidths(widths);

          上面的代碼設置了一個有8列的表格,通過一個float數(shù)組設置列寬,這里是百分比。

          九。單元格內(nèi)段落文字居中和換行?
          居中通過Cell類來設置,一開始我以為設置段落對齊就可以了,沒想到是需要設置單元格:

          cell.setHorizontalAlignment(Element.ALIGN_CENTER);


          轉義符\n實現(xiàn)。在我的這個應用中,因為數(shù)據(jù)庫取出的數(shù)據(jù)是為了顯示在html上的,所以有很多<br>標簽,可以使用正則表達式替換成"\n"
          "<br>1.測試<br>2.測試2".replaceAll("<br>|</br>","\n");

          十。如何顯示頁碼?
          復雜的頁碼顯示和水印添加,需要使用到PdfPageEventHelper、PdfTemplate等輔助類,具體的例子參見iText的文檔,如果只是為了簡單的顯示頁數(shù),可以使用下面的代碼:
                      HeaderFooter footer = new HeaderFooter(new Phrase("頁碼:",getChineseFont()), true);
                      footer.setBorder(Rectangle.NO_BORDER);
                      document.setFooter(footer);
                      document.open();
          你可能注意到了,添加footer需要在document.open之前。

          評論

          # re: iText操作PDF問題總結  回復  更多評論   

          2007-04-04 08:51 by 祎恬凡
          對于你開始那個結構,你又沒想過用子報表將其分割!!!
          不知道子報表是否可行!!

          # re: iText操作PDF問題總結[未登錄]  回復  更多評論   

          2007-04-04 08:56 by dennis
          @祎恬凡

          這個我早就試過,沒辦法做到的,因為跨行的單行高度與子報表關聯(lián),又沒辦法動態(tài)設置行高

          # re: iText操作PDF問題總結  回復  更多評論   

          2007-04-30 10:30 by 葉之韻律
          終于找到一個稍微有點建設性的文章了,可惜還是沒提到我需要解決的問題:動態(tài)換行。簡單地說就是,如果某一行有個字段的數(shù)據(jù)過長,我想把該字段自動換行,同時把該行的所有字段的高度撐大。我在iReport把Stretch Type的Relavive to band height選上,并且把Stretch with overflow給勾上后,預覽JrViewer時保存為PDF文件,如果有一個字段太長了,就可以自動把該字段所在行的整行換行;但如果用代碼輸出為pdf時,需要換行的字段卻不顯示出來,并且整行也不換行了。請教一下,這個問題應該怎么解決呢?

          # re: iText操作PDF問題總結  回復  更多評論   

          2007-05-08 15:15 by dennis
          @葉之韻律
          似乎沒辦法解決,我的處理方法就是將field的length和height相應增大,字段總有一個最大長度!-_-

          # re: iText操作PDF問題總結  回復  更多評論   

          2007-06-28 10:07 by Melinda
          葉之韻律:
          屬性中的position type應該選成float

          # re: iText操作PDF問題總結  回復  更多評論   

          2008-06-06 11:12 by xmzzy
          請問下,用iReport導出到word后,原來<textarea>中的大段文字的換行符會在導出的word里顯示成<br>,這個問題如何解決?

          # re: iText操作PDF問題總結  回復  更多評論   

          2012-07-09 17:08 by 閆曉盼
          如何設置表頭內(nèi)容???

          # re: iText操作PDF問題總結  回復  更多評論   

          2012-07-09 17:13 by 閆曉盼
          明白了……對自己無解了,嘿嘿,

          # 換行  回復  更多評論   

          2013-08-09 13:56 by 張志明
          換行成兩行 的高度是一行的高度兩倍怎么換
          主站蜘蛛池模板: 东明县| 视频| 平谷区| 临江市| 成武县| 青田县| 隆林| 柳州市| 句容市| 敦煌市| 红原县| 博野县| 三明市| 綦江县| 玉屏| 金门县| 梁河县| 汾西县| 包头市| 龙胜| 巩义市| 平原县| 闵行区| 龙南县| 明水县| 安新县| 道孚县| 湖北省| 呼玛县| 高雄县| 丰顺县| 古交市| 德钦县| 庆元县| 浦县| 天津市| 金湖县| 伊川县| 理塘县| 洛浦县| 历史|