我想删除某些图像显示在页面使用PDFBox库.据我所知,识别一个图像最合适的方法是在XOBJECT目录中找到它的"名称".因此,从理论上讲,应该做的一切都是从XOBJECT个目录和显示该图像的操作员中删除该图像.这就是我如何处理从页面中删除图像的问题.Using PDFBox Debugger我找到了图像的id(Im3)和在页面上显示它的说明:

enter image description here

我的问题是,我应该如何删除显示图像的指令之前和之后的指令(Do用于显示图像).我决定删除从/Gs1 gs/Im3 Do的所有内容(因此包括在内).这是正确的做法吗?这是我的代码.它工作正常,即.没有包含不需要的图像的页面.我使用最新的(即V3).

import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdfparser.PDFStreamParser;
import org.apache.pdfbox.pdfwriter.ContentStreamWriter;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDStream;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

import static org.apache.pdfbox.contentstream.operator.OperatorName.DRAW_OBJECT;
import static org.apache.pdfbox.contentstream.operator.OperatorName.SET_GRAPHICS_STATE_PARAMS;


public class GraphicRemover {

    private static final COSName X_OBJECT_NAME_TO_REMOVE = COSName.getPDFName("Im3");

    public void remove(final PDDocument document) throws IOException {

        for (final PDPage page : document.getPages()) {

            final PDFStreamParser parser = new PDFStreamParser(page);
            final List<Object> tokens = parser.parse();

            final boolean hasImage = tokens.stream().anyMatch(X_OBJECT_NAME_TO_REMOVE::equals);

            if (!hasImage) {
                continue;
            }

            for (int i = tokens.size() - 1; i >= 0; i--) {

                if (!tokens.get(i).equals(X_OBJECT_NAME_TO_REMOVE)) {
                    continue;
                }

                int indexOfGraphicStartCommand = i - 1;
                while (!Operator.getOperator(SET_GRAPHICS_STATE_PARAMS).equals(tokens.get(indexOfGraphicStartCommand))) {
                    --indexOfGraphicStartCommand;
                }

                int indexOfDisplayGraphicCommand = i;
                while (!Operator.getOperator(DRAW_OBJECT).equals(tokens.get(indexOfDisplayGraphicCommand))) {
                    ++indexOfDisplayGraphicCommand;
                }
                final int indexOfDisplayGraphicArgument = --indexOfGraphicStartCommand;
                tokens.subList(indexOfDisplayGraphicArgument, indexOfDisplayGraphicCommand).clear();
                final PDStream newContents = new PDStream(document);
                final OutputStream newContentOutput = newContents.createOutputStream(COSName.FLATE_DECODE);
                final ContentStreamWriter newContentWriter = new ContentStreamWriter(newContentOutput);
                newContentWriter.writeTokens(tokens);
                newContentOutput.close();
                page.setContents(newContents);
                removeWatermarkObject(page);
                break;
            }
        }
    }

    private void removeWatermarkObject(final PDPage page) {
        ((COSDictionary) page.getResources().getCOSObject()
                .getDictionaryObject(COSName.XOBJECT)).removeItem(X_OBJECT_NAME_TO_REMOVE);
        removeEmptyXobjects(page);
    }

    private void removeEmptyXobjects(final PDPage page) {
        final COSDictionary xObjects =
                (COSDictionary) page.getResources().getCOSObject().getDictionaryObject(COSName.XOBJECT);

        if (xObjects == null || xObjects.size() == 0) {
            page.getResources().getCOSObject().removeItem(COSName.XOBJECT);
        }
    }
} 

推荐答案

我决定删除所有从(因此包括)/Gs1 gs/Im3 Do.这是正确的做法吗?

如果包含开头q,则还必须包含结尾Q:它们表示保存图形状态(在堆栈上)和恢复图形状态(从该堆栈中),因此仅移除开头q可能会对以下内容产生严重影响.

或者,也可以只删除/Im3 Do个.

在你随后发表的一条 comments 中:

因此,输出应如下所示:

https://imgur.com/a/YW1EkAZ

这将是一个有效的 Select .

但是如果你真的想删除的不仅仅是/Im3 Do个,你也可以删除剩下的q /Perceptual ri Q个,因为这本质上是一个NOP.

Java相关问答推荐

如何将kotlin代码转换为java

无法找到符号错误—Java—封装

Javascript在边界中心调整ImageView大小

Intellij显示项目语言级别最高为12,尽管有java版本17 SDK

有关手动创建的包的问题

Hibernate 6支持Joda DateTime吗?

我需要生成一个文件来整合每个特性执行的所有JSON结果

如何创建同一类的另一个对象,该对象位于变量中?

Spring @Value default无法计算表达式

每次FXMLLoader调用ApplationConext.getBean(类)时创建@Component的新实例

将PNG转换为位图自定义十六进制字符串

在Java中将int[]矩阵添加到ArrayList中,但出现错误

将JSON字符串转换为Java类

JNI:将代码打包成自包含的二进制文件

Java.time.OffsetDateTime的SQL Server数据库列类型是什么?

在Java中将对象&转换为&q;HashMap(&Q)

如何设计包含已知和未知键值对映射的Java类?

rest api服务 spring 启动中出现IllegalFormatConversionException

无泄漏函数的Java DRY

将Optionals/null安全添加到嵌套的flatMap/流