itext根据模版生成PDF与合并多个PDF以及向已存在PDF增加水印设置权限等操作

    我之前写了一篇文章讲了itext的基础操作常用方法(https://my.oschina.net/itazi/blog/1812042),但是有时涉及到比较复杂的PDF生成,手工操作就很复杂,可以使用模板生成方式。有时还要涉及合并等,于是将用到的略作记载。

   首先要用到的依赖:

 <dependency>
		    <groupId>com.itextpdf</groupId>
		    <artifactId>itextpdf</artifactId>
		    <version>5.5.10</version>
		</dependency>
		
		<dependency>
		    <groupId>com.itextpdf</groupId>
		    <artifactId>itext-asian</artifactId>
		    <version>5.2.0</version>
		</dependency>
		
		<dependency>
		    <groupId>org.bouncycastle</groupId>
		    <artifactId>bcprov-jdk15on</artifactId>
		    <version>1.54</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/com.lowagie/itext -->
		<dependency>
		    <groupId>com.lowagie</groupId>
		    <artifactId>itext</artifactId>
		    <version>2.1.7</version>
		</dependency>

    首先我们来讲讲制作模板,可以查考这个https://www.cnblogs.com/LUA123/p/5108007.html,这里面感觉很详细了,另外特别提到一点,由于要用Adobe制作的话需要购买,所以作为代提方案,你还可以使用福晰PDF软件制作,也可以实现相同效果,亲测可用。制作好模板之后接下来就是根据模板生成PDF,代码如下:

/**
     * 根据模版生成pdf
     * 
     * @param templateFile 模板路径
     * @param targetFile 将要生成的pdf路径
     * @param fieldMap 填充字段
     */
    public static Boolean createPdfFromTemplate(String templateFile, String targetFile, Map<String, String> fieldMap) {
        Boolean retValue = false;
        try {
            /* 打开已经定义好字段以后的pdf模板 */
            com.itextpdf.text.pdf.PdfReader reader = new com.itextpdf.text.pdf.PdfReader(templateFile);

            /* 将要生成的目标PDF文件名称 */
            PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(targetFile));

            PdfContentByte under = stamp.getUnderContent(1);

            /* 使用中文字体 */
            BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
            Font fontChinese = new Font(bf, 12, Font.NORMAL);

            /* 取出报表模板中的所有字段 */
            AcroFields form = stamp.getAcroFields();
            form.addSubstitutionFont(bf);//这行必须添加否则中文不显示

            /* 为字段赋值,注意字段名称是区分大小写的 */
            for (String key : fieldMap.keySet()) {
                form.setField(key, fieldMap.get(key));
            }

            stamp.setFormFlattening(true);
            /* 必须要调用这个,否则文档不会生成的 */
            stamp.close();
            reader.close();
            retValue = true;
        } catch (DocumentException de) {
            System.err.println(de.getMessage());
        } catch (IOException ioe) {
            System.err.println(ioe.getMessage());
        } finally {
            return retValue;
        }
    
    }

    测试代码如下(注意:关于路径你要改成你自己本地的路径,要正确,特别是你制作模板的路径,要填写正确,要不然模板都找不到,谈何制作pdf呢):

Map<String, String> map = new HashMap<String, String>();
        map.put("projectname", "map填充");//这里的projectname是你制作PDF时填入的字段
        map.put("applyname", "shishui??");//同上
        System.out.println(PdfUtils.createPdfFromTemplate("/Users/hxm/Documents/pdf/project_detail_model_wrapper_2.pdf", 
                "/Users/hxm/Documents/pdf/tempalte.pdf", map));

    结果:

