java实现对pdf文件压缩,拆分,修改水印,添加水印

      最近要实现一个文件上传,并且在线预览上传文件的功能,设计思路是:把上传的文件通过openoffice转成pdf文件,并将pdf文件以流的形式返回到浏览器,由于上传的部分文件过大,转成pdf后传回前端浏览器需要的时间太长会找出接口超时问题,故需要对转化后的pdf文件进行压缩,分割再分页传回到前台。

        在网上看了很多对pdf文件进行操作文档后,收集整理了4个好用代码片段,希望对需要的人有用处吧。

1.java实现对pdf文件压缩:

引用的maven坐标

        <!--文件压缩-->
        <dependency>
            <groupId>com.aspose</groupId>
            <artifactId>aspose-pdf</artifactId>
            <version>18.2</version>
        </dependency>

整理的代码片段

package tvap.pdfutil;

import com.aspose.pdf.Document;
import tvap.pdfutil.util.DateUtil;

/**pdf文件压缩
 * @author liyuliang
 * @date 2021/7/14
 */
public class PdfZipUtil {
    public static void main(String[] args) {
        String inputFile = "D:\\opt\\jenkins\\gccc.pdfutil";
        String outputFile = "D:\\opt\\jenkins\\gccc-opt2.pdfutil";
        System.out.println(DateUtil.getCurrentTime());
        optimize(inputFile, outputFile);
        System.out.println(DateUtil.getCurrentTime());
    }

    public static void optimize(String source, String target) {
        Document doc = new Document(source);
        //设置压缩属性
        Document.OptimizationOptions opt = new Document.OptimizationOptions();
        //删除PDF不必要的对象
        opt.setRemoveUnusedObjects(true);
        //链接重复流
        opt.setLinkDuplcateStreams(false);
        //删除未使用的流
        opt.setRemoveUnusedStreams(false);
        //删除不必要的字体
        //  opt.setUnembedFonts(true);
        //压缩PDF中的图片
        opt.setCompressImages(true);
        //图片压缩比, 0 到100可选,越低压缩比越大
        opt.setImageQuality(10);
        doc.optimizeResources(opt);
        //优化web的PDF文档
        doc.optimize();
        doc.save(target);
        doc.close();
    }

}

进行pdf文件压缩后,pdf文件顶部会有水印,"Evaluation Only. Created with Aspose.PDF. Copyright 2002-2018 Aspose Pty Ltd." 可以使用对pdf进行修改的方法把水印去掉。

2.java实现对pdf文件的修改

引用的maven坐标

   <!--修改pdf水印/分割pdf文件-->
    <dependencies>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>

整理的代码片段

package tvap.pdfutil;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Font;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import tvap.pdfutil.listen_pdf.KeyWordPositionListener;
import tvap.pdfutil.listen_pdf.MatchItem;
import tvap.pdfutil.util.DateUtil;

import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author liyuliang
 * @date 2021/7/14
 * pdf替换文字工具类
 * <p>
 * 思路:
 * 1.逐页搜索关键字,逐页匹配
 * 2.先读取一页的所有字符信息,存放到allItems中
 * 3.把一页的字符拼接成字符串,然后匹配关键字,匹配上,记录匹配的第一个字符的MatchItem信息;匹配不是,继续下一页匹配
 * 4.根据匹配字符串的长度和字符的宽高信息画遮罩层,然后替换文字生成新的pdf文件
 * <p>
 * 不足之处:
 * 1.目前只支持单字符串匹配
 * 2.替换之后的文字无法和原pdf中替换掉的文字信息一致(主要有:字体大小、样式等)
 * 3.某些情况下(主要是替换字体的大小)替换之后显示不是太整齐
 * 4.字体大小、样式无法把控
 * 5.无法匹配目标文字在两页中显示的情况(例如:目标文字:替换工具,第一页页尾有替换两字,第二页页首有工具二字)
 */
 */
public class PdfDelwaterUtil {
    public static void main(String[] args) throws Exception {
        String src = "D:\\opt\\jenkins\\ilovepdf-opt2.pdf";
        String dest = "D:\\opt\\jenkins\\ilovepdf-no-water.pdf";
        String keyWord = "Evaluation Only. Created with Aspose.PDF. Copyright 2002-2018 Aspose Pty Ltd.";
        String keyWordNew = "";
        System.out.println( DateUtil.getCurrentTime());
        pdfReplace(src, dest, keyWord, keyWordNew);
        System.out.println( DateUtil.getCurrentTime());
    }

