如何从PDF文件中删除图像?

2022-07-18 00:00:00 pdf java pdfbox

您好,感谢您回答我的问题。这个问题困扰了我很长时间。

我已经搜索这个QS很长时间了,我在堆栈溢出和Google上读了很多文章,但那些文章过时了或碎片化了,所以我不得不寻求帮助。 我希望有人能帮帮我。

public class TEST04 {
    public static void main(String[] args) throws IOException {
        System.out.println("Hi");
        //ori pdf file
        String oriPDFFile = IFileUtils.getDesktopPath().getAbsoluteFile() + "\1.pdf";
        //out pdf file
        String outPDFFile = IFileUtils.getDesktopPath().getAbsoluteFile() + "\2.pdf";
        strip(oriPDFFile, outPDFFile);
    }

    //parse
    public static void strip(String pdfFile, String pdfFileOut) throws IOException {
        //load ori pdf file
        PDDocument document = PDDocument.load(new File(pdfFile));
        //get All pages
        List<PDPage> pageList = IterUtil.toList(document.getDocumentCatalog().getPages());

        for (int i = 0; i < pageList.size(); i++) {
            PDPage page = pageList.get(i);
            COSDictionary newDictionary = new COSDictionary(page.getCOSObject());
            PDFStreamParser parser = new PDFStreamParser(page);
            List tokens = parser.getTokens();
            List newTokens = new ArrayList();

            for (int j = 0; j < tokens.size(); j++) {
                Object token = tokens.get(j);
                if (token instanceof Operator) {
                    Operator operator = (Operator) token;
                    if (operator.getName().equals("Do")) {
                        COSName cosName = (COSName) newTokens.remove(newTokens.size() - 1);
                        deleteObject(newDictionary, cosName);
                        continue;
                    }
                }
                newTokens.add(token);
            }
            PDStream newContents = new PDStream(document);
            try (OutputStream outputStream = newContents.createOutputStream()) {
                ContentStreamWriter writer = new ContentStreamWriter(outputStream);
                writer.writeTokens(newTokens);
            }
            page.setContents(newContents);

//            ContentStreamWriter writer = new ContentStreamWriter(newContents.createOutputStream());
//            writer.writeTokens( newTokens );
//            page.setContents(newContents);
            
            PDResources newResources = new PDResources(newDictionary);
            page.setResources(newResources);

        }
        document.save(pdfFileOut);
        document.close();
    }
    //delete
    public static boolean deleteObject(COSDictionary d, COSName name) {
        for(COSName key : d.keySet()) {
            if( name.equals(key) ) {
                d.removeItem(key);
                return true;
            }
            COSBase object = d.getDictionaryObject(key);
            if(object instanceof COSDictionary) {
                if( deleteObject((COSDictionary)object, name) ) {
                    return true;
                }
            }
        }
        return false;
    }
}
堆栈跟踪:


解决方案

在my other answer中,我重点介绍了如何修复问题中的代码。在这里,我将重点介绍一种不同的任务方法。

在代码中,您可以尝试删除位图图像,方法是检查页面内容流,在绘制XObject中找到do操作,然后删除此指令和引用的XObject。

简单地将资源中的所有图像XObject替换为一个空的表单XObject会更容易一些。这就是这里使用的方法。

因为该方法非常容易实现,所以我对其进行了扩展,使其不仅可以遍历页面的直接资源,还可以迭代为嵌入的表单XObject和模式。

void replaceBitmapImagesResources(PDDocument document) throws IOException {
    PDFormXObject pdFormXObject = new PDFormXObject(document);
    pdFormXObject.setBBox(new PDRectangle(1, 1));
    for (PDPage pdPage : document.getPages()) {
        replaceBitmapImagesResources(pdPage.getResources(), pdFormXObject);
    }
}

void replaceBitmapImagesResources(PDResources resources, PDFormXObject formXObject) throws IOException {
    if (resources == null)
        return;

    for (COSName cosName : resources.getPatternNames()) {
        PDAbstractPattern pdAbstractPattern = resources.getPattern(cosName);
        if (pdAbstractPattern instanceof PDTilingPattern) {
            PDTilingPattern pdTilingPattern = (PDTilingPattern) pdAbstractPattern;
            replaceBitmapImagesResources(pdTilingPattern.getResources(), formXObject);
        }
    }

    List<COSName> xobjectsToReplace = new ArrayList<>();
    for (COSName cosName : resources.getXObjectNames()) {
        PDXObject pdxObject = resources.getXObject(cosName);
        if (pdxObject instanceof PDImageXObject) {
            xobjectsToReplace.add(cosName);
        } else if (pdxObject instanceof PDFormXObject) {
            PDFormXObject pdFormXObject = (PDFormXObject) pdxObject;
            replaceBitmapImagesResources(pdFormXObject.getResources(), formXObject);
        }
    }

    for (COSName cosName : xobjectsToReplace) {
        resources.put(cosName, formXObject);
    }
}

(RemoveImages帮助器方法)

若要将此方法应用于PDDocument,只需使用该文档作为参数调用第一个replaceBitmapImagesResources

注意:我试图保持代码简单;对于生产使用,请记住限制此处的递归,以防止无休止的递归,因为在某些PDF中,XObject或模式直接或间接地调用自身。此外,您可能需要检查页面批注和模板页面的资源。

相关文章