iText PDF:替换/转换颜色

时间:2011-01-11 00:23:24

标签: pdf colors itext

我在Java中使用iText从大型PDF文档中选择几页并保存为新的较小的PDF。与此同时,我想改变他们的颜色。

例如,假设我的页面都使用灰色阴影,我想将其设为绿色。使用的所有颜色都是灰色阴影。我想用绿色的相应颜色替换每种颜色。


Mark Storer问道:

  

你到底想要完成什么?

将此...改为:

gray page green page

我有some documents,我已经使用iText根据用户输入从文档中选择一组较小的页面 - 将页面减少到100页以下,大约为5页。同时我希望生产绿色,蓝色,黄色,粉红色等版本。不是每个页面都是灰度级的,而是所有重要的页面,所以如果需要,我可以强制它们的颜色空间。


更新

按照Mark Storer关于混合模式的建议,这就是我所拥有的:

    val reader = new PdfReader(file.toURL)
    val document = new Document
    val writer = PdfWriter.getInstance(document, outputStream)
    document.open()

    /* draw a white background behind the page, so the
       blend always has something to transform, otherwise
       it just fills. */
    val canvas = writer.getDirectContent
    canvas.setColorFill(new CMYKColor(0.0f, 0.0f, 0.0f, 0.0f))
    canvas.rectangle(10f, 0f, 100f, 100f)
    canvas.fill

    /* Put the imported page on top of that */
    val page = writer.getImportedPage(reader, 1)
    canvas.addTemplate(page, 0, 0)

    /* Fill a box with colour and a blending mode */
    canvas.setColorFill(new CMYKColor(0.6f,0.1f,0.0f,0.5f))
    val gstate = new PdfGState
    gstate.setBlendMode(PdfGState.BM_SCREEN)
    canvas.setGState(gstate)
    canvas.rectangle(0f, 0f, 100f, 100f)
    canvas.fill

    document.close()

(它在Scala中,但iText库与Java中的相同)

问题是,iText提供的所有混合模式都是“可分离”模式:它们独立地在每个颜色通道上运行。这意味着我可以单独调整青色,品红色,黄色或黑色值,但我不能将灰色变为绿色。

要做到这一点,我需要使用颜色混合模式,即“不可分离”,即颜色通道相互影响。据我所知,iText没有提供 - PdfGState中的常量中没有列出任何非分离混合模式。我正在使用iText 5.0.5,这是写这篇文章时的最新版本。

有没有办法在iText中访问这些混合模式,甚至是黑客入侵?还有另一种方法可以达到结果吗?


更新

即使将混合模式设置为“颜色”也不起作用。我在代码中这样做是为了强制它:

    val gstate = new PdfGState
    gstate.put(PdfName.BM, new PdfName("Color"))
    canvas.setGState(gstate)

我在文本编辑器中检查了生成的PDF,以确保它说得对。可悲的是,屏幕上的结果不起作用。我不知道为什么,根据PDF规范应该是正确的混合模式。


Mark Storer问道:

  

“颜色”不起作用?质朴。我们能看到PDF吗?

Here's a PDF

将它放在网络上,我现在可以看到“颜色”模式在Chrome中正常工作,但在Acrobat 9 Pro(CS4)中不起作用。所以这项技术是正确的,但Adobe在渲染时失败了!

我想知道是否没有某种方法可以“展平”混合模式的效果,因此PDF直接包含所需的颜色对象,而不是用于产生正确颜色的混合。

  

想法:将其颠倒过来。将现有页面用作填充页面上的Alpha通道   完全用所需的颜色而不是相反的方式。

如何?我不确定GState是否适用于添加模板?

此外,导入的页面首先需要添加白色背景,或者只有在没有对象而不是混合的情况下,它只会泛起颜色。

我试过这样做:

    val canvas = writer.getDirectContent
    canvas.setColorFill(new CMYKColor(0.6f,0.1f,0.0f,0.0f))
    canvas.rectangle(10f, 0f, 500f, 500f)
    canvas.fill

    val template = canvas.createTemplate(500f, 500f)
    template.setColorFill(new CMYKColor(0f, 0f, 0f, 0f))
    template.rectangle(0f, 0f, 500f, 500f)
    template.fill

    val page = writer.getImportedPage(reader, 1)
    template.addTemplate(page, 0, 0)

    val gstate = new PdfGState
    gstate.put(PdfName.BM, new PdfName("Color"))
    canvas.setGState(gstate)
    canvas.addTemplate(template, 0, 0)

here's the PDF it produced。在Chrome或Acrobat中不太对劲:)

编辑:傻傻的我。我将模式更改为“Luminosity”,producing this file。和以前一样,这在Chrome中看起来不正确,但在Acrobat中看起来不正确。


我刚检查过,甚至Adobe Reader X都没有正确呈现它。这可能意味着我所要求的是不可能的。 :(


解决方案

来自Adobe的Leonard Rosenthal回复了我,并澄清了问题:“颜色”混合模式仅在转换空间为RGB而非CMYK时才有效。我的PDF没有指定空间,因此Adobe产品默认为CMYK,而其他产品默认为RGB。

iText中的解决方案是将此行添加到顶部附近:

    writer.setRgbTransparencyBlending(true)

当然,为了颜色准确性,您不需要比绝对必要的颜色空间转换更多,所以如果您确实需要使用RGB混合模式,请仅使用此行。

从Photoshop用户的角度来看,制作的彩色页面看起来有点奇怪:看起来浅灰色比黑色灰色更饱满。我正在研究组合过滤器以调整输出的方法。

Here's the result!

非常感谢Mark Storer帮助我实现这一解决方案。

1 个答案:

答案 0 :(得分:5)

如果你一直想从“灰色阴影”变为“颜色X阴影”,你可以在一些时髦的混合模式下使用透明度。

如果您想浏览所有内容流并编辑现有的颜色命令,这是一个非常高的顺序。你必须考虑各种各样的colo(u)r空间。 DeviceGray,DeviceRGB,DeviceCMYK,ICC配置文件,校准RGB和CMYK,专色,以及此类。

你到底想要完成什么?


“颜色”不起作用?质朴。我们能看到PDF吗?


想法:将其颠倒过来。将现有页面用作完全填充所需颜色的页面上的Alpha通道,而不是相反。


再试一次。而不是混合,使用传递函数。您需要构建一个Function字典。您坚持使用CMYK,因此将任何和所有输入填充到特定输出中应该相当简单。

类似的东西:

C:[0 1] - > [0 0.6]
M:[0 1] - > [0 0.1]
Y:[0 1] - > [0 0]
K:[0 1] - > [0 0]

(我从你的PDF中刷了0.6 0.1 0 0)

Urgh ...只有你现有的页面都是deviceGray,对吧?不...... CMYK也只是K's。你需要一个带有K值的传递函数,并根据你想要的颜色输出将它们映射到CMYK。

然后我看了你如何在PDF中定义一个函数。这么简单。域名和范围和样本哦,我的!不完全是微不足道的。

不过,这可能会奏效。

(虽然我仍然认为你应该找到一个适用于Acrobat的混合PDF,看看有什么不同之处)


最后的努力: PM Leonard Rosenthol。他在这里有一个账号。他是Adobe的Acrobat开发者关系人员。告诉他Mark Storer很难过。这应引起他的注意。 ;)