    /**
     * 根据关键字和pdf路径,全文搜索关键字
     *
     * @param filePath pdf目标路径
     * @param keyword  关键字
     * @return
     * @throws Exception
     */
    public static List<MatchItem> matchAll(String filePath, String keyword) throws Exception {
        List<MatchItem> items = new ArrayList<MatchItem>();
        PdfReader reader = new PdfReader(filePath);
        //获取pdf页数
        int pageSize = reader.getNumberOfPages();
        //逐页匹配关键字
        for (int page = 1; page <= pageSize; page++) {
            items.addAll(matchPage(reader, page, keyword));
        }
        return items;
    }

    /**
     * 根据关键字、文档路径、pdf页数寻找特定的文件内容
     *
     * @param reader
     * @param pageNumber 页数
     * @param keyword    关键字
     * @return
     * @throws Exception
     */
    public static List<MatchItem> matchPage(PdfReader reader, Integer pageNumber, String keyword) throws Exception {
        PdfReaderContentParser parse = new PdfReaderContentParser(reader);
        Rectangle rectangle = reader.getPageSize(pageNumber);
        //匹配监听
        KeyWordPositionListener renderListener = new KeyWordPositionListener();
        renderListener.setKeyword(keyword);
        renderListener.setPageNumber(pageNumber);
        renderListener.setCurPageSize(rectangle);
        parse.processContent(pageNumber, renderListener);
        return findKeywordItems(renderListener, keyword);
    }

    /**
     * 找到匹配的关键词块
     *
     * @param renderListener
     * @param keyword
     * @return
     */
    public static List<MatchItem> findKeywordItems(KeyWordPositionListener renderListener, String keyword) {
        //先判断本页中是否存在关键词
        List<MatchItem> allItems = renderListener.getAllItems();//所有块LIST
        StringBuffer sbtemp = new StringBuffer("");

        for (MatchItem item : allItems) {//将一页中所有的块内容连接起来组成一个字符串。
            sbtemp.append(item.getContent());
        }

        List<MatchItem> matches = renderListener.getMatches();

        //一页组成的字符串没有关键词,直接return
        //第一种情况:关键词与块内容完全匹配的项,直接返回
        if (sbtemp.toString().indexOf(keyword) == -1 || matches.size() > 0) {
            return matches;
        }
        //第二种情况:多个块内容拼成一个关键词,则一个一个来匹配,组装成一个关键词
        sbtemp = new StringBuffer("");
        List<MatchItem> tempItems = new ArrayList();
        for (MatchItem item : allItems) {
            if (keyword.indexOf(item.getContent()) != -1) {
                tempItems.add(item);
                sbtemp.append(item.getContent());

                if (keyword.indexOf(sbtemp.toString()) == -1) {//如果暂存的字符串和关键词 不再匹配时
                    sbtemp = new StringBuffer(item.getContent());
                    tempItems.clear();
                    tempItems.add(item);
                }

                if (sbtemp.toString().equalsIgnoreCase(keyword)) {//暂存的字符串正好匹配到关键词时
                    matches.add(tempItems.get(0));//得到匹配的项
                    sbtemp = new StringBuffer("");//清空暂存的字符串
                    tempItems.clear();//清空暂存的LIST
                    continue;//继续查找
                }
            } else {//如果找不到则清空
                sbtemp = new StringBuffer("");
                tempItems.clear();
            }
        }
        return matches;
    }

