我需要在“PDF”(不是整个PDF页面)的ColorSpace级别设置overprint = true。我正在尝试使用PDFBox解决这个问题。
同样,我想仅为特定的colorSpace应用叠印(参见下面示例代码中的If条件),但是graphicsState.setStrokingOverprintControl(true);似乎是为整个PDF页面(所有colorSpaces)设置叠印。
以下是示例代码。有谁遇到过这个问题?我错过了什么吗?
示例代码:
public static void fixPdfOverprint(String inputFilePath, String outputFilePath) throws IOException {
final ByteArrayInputStream pdfStream = new ByteArrayInputStream(readFileIntoMemory(inputFilePath));
try(PDDocument document = PDDocument.load(pdfStream)) {
for (PDPage page : document.getDocumentCatalog().getPages()) {
try(PDPageContentStream contentStream = createPageContentStream(document, page)) {
PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
PDResources pdResources = document.getDocumentCatalog().getPages().get(0).getResources();
for (COSName cosName : pdResources.getColorSpaceNames()) {
if(cosName.getName().equals("<my specific colorSpace>")) {
graphicsState.setStrokingOverprintControl(true); // Why this is setting for the entire page rathen than just this colorSpace. Btw - I confirmed that this if condition is correct.
}
}
contentStream.setGraphicsStateParameters(graphicsState);
}
}
document.save(outputFilePath);
}
}
答案 0 :(得分:1)
以下是一些仅适用于页面内容流的代码。它不处理xobject表单,模式和任何其他内容流。它基于源代码下载中的RemoveAllText.java示例,但在设置颜色空间后插入ExtGState的设置。请注意,您必须至少进行一次更改//可以看到TODO。
public static void main(String[] args) throws IOException
{
if( args.length != 2 )
{
usage();
}
else
{
try (PDDocument document = PDDocument.load(new File(args[0])))
{
if (document.isEncrypted())
{
System.err.println(
"Error: Encrypted documents are not supported for this example.");
System.exit(1);
}
for (PDPage page : document.getPages())
{
insertOverprint(page, document);
}
document.save(args[1]);
}
}
}
private static void insertOverprint(PDPage page, PDDocument document) throws IOException
{
// non stroking overprint control true
PDExtendedGraphicsState extGStateNonStrokingOverprintCtrlTrue = new PDExtendedGraphicsState();
extGStateNonStrokingOverprintCtrlTrue.setNonStrokingOverprintControl(true);
COSName nameExtGStateNonStrokingOverprintCtrlTrue = page.getResources().add(extGStateNonStrokingOverprintCtrlTrue);
// stroking overprint control true
PDExtendedGraphicsState extGStateStrokingOverprintCtrlTrue = new PDExtendedGraphicsState();
extGStateStrokingOverprintCtrlTrue.setStrokingOverprintControl(true);
COSName nameExtGStateStrokingOverprintCtrlTrue = page.getResources().add(extGStateStrokingOverprintCtrlTrue);
// non stroking overprint control false
PDExtendedGraphicsState extGStateNonStrokingOverprintCtrlFalse = new PDExtendedGraphicsState();
extGStateNonStrokingOverprintCtrlFalse.setNonStrokingOverprintControl(false);
COSName nameExtGStateNonStrokingOverprintCtrlFalse = page.getResources().add(extGStateNonStrokingOverprintCtrlFalse);
// stroking overprint control false
PDExtendedGraphicsState extGStateStrokingOverprintCtrlFalse = new PDExtendedGraphicsState();
extGStateStrokingOverprintCtrlFalse.setStrokingOverprintControl(false);
COSName nameExtGStateStrokingOverprintCtrlFalse = page.getResources().add(extGStateStrokingOverprintCtrlFalse);
PDFStreamParser parser = new PDFStreamParser(page);
List<Object> newTokens = new ArrayList<>();
Object token = parser.parseNextToken();
while (token != null)
{
if (token instanceof Operator && !newTokens.isEmpty())
{
String opname = ((Operator) token).getName();
Object lastToken = newTokens.get(newTokens.size() - 1);
// check whether this is an operator that sets colorspace and was preceded by a name
if (lastToken instanceof COSName && !"Pattern".equals(((COSName) lastToken).getName()) &&
("CS".equals(opname.toUpperCase()) || "SCN".equals(opname.toUpperCase())))
{
// get last item = argument = colorspace name
COSName name = (COSName) lastToken;
System.out.println(name.getName() + " " + opname);
newTokens.add(token);
if (true) // TODO !here! add code to check whether this is the correct colorspace name
{
if (Character.isUpperCase(opname.charAt(0)))
{
// stroking
newTokens.add(nameExtGStateStrokingOverprintCtrlTrue);
}
else
{
// nonstroking
newTokens.add(nameExtGStateNonStrokingOverprintCtrlTrue);
}
}
else
{
if (opname.contains("S"))
{
// stroking
newTokens.add(nameExtGStateStrokingOverprintCtrlFalse);
}
else
{
// nonstroking
newTokens.add(nameExtGStateNonStrokingOverprintCtrlFalse);
}
}
// Set parameters from graphics state parameter dictionary
newTokens.add(Operator.getOperator("gs"));
token = parser.parseNextToken();
continue;
}
// check all operators that implicitely set a colorspace
else if ("G".equals(opname.toUpperCase()) || "RG".equals(opname.toUpperCase()) || "K".equals(opname.toUpperCase()))
{
newTokens.add(token);
if (Character.isUpperCase(opname.charAt(0)))
{
// stroking
newTokens.add(nameExtGStateStrokingOverprintCtrlFalse);
}
else
{
// nonstroking
newTokens.add(nameExtGStateNonStrokingOverprintCtrlFalse);
}
// Set parameters from graphics state parameter dictionary
newTokens.add(Operator.getOperator("gs"));
token = parser.parseNextToken();
continue;
}
}
newTokens.add(token);
token = parser.parseNextToken();
}
PDStream newContents = new PDStream(document);
try (OutputStream out = newContents.createOutputStream(COSName.FLATE_DECODE))
{
ContentStreamWriter writer = new ContentStreamWriter(out);
writer.writeTokens(newTokens);
}
page.setContents(newContents);
}
/**
* This will print the usage for this document.
*/
private static void usage()
{
System.err.println("Usage: java " + InsertOverprint.class.getName() + " <input-pdf> <output-pdf>");
}
更多解释:sc,scn,SC和SCN是设置描边或非描边颜色的操作符。大写操作符用于描边操作,小写操作符用于非描边操作符。在内容流中,颜色空间的名称位于运算符之前。我排除了“图案”颜色,因为它不是真正的颜色空间。
更新25.7.2017:RemoveAllTexts example(我用作此问题的起点)已得到改进,现在它不仅处理页面和xobject表单,还处理模式。要根据此处的操作对其进行修改,请查看createTokensWithoutText()
。