java操作pdf之iText快速入门

java操作pdf之iText快速入门

iText是著名的开放项目,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。

iText官网: http://itextpdf.com/

官网示例: http://itextpdf.com/examples/

更多示例: https://kb.itextpdf.com/home/it5kb/examples

Maven依赖:

    <!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
    <dependency>
      <groupId>com.itextpdf</groupId>
      <artifactId>itextpdf</artifactId>
      <version>5.5.13</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
    <dependency>
      <groupId>com.itextpdf</groupId>
      <artifactId>itext-asian</artifactId>
      <version>5.2.0</version>
    </dependency>

pdf和iText简介

第一个iText示例:Hello World

public class HelloWorld {

    public static final String RESULT
            = "src/main/resources/hello.pdf";

    /**
     * 创建一个pdf文件: hello.pdf
     */
    public static void main(String[] args)
            throws DocumentException, IOException {
        new HelloWorld().createPdf(RESULT);
    }

    //五个步骤
    public void createPdf(String filename)
            throws DocumentException, IOException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        document.add(new Paragraph("Hello World!"));
        // step 5
        document.close();
    }
}

自定义页面大小

通过 Document构造函数来设置页面的大小尺寸和 页面边距。

Document(Rectangle pageSize, float marginLeft, float marginRight, float marginTop, float marginBottom)

其中通过 Rectangle(宽,高)来指定pdf页面的尺寸大小,通过marginLeft marginRight marginTop marginBottom来设置页面边距.

 Rectangle pagesize = new Rectangle(216f, 720f);

 Document document = new Document(pagesize, 36f, 72f, 108f, 180f);

或者

通过PageSize.LETTER来指定页面的大小。在实际开发中PageSize.A4使用的比较多。如果构造不指定的话默认就是PageSize.A4 页边距全是36pt。

在这里插入图片描述

Document document = new Document(PageSize.LETTER);

常用属性

		 //设置作者
        document.addAuthor("ZBK");
        //设置创建日期
        document.addCreationDate();
        // 设置创建者
        document.addCreator("张宝奎");
        // 设置生产者
        document.addProducer();
        // 设置关键字
        document.addKeywords("my");
        //设置标题
        document.addTitle("标题");
        //设置主题
        document.addSubject("主题");

最大页面尺寸

public class HelloWorldMaximum {
    public static final String RESULT = "src/main/resources/hello_maximum.pdf";

    public static void main(String[] args)
            throws DocumentException, IOException {
        // 第一步
        //最大页面尺寸
        Document document = new Document(new Rectangle(14400, 14400));
        // 第二步
        PdfWriter writer =PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // 改变用户单位 UserUnit是定义默认用户空间单位的值。最小UserUnit为1(1个单位= 1/72英寸)。最大UserUnit为75,000。
        writer.setUserunit(75000f);
        // step 3
        document.open();
        // step 4
        document.add(new Paragraph("Hello World"));
        // step 5
        document.close();
    }

}

横向显示pdf

通过**rotate()**方法

Document document = new Document(PageSize.LETTER.rotate());

或者

通过设置

Document document = new Document(new Rectangle(792, 612));

设置页边距和装订格式

​ 对于需要装订成册的多页pdf,如果是左右装订(正反面打印)的话我们第一页的左边距要与第二页的右边距一样,第一页的右边距要与第二页的左边距一样,也就是保证页边距要对称。

通过 setMargins设置页边距,通过setMarginMirroring(true) 来设置两页的边距对称

注意: 如果是上下装订的方式装订,则通过**setMarginMirroringTopBotton(true)**来设置两页的边距对称.

public class HelloWorldMirroredMargins {

    public static final String RESULT
            = "src/main/resources/hello_mirrored_margins.pdf";
    
    public static void main(String[] args)
            throws DocumentException, IOException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        document.setPageSize(PageSize.A5);
        document.setMargins(36, 72, 108, 180);
        document.setMarginMirroring(true);  //设置边距对称
        // step 3
        document.open();
        // step 4
        document.add(new Paragraph(
                "The left margin of this odd page is 36pt (0.5 inch); " +
                        "the right margin 72pt (1 inch); " +
                        "the top margin 108pt (1.5 inch); " +
                        "the bottom margin 180pt (2.5 inch)."));
        Paragraph paragraph = new Paragraph();
        paragraph.setAlignment(Element.ALIGN_JUSTIFIED);
        for (int i = 0; i < 20; i++) {
            paragraph.add("Hello World! Hello People! " +
                    "Hello Sky! Hello Sun! Hello Moon! Hello Stars!");
        }
        document.add(paragraph);
        document.add(new Paragraph(
                "The right margin of this even page is 36pt (0.5 inch); " +
                        "the left margin 72pt (1 inch)."));
        // step 5
        document.close();
    }
}