    /**
     * 替换目标文字,生成新的pdf文件
     *
     * @param src  目标pdf路径
     * @param dest 新pdf的路径
     * @throws Exception
     */
    public static void manipulatePdf(String src, String dest, List<MatchItem> matchItems, String keyWord, String keyWordNew) throws Exception {
        PdfReader reader = new PdfReader(src);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        PdfContentByte canvas = null;
        Map<Integer, List<MatchItem>> mapItem = new HashMap<Integer, List<MatchItem>>();
        List<MatchItem> itemList = null;
        for (MatchItem item : matchItems) {
            Integer pageNum = item.getPageNum();
            if (mapItem.containsKey(pageNum)) {
                itemList = mapItem.get(pageNum);
                itemList.add(item);
                mapItem.put(pageNum, itemList);
            } else {
                itemList = new ArrayList<MatchItem>();
                itemList.add(item);
                mapItem.put(pageNum, itemList);
            }
        }
        //遍历每一页去修改
        for (Integer page : mapItem.keySet()) {
            List<MatchItem> items = mapItem.get(page);
            //遍历每一页中的匹配项
            for (MatchItem item : items) {
                canvas = stamper.getOverContent(page);
                float x = item.getX();
                float y = item.getY();
                float fontWidth = item.getFontWidth();
                float fontHeight = item.getFontHeight();
                canvas.saveState();
                canvas.setColorFill(BaseColor.WHITE);
                canvas.rectangle(x, y, fontWidth * keyWord.length(), fontWidth + 2);
                canvas.fill();
                canvas.restoreState();
                //开始写入文本
                canvas.beginText();
                BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
                Font font = new Font(bf, fontWidth, Font.BOLD);
                //设置字体和大小
                canvas.setFontAndSize(font.getBaseFont(), fontWidth);
                //设置字体的输出位置
                canvas.setTextMatrix(x, y + fontWidth / 10 + 0.5f);
                //要输出的text
                canvas.showText(keyWordNew);

                canvas.endText();
            }
        }
        stamper.close();
        reader.close();
        System.out.println("complete");
    }

    /**
     * 替换pdf中指定文字
     *
     * @param src        目标pdf路径
     * @param dest       新pdf的路径
     * @param keyWord    替换的文字
     * @param keyWordNew 替换后的文字
     * @throws Exception
     */
    public static void pdfReplace(String src, String dest, String keyWord, String keyWordNew) throws Exception {
        manipulatePdf(src, dest, matchAll(src, keyWord), keyWord, keyWordNew);
    }
}

 这个水印修改代码片段中还有,两个附属类如下:

实体类MatchItem 

package com.Stream.pdfcut;

/**
 * @author liyuliang
 * @date 2021/7/14
 * 用来保存关键字信息
 */
public class MatchItem {

    //页数
    private Integer pageNum;
    //x坐标
    private Float x;
    //y坐标
    private Float y;
    //页宽
    private Float pageWidth;
    //页高
    private Float pageHeight;
    //匹配字符
    private String content;
    //字体宽
    private float fontWidth;
    //字体高
    private float fontHeight = 12;

    public Integer getPageNum() {
        return pageNum;
    }

    public void setPageNum(Integer pageNum) {
        this.pageNum = pageNum;
    }

    public Float getX() {
        return x;
    }

    public void setX(Float x) {
        this.x = x;
    }

    public Float getY() {
        return y;
    }

    public void setY(Float y) {
        this.y = y;
    }

    public Float getPageWidth() {
        return pageWidth;
    }

    public void setPageWidth(Float pageWidth) {
        this.pageWidth = pageWidth;
    }

    public Float getPageHeight() {
        return pageHeight;
    }

    public void setPageHeight(Float pageHeight) {
        this.pageHeight = pageHeight;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public float getFontWidth() {
        return fontWidth;
    }

    public void setFontWidth(float fontWidth) {
        this.fontWidth = fontWidth;
    }

    public float getFontHeight() {
        return fontHeight;
    }

    public void setFontHeight(float fontHeight) {
        this.fontHeight = fontHeight;
    }

    @Override
    public String toString() {
        return "MatchItem{" +
                "pageNum=" + pageNum +
                ", x=" + x +
                ", y=" + y +
                ", pageWidth=" + pageWidth +
                ", pageHeight=" + pageHeight +
                ", content='" + content + '\'' +
                '}';
    }
}

和这个监听类KeyWordPositionListener 

package tvap.pdfutil.listen_pdf;

import com.itextpdf.awt.geom.Rectangle2D;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;

import java.util.ArrayList;
import java.util.List;
/**
 * @author liyuliang
 * @date 2021/7/14
 */

/**
 * 用来匹配pdf的关键词 监听类
 */
public class KeyWordPositionListener implements RenderListener {

    //存放匹配上的字符信息
    private List<MatchItem> matches = new ArrayList<MatchItem>();
    //存放所有的字符信息
    private List<MatchItem> allItems = new ArrayList<MatchItem>();

    private Rectangle curPageSize;

    /**
     * 匹配的关键字
     */
    private String keyword;
    /**
     * 匹配的当前页
     */
    private Integer pageNumber;

    @Override
    public void beginTextBlock() {
        //do nothing
    }

