欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

听说你想用Java去掉PDF里全部文本?看这

程序员文章站 2022-03-18 20:33:40
听说你想用Java去掉文章里全部文本?看这,PDFBox去文本...

1、网上查Java处理PDF文档的框架常见就两个iText和PDFBox,其中iText的口碑比较好,网上说功能比PDFBox强大效果更好,但是自己用可以商用需要授权的,就是收钱的,而PDFBox是apache的开源项目,应该不收钱八。

2、根据查阅资料可知,文本信息存PDF结构里面的stream里面,文本工具打开如下图
stream内送是经过压缩处理过的所以显示乱码,压缩算法记在/Filter里面。不过这些都不用考虑,PDFBox加载PDF文档时已经帮忙解压好啦,并将流保存在一个对象里面,取出来用即可。
听说你想用Java去掉PDF里全部文本?看这

3、流里面有文本、图像等信息,时通过流里面的操作符区分的,所有的操作符PDFBox已经枚举好了在对象OperatorName里面,含有Tj和DJ字样标识前面是需要展示的文字。要去掉所有文本只需要把这两个操作符前面的内容直接置空即可

4、其中Resources和Contents里面都含有文字的流,直接遍历字典下所有流判断即可

使用的pdfbox版本

<dependency>
      <groupId>org.apache.pdfbox</groupId>
      <artifactId>pdfbox</artifactId>
      <version>2.0.22</version>
</dependency>
public class PDFUtil{
    
    /**
     * 去掉文档里的全部文本信息
     */
    public static void removeAllText(PDDocument pdDocument) {
        try {
            for (PDPage pdPage : pdDocument.getPages()) {
                //遍历Resources
                PDResources pdResources = pdPage.getResources();
                COSDictionary resourceDictionary = pdResources.getCOSObject();
                findStreamToRemoveText(resourceDictionary);

                //遍历Contents
                pdPage.getContentStreams().forEachRemaining(pdStream -> {
                    removeText(pdStream.getCOSObject());
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 遍历字典寻找流类型的对象进行去文字
     * 注意的是流对象也同时是字典对象
     * @param cosDictionary 字典类型
     */
    public static void findStreamToRemoveText(COSDictionary cosDictionary) {
        for (COSBase resourceBase : cosDictionary.getValues()) {
            //流
            if (resourceBase instanceof COSStream) {
                removeText((COSStream) resourceBase);
            }
            //字典
            if (resourceBase instanceof COSDictionary) {
                findStreamToRemoveText((COSDictionary) resourceBase);
            }
            //对象
            if (resourceBase instanceof COSObject) {
                if (((COSObject) resourceBase).getObject() instanceof COSStream) {
                    removeText((COSStream) ((COSObject) resourceBase).getObject());
                }
                if (((COSObject) resourceBase).getObject() instanceof COSDictionary) {
                    findStreamToRemoveText((COSDictionary) ((COSObject) resourceBase).getObject());
                }
            }
        }
    }


    /**
     * 去除流里面的文字
     *
     * @param pdStream 待修改流
     */
    public static void removeText(COSStream pdStream) {
        try {
            PDFStreamParser parser = new PDFStreamParser(pdStream);
            try {
                parser.parse();
            } catch (Exception e) {
                //如果有异常说明无法处理流,可能由于流的格式不符合要求,没有文本
                return;
            }
            //获取流解码后的内容
            List<Object> tokens = parser.getTokens();
            boolean isRemove = false;
            for (int i = 0; i < tokens.size(); i++) {
                Object token = tokens.get(i);
                if (token instanceof Operator) {
                    Operator operator = (Operator) token;
                    //流中含有Tj和DJ字样标识前面是需要展示的文字,直接置空去掉
                    if (operator.getName().equals(OperatorName.SHOW_TEXT)) {
                        COSString previous = (COSString) tokens.get(i - 1);
                        //注意指定该编码确保把流写回去,不然会出现乱码导致文档全空(由于PDF流中使用压缩格式)
                        previous.setValue("".getBytes(StandardCharsets.ISO_8859_1));
                        isRemove = true;
                    } else if (operator.getName().equals(OperatorName.SHOW_TEXT_ADJUSTED)) {
                        COSArray previous = (COSArray) tokens.get(i - 1);
                        for (int k = 0; k < previous.size(); k++) {
                            Object arrElement = previous.getObject(k);
                            if (arrElement instanceof COSString) {
                                COSString cosString = (COSString) arrElement;
                                cosString.setValue("".getBytes(StandardCharsets.ISO_8859_1));
                                isRemove = true;
                            }
                        }
                    }
                }
            }
            //删除了文字才进行流的更新
            if (isRemove) {
                OutputStream out = pdStream.createOutputStream();
                ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
                tokenWriter.writeTokens(tokens);
                out.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }
    
}

本文地址:https://blog.csdn.net/I_am_hardy/article/details/111991101