填充成功。

    接下来我们来谈谈合并PDF,有时候你有多个PDF,正好需要合并成一个,你可能就需要这个方法了(部分内容参考:https://www.cnblogs.com/pocketbook/p/6427579.html)。代码如下:

/**
     * 合并pdf
     * @param files 要合并的pdf文件
     * @param newfile 生成的文件名
     * @return
     */
    public static Boolean mergePdfFiles(String[] files, String newfile) {
        Boolean retValue = false;  
        Document document = null;  
       try {  
           document = new Document(new PdfReader(files[0]).getPageSize(1));
           PdfCopy copy = new PdfCopy(document, new FileOutputStream(newfile)); 
           document.open();  
           for (int i = 0; i < files.length; i++) {  
               PdfReader reader = new PdfReader(files[i]);  
               int n = reader.getNumberOfPages();  
               for (int j = 1; j <= n; j++) {  
                   document.newPage();  
                   PdfImportedPage page = copy.getImportedPage(reader, j);  
                   copy.addPage(page);  
               }  
           }  
           retValue = true;  
       } catch (Exception e) {  
           e.printStackTrace();  
       } finally {  
           document.close();  
       }  
       return retValue;  
   }  

    测试代码(路径要能和你自己的pdf地址对上):

String[] files = { "/Users/hxm/Documents/pdf/audit.pdf", "/Users/hxm/Documents/pdf/template.pdf"};  
        String savepath = "/Users/hxm/Documents/pdf/newmerge"+ System.currentTimeMillis() +".pdf";  
        PdfTemplateUtil.mergePdfFiles(files, savepath);

结果:

合并成功。

    如果已经存在一个PDF,你想添加某些属性再生成一个新的PDF文件,如增加水印,加密,设置权限等,这时你就又需要一个方法了,代码如下(其中部分参考一个外国小哥的代码):

public static Boolean addAttributeToPdfFile(String strFileLocation, String strFileLocationOut) {
        Boolean isSuccess = false;
        try {
            // read existing pdf
            com.itextpdf.text.pdf.PdfReader reader = new com.itextpdf.text.pdf.PdfReader(strFileLocation);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(strFileLocationOut));

            stamper.setEncryption(null, null, PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128);
            // text watermark
            Font FONT = new Font(Font.FontFamily.HELVETICA, 34, Font.BOLD, new GrayColor(0.5f));
//            Phrase p = new Phrase("Memorynotfound (watermark)", FONT);
            BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            Font font = new Font(bfChinese, 30, Font.BOLD, new GrayColor(0.90f));
            Phrase p = new Phrase("(watermark)", font);

            // image watermark
//            Image img = Image.getInstance(imgUrl);
//            float w = img.getScaledWidth();
//            float h = img.getScaledHeight();

            // properties
            PdfContentByte over;
            Rectangle pagesize;
            float x, y;

            // loop over every page
            int n = reader.getNumberOfPages();
            for (int i = 1; i <= n; i++) {
                // get page size and position
//                pagesize = reader.getPageSizeWithRotation(i);
//                x = (pagesize.getLeft() + pagesize.getRight()) / 2;
//                y = (pagesize.getTop() + pagesize.getBottom()) / 2;
                over = stamper.getUnderContent(i);
                over.saveState();

                // set transparency
                PdfGState state = new PdfGState();
                state.setFillOpacity(0.2f);
                over.setGState(state);

//                ColumnText.showTextAligned(over, Element.ALIGN_CENTER, p, x, y, 0);
                //控制水印的显示效果,可以自己调整看看
                float beginPositionX = 10, beginPositionY = 70, distance = 175;
                for (int i2 = 0; i2 < 4; i2++) {
                    for (int j = 0; j < 4; j++) {
                        ColumnText.showTextAligned(over, Element.ALIGN_LEFT,
                                p, beginPositionX + distance*i2, beginPositionY + distance*j, 25);
                        
                    }
                }
                // add watermark text and image
//                if (i % 2 == 1) {
//                    ColumnText.showTextAligned(over, Element.ALIGN_CENTER, p, x, y, 0);
//                } else {
//                    over.addImage(img, w, 0, 0, h, x - (w / 2), y - (h / 2));
//                }

                over.restoreState();
            }
            stamper.close();
            reader.close();
            isSuccess = true;
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            return isSuccess;
        }
    }

测试代码:

 PdfUtils.addAttributeToPdfFile("/Users/hxm/Documents/pdf/newmerge1527731906780.pdf",
                "/Users/hxm/Documents/pdf/mytemplate.pdf");

效果如下:

    另外注意点是我上面的几个方法都放在一个叫PdfUtils的类中。大概结构如下:

package pdf;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.GrayColor;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
import com.lowagie.text.Document;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
/**
 * pdf工具类
 *
 * @author hxm
 */
public class PdfUtils {
}

    上面就是这些常用方法了,因为要用到本人也网上搜索了很多资料,看了很多,最后特地整理一下,也以备自己以后查询之用处。

猜你喜欢

转载自my.oschina.net/itazi/blog/1822301