内存中操作pdf文件

public class HelloWorldMemory {

    public static final String RESULT = "src/main/resources/hello_memory.pdf";

    public static void main(String[] args)
            throws DocumentException, IOException {
        // step 1
        Document document = new Document();
        // step 2
        // we'll create the file in memory
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PdfWriter.getInstance(document, baos);
        // step 3
        document.open();
        // step 4
        document.add(new Paragraph("Hello World!"));
        // step 5
        document.close();

        // let's write the file in memory to a file anyway
        FileOutputStream fos = new FileOutputStream(RESULT);
        fos.write(baos.toByteArray());
        fos.close();
    }
}

设置pdf版本

通过PdfWriter 的 setPdfVersion 方法来设置我们pdf的版本号

public class HelloWorldVersion_1_7 {

    public static final String RESULT = "src/main/resources/hello_1_7.pdf";
    
    public static void main(String[] args)
        throws DocumentException, IOException {
        // step 1
        Document document = new Document();
        // step 2
        // Creating a PDF 1.7 document
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        writer.setPdfVersion(PdfWriter.VERSION_1_7);
        // step 3
        document.open();
        // step 4
        document.add(new Paragraph("Hello World!"));
        // step 5
        document.close();
    }
}

添加内容

添加内容也有两个方法

  • 往Document类中添加high-level的对象
  • 直接用PdfWriter实例添加比较low-level的数据。
public class HelloWorldDirect {

    public static final String RESULT = "src/main/resources/hello_direct.pdf";

    public static void main(String[] args)
            throws DocumentException, IOException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // step 3
        document.open();
        // step 4
        PdfContentByte canvas = writer.getDirectContentUnder();
        writer.setCompressionLevel(0);
        canvas.saveState();                               // q
        canvas.beginText();                               // BT
        canvas.moveText(36, 788);                         // 36 788 Td
        canvas.setFontAndSize(BaseFont.createFont(), 12); // /F1 12 Tf
        canvas.showText("Hello World");                   // (Hello World)Tj
        canvas.endText();                                 // ET
        canvas.restoreState();                            // Q
        // step 5
        document.close();
    }
}

和以前代码不同的是:我们将生成的PdfWriter实例保存到局部变量writer中。因为后续要通过此writer来获取canvas画线画图。代码中通过设置CompressionLevel属性为0可以避免对输出流的压缩,我们也可以通过记事本来查看pdf的语法语句。以上canvas的每个方法后面的注释对应具体的pdf语法,大家用记事本打开就可以看到。

在这里插入图片描述

压缩多个pdf文件

通过ZipEntry 将多个pdf压缩成一个压缩文件

public class HelloZip {

    public static final String RESULT = "src/main/resources/hello.zip";

    public static void main(String[] args)
            throws DocumentException, IOException {
        // creating a zip file with different PDF documents
        ZipOutputStream zip =
                new ZipOutputStream(new FileOutputStream(RESULT));
        for (int i = 1; i <= 3; i++) {
            ZipEntry entry = new ZipEntry("hello_" + i + ".pdf");
            zip.putNextEntry(entry);

            // step 1
            Document document = new Document();
            // step 2
            PdfWriter writer = PdfWriter.getInstance(document, zip);
            writer.setCloseStream(false);
            // step 3
            document.open();
            // step 4
            document.add(new Paragraph("Hello " + i));
            // step 5
            document.close();

            zip.closeEntry();
        }
        zip.close();
    }
}

添加新页

document.newPage();  

添加水印

文字水印
public class PdfWaterMark {
    public static final String RESULT = "src/main/resources/font_water_mark.pdf";

