设置"overprint = true";用于PDF上的特定ColorSpace(不是整个PDF页面) [英] Setting "overprint=true" for a specific ColorSpace on PDF (not the entire PDF Page)

查看:122
本文介绍了设置"overprint = true";用于PDF上的特定ColorSpace(不是整个PDF页面)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在ColorSpace级别的"PDF"(不是整个PDF页面)上设置overprint = true.我正在尝试使用PDFBox解决此问题.

I have a requirement to set overprint=true at ColorSpace level on a "PDF" (not for the entire PDF Page). I'm trying to solve this using PDFBox.

同样,我只想对特定的colorSpace应用套印(请参见下面的示例代码中的If条件),但是graphicsState.setStrokingOverprintControl(true);似乎正在为整个PDF页面(所有colorSpaces)设置套印.

Again, I want to apply overprint only for a specific colorSpace (see If condition in the sample code below), but graphicsState.setStrokingOverprintControl(true); seems to be setting overprint for the entire PDF Page (all colorSpaces).

这是示例代码.有人遇到过这个问题吗?我想念什么吗?

Here's the sample code. Anyone came across this problem? Am I missing something?

示例代码:

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);
        }
    }

推荐答案

以下代码仅适用于页面的内容流.它不处理xobject形式,模式以及任何其他内容流.它在某种程度上基于源代码下载中的RemoveAllText.java示例,但是在颜色空间设置之后插入了ExtGState的设置.请注意,您必须至少更改一项才能看到//TODO.

Here's some code that will work only on the content stream of the page. It does not process xobject forms, patterns and whatever other content streams. It is based somewhat on the RemoveAllText.java example from the source code download, but inserts the setting of an ExtGState after the setting of a colorspace. Note that you must do at least one change where //TODO can be seen.

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是用于设置描边或不描边颜色的运算符.大写运算符用于笔触,小写运算符用于非笔触.在内容流中,颜色空间的名称位于运算符之前.我排除了图案"颜色,因为它不是真正的色彩空间.

Some more explanations: sc, scn, SC and SCN are operators to set the stroking or non-stroking colors. The upper case operators are for stroking, the lower case operators for non stroking. In the content stream, the name of the colorspace is before the operator. I excluded the "Pattern" color because it isn't a real colorspace.

2017年2月5日更新:

Update 25.7.2017: The RemoveAllTexts example (which I've used as a starting point for this question) has been improved, now it handles not just the page and xobject forms, but also patterns. To modify it for what is done here, have a look at createTokensWithoutText().

这篇关于设置"overprint = true";用于PDF上的特定ColorSpace(不是整个PDF页面)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