    @Override
    public void renderText(TextRenderInfo renderInfo) {
        //获取字符
        String content = renderInfo.getText();
        Rectangle2D.Float textRectangle = renderInfo.getDescentLine().getBoundingRectange();

        MatchItem item = new MatchItem();
        item.setContent(content);
        item.setPageNum(pageNumber);
        item.setFontHeight(textRectangle.height == 0 ? 12 : textRectangle.height);//默认12
        item.setFontWidth(textRectangle.width);
        item.setPageHeight(curPageSize.getHeight());
        item.setPageWidth(curPageSize.getWidth());
        item.setX((float) textRectangle.getX());
        item.setY((float) textRectangle.getY());

        //若keyword是单个字符,匹配上的情况
        if (content.equalsIgnoreCase(keyword)) {
            matches.add(item);
        }
        //保存所有的项
        allItems.add(item);
    }

    @Override
    public void endTextBlock() {
        //do nothing
    }

    @Override
    public void renderImage(ImageRenderInfo renderInfo) {
        //do nothing
    }

    /**
     * 设置需要匹配的当前页
     *
     * @param pageNumber
     */
    public void setPageNumber(Integer pageNumber) {
        this.pageNumber = pageNumber;
    }

    /**
     * 设置需要匹配的关键字,忽略大小写
     *
     * @param keyword
     */
    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }

    /**
     * 返回匹配的结果列表
     *
     * @return
     */
    public List<MatchItem> getMatches() {
        return matches;
    }

    public  void setCurPageSize(Rectangle rect) {
        this.curPageSize = rect;
    }

    public List<MatchItem> getAllItems() {
        return allItems;
    }

    public void setAllItems(List<MatchItem> allItems) {
        this.allItems = allItems;
    }

}

3.java实现对pdf文件的拆分

引入的maven坐标

       <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>

代码片段

package tvap.pdfutil;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import tvap.pdfutil.util.DateUtil;

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

/**
 * 分割pdf文件工具类
 * @author liyuliang
 * @date 2021/7/14
 */
public class PdfSpiltUtil {
    public static void main(String[] args) {
        String inputFile = "D:\\opt\\jenkins\\ilovepdf.pdfutil";
        System.out.println(DateUtil.getCurrentTime());
        try {
            splitFileBySiz(inputFile,10);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(DateUtil.getCurrentTime());
    }

    /**
     * 分割pdf文件,并设置尺寸
     * @param pdfFilePath
     * @param size
     * @throws Exception
     */
    public static void splitFileBySiz (String pdfFilePath,int size)throws Exception{
        PdfReader reader = new PdfReader(pdfFilePath);
        int pagecount = reader.getNumberOfPages();
        for (int i = 0; i < pagecount / size + 1; i++) {
            if (i != pagecount / size) {
                splitFile(pdfFilePath, i * size + 1, (i + 1) * size,i);
            } else {
                splitFile(pdfFilePath, i * size + 1, pagecount,i);
            }
        }
    }

    /**
     * 分割pdf文件
     * @param pdfFile
     * @param from
     * @param end
     * @return
     */
    public static String splitFile(String pdfFile, Integer from, Integer end,Integer i) {

        Document document = null;
        PdfCopy copy = null;
        try {
            PdfReader reader = new PdfReader(pdfFile);
            int n = reader.getNumberOfPages();
            if (end == 0) {
                end = n;
            }
            List<String> savepaths = new ArrayList<String>();
            int a = pdfFile.lastIndexOf(".pdfutil");
            String staticpath = pdfFile.substring(0, a);
           // String savepath = staticpath + "_from_" + from + "_to_" + end + "_.pdfutil";
            String savepath = staticpath + "_"+i+".pdfutil";
            savepaths.add(savepath);
            document = new Document(reader.getPageSize(1));
            copy = new PdfCopy(document, new FileOutputStream(savepaths.get(0)));
            document.open();
            for (int j = from; j <= end; j++) {
                document.newPage();
                PdfImportedPage page = copy.getImportedPage(reader, j);
                copy.addPage(page);
            }
            document.close();
            return new File(savepath).getName();
        } catch (IOException e) {
            return null;
        } catch (DocumentException e) {
            return null;
        }

    }
}

 4.java实现对pdf文件的水印添加

引入的maven坐标

        <!--添加水印-->
        <dependency>
            <groupId>org.eclipse.birt.runtime.3_7_1</groupId>
            <artifactId>com.lowagie.text</artifactId>
            <version>2.1.7</version>
        </dependency>

代码片段

package tvap.pdfutil;

import java.awt.*;
import java.io.FileOutputStream;
import com.lowagie.text.Element;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfGState;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStamper;
import javax.swing.*;


/**
 * 添加水印
 * @author liyuliang
 * @date 2021/7/14
 */
public class PdfAddwaterUtil {