    public static void main(String[] args) throws FileNotFoundException, DocumentException {

        Document document = new Document();
        PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // 打开文档
        document.open();
        // 加入水印
        PdfContentByte waterMar = pdfWriter.getDirectContentUnder();
        // 开始设置水印
        waterMar.beginText();
        // 设置水印透明度
        PdfGState gs = new PdfGState();
        // 设置填充字体不透明度为0.4f
        gs.setFillOpacity(0.4f);
        try {
            // 设置水印字体参数及大小                                  (字体参数,字体编码格式,是否将字体信息嵌入到pdf中(一般不需要嵌入),字体大小)
            waterMar.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED), 60);
            // 设置透明度
            waterMar.setGState(gs);
            // 设置水印对齐方式 水印内容 X坐标 Y坐标 旋转角度
            waterMar.showTextAligned(Element.ALIGN_RIGHT, "www.newland.com", 500, 430, 45);
            // 设置水印颜色
            waterMar.setColorFill(BaseColor.GRAY);
            //结束设置
            waterMar.endText();
            waterMar.stroke();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 加入文档内容
        document.add(new Paragraph("my first pdf demo"));
        // 关闭文档
        document.close();
        pdfWriter.close();
    }

}

在这里插入图片描述

图片水印
public class PdfWaterMark {
    public static final String RESULT = "src/main/resources/img_water_mark.pdf";

    public static void main(String[] args) throws FileNotFoundException, DocumentException {

        Document document = new Document();
        PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
        // 打开文档
        document.open();
        // 加入水印
        PdfContentByte waterMar = pdfWriter.getDirectContentUnder();
        // 开始设置水印
        waterMar.beginText();
        // 设置水印透明度
        PdfGState gs = new PdfGState();
        // 设置填充字体不透明度为0.4f
        gs.setFillOpacity(0.4f);
        try {
            Image image = Image.getInstance("D:\\Folder\\image\\logo.png");
            // 设置坐标 绝对位置 X Y
            image.setAbsolutePosition(200, 300);
            // 设置旋转弧度
            image.setRotation(30);// 旋转 弧度
            // 设置旋转角度
            image.setRotationDegrees(45);// 旋转 角度
            // 设置等比缩放
            image.scalePercent(30);// 依照比例缩放
            // image.scaleAbsolute(200,100);//自定义大小
            // 设置透明度
            waterMar.setGState(gs);
            // 添加水印图片
            waterMar.addImage(image);
            // 设置透明度
            waterMar.setGState(gs);
            //结束设置
            waterMar.endText();
            waterMar.stroke();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 加入文档内容
        document.add(new Paragraph("hello world"));
        // 关闭文档
        document.close();
        pdfWriter.close();
    }

}

在这里插入图片描述

给已经存在的pdf添加文字水印
/**
 *  已有的pdf文件添加水印
 * @param inputFile:要加水印的源文件的路径
 * @param outputFile:加水印后文件的输出路径
 * @param waterMarkName:要加的水印名
 */
public static void waterMark(String inputFile,String outputFile, String waterMarkName) {
    try {
        PdfReader reader = new PdfReader(inputFile);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));

        BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);

        PdfGState gs = new PdfGState();
        //改透明度
        gs.setFillOpacity(0.5f);
        gs.setStrokeOpacity(0.4f);
        int total = reader.getNumberOfPages() + 1;

        JLabel label = new JLabel();
        label.setText(waterMarkName);

        PdfContentByte under;
        // 添加一个水印
        for (int i = 1; i < total; i++) {
            // 在内容上方加水印
            under = stamper.getOverContent(i);
            //在内容下方加水印
            //under = stamper.getUnderContent(i);
            gs.setFillOpacity(0.5f);
            under.setGState(gs);
            under.beginText();
            //改变颜色
            under.setColorFill(BaseColor.LIGHT_GRAY);
            //改水印文字大小
            under.setFontAndSize(base, 100);
            under.setTextMatrix(70, 200);
            //后3个参数,x坐标,y坐标,角度
            under.showTextAligned(Element.ALIGN_CENTER, waterMarkName, 300, 350, 55);

            under.endText();
        }
        stamper.close();
        reader.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
给已经存在的pdf添加图片水印
/**
 * @param inputFile:要加水印的源文件的路径
 * @param outputFile:加水印后文件的输出路径
 * @param pocturePath:           图片的位置
 */
public static void pictureWaterMark(String inputFile, String outputFile, String pocturePath) {
    try {
        PdfReader reader = new PdfReader(inputFile);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));


        PdfGState gs = new PdfGState();
        //设置透明度
        gs.setFillOpacity(0.3f);
        gs.setStrokeOpacity(0.4f);
        int total = reader.getNumberOfPages() + 1;
        
        PdfContentByte waterMar;
        // 添加一个水印
        for (int i = 1; i < total; i++) {
            // 在内容上方加水印
            waterMar = stamper.getOverContent(i);
            //在内容下方加水印
            //under = stamper.getUnderContent(i);
            waterMar.setGState(gs);
            waterMar.beginText();
            Image image = Image.getInstance(pocturePath);
            // 设置坐标 绝对位置 X Y
            image.setAbsolutePosition(150, 250);
            // 设置旋转弧度
            image.setRotation(30);// 旋转 弧度
            // 设置旋转角度
            image.setRotationDegrees(45);// 旋转 角度
            // 设置等比缩放
            image.scalePercent(30);// 依照比例缩放
            // image.scaleAbsolute(200,100);//自定义大小
            // 添加水印图片
            waterMar.addImage(image);
            // 设置透明度
            waterMar.setGState(gs);
            //结束设置
            waterMar.endText();
            waterMar.stroke();
        }
        stamper.close();
        reader.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

