PDFBox 覆盖失败
PDFBox Overlay fails
我使用 PDFBox 1.8.8 并尝试使用以下 Scala 方法将 PDDocument 与其他文档叠加
def mergeTest() = {
val home = System.getProperty("user.home")
val doc = PDDocument.load(home + "/tmp/document.pdf")
val ovl = PDDocument.load(home + "/tmp/overlay.pdf")
val ov = new Overlay()
val mergeDoc = ov.overlay(ovl, doc)
mergeDoc.save(home + "/tmp/result.pdf")
doc.close()
ovl.close()
mergeDoc.close()
}
我希望 "document.pdf"(N 页)的每一页都覆盖 "overlay.pdf"(1 页)的内容。
因此 "result.pdf" 中的页面与 "document.pdf" 中的页面一样多,但是 "document.pdf" 中的原始内容完全被叠加的内容覆盖。
原因
OP 的 overlay.pdf 页面内容以
开头
/Cs1 cs
1 sc
0.1400146 841.945 m
595.14 841.945 l
595.14 -0.05499268 l
0.1400146 -0.05499268 l
h
f
0.1400146 841.945 m
595.14 841.945 l
595.14 -0.05499268 l
0.1400146 -0.05499268 l
h
f
这些操作绘制了两个白色(CS1是灰度颜色space)的矩形,几乎覆盖了整个MediaBox[0, 0, 595.28, 841.89]
除了顶部和左侧的一条非常细的线
因此,将此页面内容放在另一个页面上,完全覆盖了该页面的所有现有内容,这正是您所观察到的:
the original content of "document.pdf" is completely overwritten by the content of the overlay
通常只有覆盖一个没有涵盖所有内容的页面才有意义。
A work-around 使用混合模式 Darken
或者,您可能想尝试使用混合模式 Darken 进行叠加,选择较暗的背景色和源颜色,背景被替换为源较暗的源;否则,保持不变。
在Java中(我没有使用过Scala,所以我希望你能利用Java源代码)你可以使用这样的方法:
void overlayWithDarkenBlendMode(PDDocument document, PDDocument overlay) throws IOException
{
PDXObjectForm xobject = importAsXObject(document, (PDPage) overlay.getDocumentCatalog().getAllPages().get(0));
PDExtendedGraphicsState darken = new PDExtendedGraphicsState();
darken.getCOSDictionary().setName("BM", "Darken");
List<PDPage> pages = document.getDocumentCatalog().getAllPages();
for (PDPage page: pages)
{
Map<String, PDExtendedGraphicsState> states = page.getResources().getGraphicsStates();
if (states == null)
states = new HashMap<String, PDExtendedGraphicsState>();
String darkenKey = MapUtil.getNextUniqueKey(states, "Dkn");
states.put(darkenKey, darken);
page.getResources().setGraphicsStates(states);
PDPageContentStream stream = new PDPageContentStream(document, page, true, false, true);
stream.appendRawCommands(String.format("/%s gs ", darkenKey));
stream.drawXObject(xobject, 0, 0, 1, 1);
stream.close();
}
}
PDXObjectForm importAsXObject(PDDocument target, PDPage page) throws IOException
{
final PDStream xobjectStream = new PDStream(target, page.getContents().createInputStream(), false);
final PDXObjectForm xobject = new PDXObjectForm(xobjectStream);
xobject.setResources(page.findResources());
xobject.setBBox(page.findCropBox());
COSDictionary group = new COSDictionary();
group.setName("S", "Transparency");
group.setBoolean(COSName.getPDFName("K"), true);
xobject.getCOSStream().setItem(COSName.getPDFName("Group"), group);
return xobject;
}
将它们应用到您的示例文档中
@Test
public void testOverlayWithDarkenVolker() throws COSVisitorException, IOException
{
try ( InputStream sourceStream = getClass().getResourceAsStream("document1.pdf");
InputStream overlayStream = getClass().getResourceAsStream("overlay.pdf") )
{
final PDDocument document = PDDocument.load(sourceStream);
final PDDocument overlay = PDDocument.load(overlayStream);
overlayWithDarkenBlendMode(document, overlay);
document.save(new File(RESULT_FOLDER, "document1-with-overlay.pdf"));
}
}
结果
如您所见,document1.pdf 中的数字和 overlay.pdf 中的行都在那里。
当心! 此代码是 proof-of-concept,尚未准备好用于一般生产用途。它例如完全忽略 旋转 页面条目...
我使用 PDFBox 1.8.8 并尝试使用以下 Scala 方法将 PDDocument 与其他文档叠加
def mergeTest() = {
val home = System.getProperty("user.home")
val doc = PDDocument.load(home + "/tmp/document.pdf")
val ovl = PDDocument.load(home + "/tmp/overlay.pdf")
val ov = new Overlay()
val mergeDoc = ov.overlay(ovl, doc)
mergeDoc.save(home + "/tmp/result.pdf")
doc.close()
ovl.close()
mergeDoc.close()
}
我希望 "document.pdf"(N 页)的每一页都覆盖 "overlay.pdf"(1 页)的内容。
因此 "result.pdf" 中的页面与 "document.pdf" 中的页面一样多,但是 "document.pdf" 中的原始内容完全被叠加的内容覆盖。
原因
OP 的 overlay.pdf 页面内容以
开头/Cs1 cs
1 sc
0.1400146 841.945 m
595.14 841.945 l
595.14 -0.05499268 l
0.1400146 -0.05499268 l
h
f
0.1400146 841.945 m
595.14 841.945 l
595.14 -0.05499268 l
0.1400146 -0.05499268 l
h
f
这些操作绘制了两个白色(CS1是灰度颜色space)的矩形,几乎覆盖了整个MediaBox[0, 0, 595.28, 841.89]
除了顶部和左侧的一条非常细的线
因此,将此页面内容放在另一个页面上,完全覆盖了该页面的所有现有内容,这正是您所观察到的:
the original content of "document.pdf" is completely overwritten by the content of the overlay
通常只有覆盖一个没有涵盖所有内容的页面才有意义。
A work-around 使用混合模式 Darken
或者,您可能想尝试使用混合模式 Darken 进行叠加,选择较暗的背景色和源颜色,背景被替换为源较暗的源;否则,保持不变。
在Java中(我没有使用过Scala,所以我希望你能利用Java源代码)你可以使用这样的方法:
void overlayWithDarkenBlendMode(PDDocument document, PDDocument overlay) throws IOException { PDXObjectForm xobject = importAsXObject(document, (PDPage) overlay.getDocumentCatalog().getAllPages().get(0)); PDExtendedGraphicsState darken = new PDExtendedGraphicsState(); darken.getCOSDictionary().setName("BM", "Darken"); List<PDPage> pages = document.getDocumentCatalog().getAllPages(); for (PDPage page: pages) { Map<String, PDExtendedGraphicsState> states = page.getResources().getGraphicsStates(); if (states == null) states = new HashMap<String, PDExtendedGraphicsState>(); String darkenKey = MapUtil.getNextUniqueKey(states, "Dkn"); states.put(darkenKey, darken); page.getResources().setGraphicsStates(states); PDPageContentStream stream = new PDPageContentStream(document, page, true, false, true); stream.appendRawCommands(String.format("/%s gs ", darkenKey)); stream.drawXObject(xobject, 0, 0, 1, 1); stream.close(); } } PDXObjectForm importAsXObject(PDDocument target, PDPage page) throws IOException { final PDStream xobjectStream = new PDStream(target, page.getContents().createInputStream(), false); final PDXObjectForm xobject = new PDXObjectForm(xobjectStream); xobject.setResources(page.findResources()); xobject.setBBox(page.findCropBox()); COSDictionary group = new COSDictionary(); group.setName("S", "Transparency"); group.setBoolean(COSName.getPDFName("K"), true); xobject.getCOSStream().setItem(COSName.getPDFName("Group"), group); return xobject; }
将它们应用到您的示例文档中
@Test
public void testOverlayWithDarkenVolker() throws COSVisitorException, IOException
{
try ( InputStream sourceStream = getClass().getResourceAsStream("document1.pdf");
InputStream overlayStream = getClass().getResourceAsStream("overlay.pdf") )
{
final PDDocument document = PDDocument.load(sourceStream);
final PDDocument overlay = PDDocument.load(overlayStream);
overlayWithDarkenBlendMode(document, overlay);
document.save(new File(RESULT_FOLDER, "document1-with-overlay.pdf"));
}
}
结果
如您所见,document1.pdf 中的数字和 overlay.pdf 中的行都在那里。
当心! 此代码是 proof-of-concept,尚未准备好用于一般生产用途。它例如完全忽略 旋转 页面条目...