    public static void main(String[] args) {
        String inputFile = "D:\\opt\\jenkins\\ilovepdf-no-water.pdf";
        String outputFile = "D:\\opt\\jenkins\\ilovepdf_shuiyin.pdf";
        waterMark(inputFile,outputFile,"北京XXXX科技有限公司 专用");
    }
    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);
            Rectangle pageRect = null;
            PdfGState gs = new PdfGState();
            gs.setFillOpacity(0.3f);
            gs.setStrokeOpacity(0.4f);
            int total = reader.getNumberOfPages() + 1;

            JLabel label = new JLabel();
            FontMetrics metrics;
            int textH = 0;
            int textW = 0;
            label.setText(waterMarkName);
            metrics = label.getFontMetrics(label.getFont());
            textH = metrics.getHeight();
            textW = metrics.stringWidth(label.getText());

            PdfContentByte under;
            for (int i = 1; i < total; i++) {
                under = stamper.getOverContent(i);// 在内容上方加水印
                //content = stamper.getUnderContent(i);//在内容下方加水印
                gs.setFillOpacity(0.2f);
                // content.setGState(gs);
                under.beginText();

                under.setFontAndSize(base, 50);
                under.setTextMatrix(70, 200);
                under.showTextAligned(Element.ALIGN_CENTER, waterMarkName, 300, 350, 55);
                under.endText();
            }
            //一定不要忘记关闭流
            stamper.close();
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以上是本人整理的4个对pdf文件操作的代码,看了很多文档感觉不容易,所以分享出来希望对需要的人有用,另外还有一个插件也是操作pdf的叫做 spire.pdf ,它的官网有使用文档有兴趣可以去看看,以上资源整理自网络。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
您可以使用Python中的PyPDF2库来实现这些功能。 1. 合并PDF文件: ```python import PyPDF2 pdf_files = ['file1.pdf', 'file2.pdf', 'file3.pdf'] # 创建一个空的PDF文件 merged_pdf = PyPDF2.PdfFileMerger() # 将所有PDF文件合并到一个PDF文件中 for file in pdf_files: merged_pdf.append(file) # 将合并后的PDF文件保存 merged_pdf.write('merged_file.pdf') ``` 2. PDF文件: ```python import PyPDF2 pdf_file = 'original_file.pdf' # 打开PDF文件 with open(pdf_file, 'rb') as file: pdf_reader = PyPDF2.PdfFileReader(file) # 将每一页PDF文件单独保存为一个文件 for i in range(pdf_reader.getNumPages()): pdf_writer = PyPDF2.PdfFileWriter() pdf_writer.addPage(pdf_reader.getPage(i)) with open(f'page_{i}.pdf', 'wb') as output_file: pdf_writer.write(output_file) ``` 3. 旋转PDF页面: ```python import PyPDF2 pdf_file = 'original_file.pdf' # 打开PDF文件 with open(pdf_file, 'rb') as file: pdf_reader = PyPDF2.PdfFileReader(file) # 创建一个新的PDF文件写入器 pdf_writer = PyPDF2.PdfFileWriter() # 将所有PDF文件旋转180度并添加到新的PDF文件中 for page in pdf_reader.pages: page.rotateClockwise(180) pdf_writer.addPage(page) # 将旋转后的PDF文件保存 with open('rotated_file.pdf', 'wb') as output_file: pdf_writer.write(output_file) ``` 4. 添加水印PDF文件: ```python import PyPDF2 pdf_file = 'original_file.pdf' watermark_file = 'watermark.pdf' # 打开PDF文件水印文件 with open(pdf_file, 'rb') as pdf_file, open(watermark_file, 'rb') as watermark_file: pdf_reader = PyPDF2.PdfFileReader(pdf_file) watermark_reader = PyPDF2.PdfFileReader(watermark_file) # 获取水印文件的第一页 watermark_page = watermark_reader.getPage(0) # 创建一个新的PDF文件写入器 pdf_writer = PyPDF2.PdfFileWriter() # 在每一页PDF文件添加水印 for page in pdf_reader.pages: page.mergePage(watermark_page) pdf_writer.addPage(page) # 将添加水印后的PDF文件保存 with open('watermarked_file.pdf', 'wb') as output_file: pdf_writer.write(output_file) ``` 希望这些代码可以帮助到您实现您的需求!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值