pdf加密

首先要说明的是,itext中对pdf文档的加密包括两部分,第一部分是用户密码,第二部分是所有者密码。这两部分可以简单的理解为管理员密码用户密码因此我们在设置这两个密码的权限的时候,往往会将所有者密码的权限级别设置的更高,而用户密码权限往往是“只读”。

在之前的基础上添加新的Maven依赖

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.60</version>
</dependency>
public class PdfPassword {
    public static final String RESULT = "src/main/resources/password.pdf";
    public static void main(String[] args) throws FileNotFoundException,
            DocumentException {
        //实现A4纸页面 并且横向显示(不设置则为纵向)
        Document document = new Document(PageSize.A4.rotate());
        PdfWriter pdfWriter = PdfWriter.getInstance(document,new 						  		  FileOutputStream(RESULT));
        // 设置用户密码, 所有者密码,用户权限,所有者权限
        pdfWriter.setEncryption("userpassword".getBytes(), "ownerPassword".getBytes(),           PdfWriter.ALLOW_COPY, PdfWriter.ENCRYPTION_AES_128);
        // 打开文档
        document.open();
        // 加入文档内容
        document.add(new Paragraph("hello world"));
        // 关闭文档
        document.close();
        pdfWriter.close();
    }
}
  • 然后我们打开我们的pdf文档,会弹出一个让你输入密码的对话框,我们先用“userpassword”这个用户密码去打开。然后再查看文档的属性,具体如下:

    在这里插入图片描述

  • 我们可以看到,我们是无法对现在的这个pdf进行打印和修改的。接下来,我们重新打开这个pdf。用“ownerPassword”这个密码取打开。然后再查看文档的属性,具体如下:

    在这里插入图片描述

    权限参数

    PdfWriter.ALLOW_MODIFY_CONTENTS
    允许打印,编辑,复制,签名 加密级别:40-bit-RC4
    PdfWriter.ALLOW_COPY
    允许复制,签名 不允许打印,编辑 加密级别:40-bit-RC
    PdfWriter.ALLOW_MODIFY_ANNOTATIONS
    允许打印,编辑,复制,签名 加密级别:40-bit-RC4
    PdfWriter.ALLOW_FILL_IN
    允许打印,编辑,复制,签名 加密级别:40-bit-RC4
    PdfWriter.ALLOW_SCREENREADERS
    允许打印,编辑,复制,签名 加密级别:40-bit-RC4
    PdfWriter.ALLOW_ASSEMBLY
    允许打印,编辑,复制,签名 加密级别:40-bit-RC4
    PdfWriter.EMBEDDED_FILES_ONLY
    允许打印,编辑,复制,签名 加密级别:40-bit-RC4
    PdfWriter.DO_NOT_ENCRYPT_METADATA
    允许打印,编辑,复制,签名 加密级别:40-bit-RC4
    PdfWriter.ENCRYPTION_AES_256
    允许打印,编辑,复制,签名 加密级别:256-bit-AES
    PdfWriter.ENCRYPTION_AES_128
    允许打印,编辑,复制,签名 加密级别:128-bit-AES
    PdfWriter.STANDARD_ENCRYPTION_128
    允许打印,编辑,复制,签名 加密级别:128-bit-RC4
    PdfWriter.STANDARD_ENCRYPTION_40
    允许打印,编辑,复制,签名 加密级别:40-bit-RC4

使用iText的基本构建快

​ 现在我们将重点集中到第四步:添加内容。这里说的添加内容都是通过Document.Add()方法调用,也就是通过一些high-level的对象实现内容的添加。这一节如标题要介绍Chunk、Phrase、Paragraph和List对象的属性和使用。Document的Add方法接受一个IElement的接口,我们先来看下实现此接口的UML图:

201206232227117688.png (775×517)

Chunk 对象

​ Chunk类是可以添加到Document中最小的文本片段。Chunk类中包含一个StringBuilder对象,其代表了有相同的字体,字体大小,字体颜色和字体格式的文本,这些属性定义在Chunk类中Font对象中。其它的属性如背景色(background),text rise(用来模拟下标和上标)还有underline(用来模拟文本的下划线或者删除线)都定义在其它一系列的属性中,这些属性都可以通过settter 方法进行设置.

public class CountryChunks {

    public static final String RESULT = "src/main/resources/country_chunks.pdf";


    public static void main(String[] args)
            throws IOException, DocumentException, SQLException {
        new CountryChunks().createPdf(RESULT);
    }

    public void createPdf(String filename)
            throws IOException, DocumentException, SQLException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename))
                .setInitialLeading(16);
        // step 3
        document.open();
        // step 4
        // add a country to the document as a Chunk
        document.add(new Chunk("China"));
        document.add(new Chunk(" "));
        Font font = new Font(Font.FontFamily.HELVETICA, 6, Font.BOLD, BaseColor.WHITE);
        Chunk id = new Chunk("cn", font);
        // with a background color
        id.setBackground(BaseColor.BLACK, 1f, 0.5f, 1f, 1.5f);
        // and a text rise
        id.setTextRise(6);
        document.add(id);
        document.add(Chunk.NEWLINE);//换行   NEWLINE = new Chunk("\n");
        // step 5
        document.close();
    }
}

行间距: LEADING

使用Chunk类要注意的是其不知道两行之间的行间距(Leading),这就是为什么在代码中要设置InitialLeading属性的原因。大家可以试着将其去掉然后再看下重新生存的pdf文档:你会发现所有的文本都写在同一行上。

SetTextRise

SetTextRise方法的参数表示的是离这一行的基准线(baseline)的距离,如果为正数就会模拟上标,负数就会模拟为下标。

Phrase 对象

Chunk类在iText是最小的原子文本,而Phrase类被定义为 “a string of word”,因此Phrase是一个组合的对象。转换为java和iText来说,phrase就是包含了Chunk类的一个ArraryList。

Font bul = new Font(Font.FontFamily.TIMES_ROMAN, 12, Font.BOLD | Font.UNDERLINE);
Font normal = new Font(Font.FontFamily.TIMES_ROMAN, 12);

Phrase director = new Phrase();
director.Add(new Chunk("China", bul));
director.Add(new Chunk(",", bul));
director.Add(new Chunk("id", normal));

document.add(director);

Paragraph 对象

可以将Phrase和Paragraph类比HTML中的span和div。如果在前一个例子中用Paragraph代替Phrase,就没有必要添加document.Add(Chunk.NEWLINE)。

Paragraph继承Phrase类,因此我们在创建Paragraph类时和创建Phrase完全一致,不过Paragraph拥有更多的属性设置:定义文本的对齐方式、不同的缩进和设置前后的空间大小。

html转为pdf

这里需要说明一个情况,如果项目中不引入字体文件,那么生成的pdf将不会显示文字(因为生产环境的服务器不会有任何字体文件,而本地运行的话,会自动去电脑中的字体文件库中去寻找字体文件),因此,如果是需要发布的项目,务必将字体文件放到项目中,然后进行使用。

引入Maven依赖

<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>core-renderer</artifactId>
    <version>R8</version>
</dependency>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>认识table表标签</title>
    <style type="text/css">
        /*解决html转pdf文件中文不显示的问题*/
        body {
            font-family: SimSun;
        }

        /*设定纸张大小*/
        /* A4纸 */
        /* @page{size:210mm*297mm} */
        @page{size:a4}

        p {
            color: red;
        }
    </style>
</head>
<body>
    <table border="1px">
        <caption>我的标题</caption>
        <tbody>
        <tr>
            <th>班级</th>
            <th>学生数</th>
            <th>平均成绩</th>
            <th>班级</th>
            <th>学生数</th>
            <th>平均成绩</th>
            <th>班级</th>
            <th>学生数</th>
            <th>平均成绩</th>
        </tr>
        <tr>
            <td>一班</td>
            <td>30</td>
            <td>89</td>
            <td>一班</td>
            <td>30</td>
            <td>89</td>
            <td>一班</td>
            <td>30</td>
            <td>89</td>
        </tr>
        <tr>
            <td>一班</td>
            <td>30</td>
            <td>89</td>
            <td>一班</td>
            <td>30</td>
            <td>89</td>
            <td>一班</td>
            <td>30</td>
            <td>89</td>
        </tr>
        <tr>
            <td>一班</td>
            <td>30</td>
            <td>89</td>
            <td>一班</td>
            <td>30</td>
            <td>89</td>
            <td>一班</td>
            <td>30</td>
            <td>89</td>
        </tr>
        </tbody>
    </table>

    <p>
        《侠客行》<br/>
        年代: 唐 作者: 李白<br/>
        赵客缦胡缨,吴钩霜雪明。银鞍照白马,飒沓如流星。
        十步杀一人,千里不留行。事了拂衣去,深藏身与名。
        闲过信陵饮,脱剑膝前横。将炙啖朱亥,持觞劝侯嬴。
        三杯吐然诺,五岳倒为轻。眼花耳热后,意气素霓生。
        救赵挥金槌,邯郸先震惊。千秋二壮士,煊赫大梁城。
        纵死侠骨香,不惭世上英。谁能书閤下,白首太玄经。
    </p>
</body>
</html>

PdfUtil.java

public class PdfUtil {
    /**
     * @param htmlFile        html文件存储路径
     * @param pdfFile         生成的pdf文件存储路径
     * @param chineseFontPath 中文字体存储路径
     */
    public static void html2pdf(String htmlFile, String pdfFile, String chineseFontPath){
        // step 1
        String url;
        OutputStream os = null;
        try {
            url = new File(htmlFile).toURI().toURL().toString();
            os = new FileOutputStream(pdfFile);
            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocument(url);
            // 解决中文不显示问题
            ITextFontResolver fontResolver = renderer.getFontResolver();
            fontResolver.addFont(chineseFontPath, BaseFont.IDENTITY_H, 			  		             BaseFont.NOT_EMBEDDED);

            renderer.layout();
            renderer.createPDF(os);
        } catch (Exception e) {

        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        try {
            //获取项目路径
            String projectPath = System.getProperty("user.dir");
            //html文件路径
            String htmlFilePath = projectPath + "/src/main/resources/index.html";
            // 中文字体存储路径
            String chineseFontPath = projectPath +"/src/main/resources/Fonts/simsun.ttc";
            // html转pdf
            html2pdf(htmlFilePath, projectPath + "/src/main/resources/html2pdf.pdf",    	        chineseFontPath);
            System.out.println("转换成功!");
        } catch (Exception e) {
            System.out.println("转换失败!");
            e.printStackTrace();
        }
    }
}

iText转html为pdf遇到的问题

  1. 中文不显示

    原因: iText默认不支持中文

    解决方法: 引入中文字体 (本机字体文件库C:\Windows\Fonts中下载上传到项目中)

    需要注意的是在java代码中设置好中文字体后,还需要在html引用该字体,否则不会起效果。

    // 解决中文不显示问题
    ITextFontResolver fontResolver = renderer.getFontResolver();
    fontResolver.addFont(chineseFontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
    
    /*解决html转pdf文件中文不显示的问题*/
    body {
        font-family: SimSun;
    }
    
  2. css不起作用

    原因: css文件使用的是相对路径

    解决方法: 将相对路径改为绝对路径或者把css样式写在html内部.

  3. html内容转为pdf后内容不全

    解决方法: 在html中设定纸张大小

     /*设定纸张大小*/
     /* A4纸 */
     /* @page{size:210mm*297mm} */
     @page{size:a4}
    

iText转html为pdf遇到的问题

  1. 中文不显示

    原因: iText默认不支持中文

    解决方法: 引入中文字体 (本机字体文件库C:\Windows\Fonts中下载上传到项目中)

    需要注意的是在java代码中设置好中文字体后,还需要在html引用该字体,否则不会起效果。

    // 解决中文不显示问题
    ITextFontResolver fontResolver = renderer.getFontResolver();
    fontResolver.addFont(chineseFontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
    
    /*解决html转pdf文件中文不显示的问题*/
    body {
        font-family: SimSun;
    }
    
  2. css不起作用

    原因: css文件使用的是相对路径

    解决方法: 将相对路径改为绝对路径或者把css样式写在html内部.

  3. html内容转为pdf后内容不全

    解决方法: 在html中设定纸张大小

     /*设定纸张大小*/
     /* A4纸 */
     /* @page{size:210mm*297mm} */
     @page{size:a4}
    

    推荐博客:https://www.cnblogs.com/julyluo/archive/2012/07/29/2613822.html

    推荐博客:https://www.cnblogs.com/liaojie970/p/7132475.html

  • 6
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值