我正在使用Java中的iText从一个大的PDF文档中选择一些页面并保存为一个新的较小的PDF.与此同时,我想改变他们的颜色.
例如,假设我的页面都使用灰色阴影,我想将其设为绿色.使用的所有颜色都是灰色阴影.我想用绿色的相应颜色替换每种颜色.
Mark Storer问道:
你到底想要完成什么?
把这个...变成这个:


我有一些文件,我已经在使用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()
Run Code Online (Sandbox Code Playgroud)
(它在Scala中,但iText库与Java中的相同)
问题是,iText提供的所有混合模式都是"可分离"模式:它们独立地在每个颜色通道上运行.这意味着我可以单独调整青色,品红色,黄色或黑色值,但我不能将灰色变为绿色.
要做到这一点,我需要使用颜色混合模式,这是"不可分离",即颜色通道相互影响.据我所知,iText没有提供 - 没有任何非分离混合模式列在常量中PdfGState.我正在使用iText 5.0.5,这是写这篇文章时的最新版本.
有没有办法在iText中访问这些混合模式,甚至是黑客入侵?还有另一种方法可以达到效果吗?
更新:
即使将混合模式设置为Color也不起作用.我在代码中这样做是为了强制它:
val gstate = new PdfGState
gstate.put(PdfName.BM, new PdfName("Color"))
canvas.setGState(gstate)
Run Code Online (Sandbox Code Playgroud)
我在文本编辑器中检查了生成的PDF,以确保它说得对.可悲的是,屏幕上的结果不起作用.我不知道为什么,根据PDF规范应该是正确的混合模式.
Mark Storer问道:
"颜色"不起作用?质朴.我们能看到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)
Run Code Online (Sandbox Code Playgroud)
而且这里是它产生的PDF.在Chrome或Acrobat中不太对劲:)
编辑:傻我.我将模式更改为"Luminosity",生成此文件.和以前一样,这在Chrome中看起来是正确的,但在Acrobat中却看不到.
我刚检查过,甚至Adobe Reader X都没有正确呈现它.这可能意味着我所要求的是不可能的.:(
解
来自Adobe的伦纳德罗森塔尔回到我身边,澄清了问题:"颜色"混合模式仅在变换空间为RGB而非CMYK时才有效.我的PDF没有指定空间,因此Adobe产品默认为CMYK,而其他默认为RGB.
iText中的解决方案是在顶部附近添加此行:
writer.setRgbTransparencyBlending(true)
Run Code Online (Sandbox Code Playgroud)
当然,为了颜色准确性,您不需要比绝对必要的颜色空间转换更多,因此如果您确实需要使用RGB混合模式,请仅使用此行.
从Photoshop用户的角度来看,制作的彩色页面看起来有点奇怪:看起来浅灰色比黑色灰色更饱满.我正在研究组合过滤器以调整输出的方法.
非常感谢Mark Storer帮助我实现这一解决方案.
如果您一直想要从"灰色阴影"变为"颜色X的阴影",您可以使用透明度和一些时髦的混合模式.
如果您想浏览所有内容流并编辑现有的颜色命令,这是一个非常高的顺序.你必须考虑各种各样的colo(u)r空间.DeviceGray,DeviceRGB,DeviceCMYK,ICC配置文件,校准RGB和CMYK,专色和So Forth.
你到底想要完成什么?
"颜色"不起作用?质朴.我们能看到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)
呃...只有你现有的页面都是deviceGray,对吧?不...... CMYK也只是K's.您需要一个采用K值的传递函数,并根据您想要的颜色输出将它们映射到CMYK.
然后我看了你如何在PDF中定义一个函数.这么简单.域名和范围和样本哦,我的!不完全是微不足道的.
不过,这可能会奏效.
(虽然我仍然认为你应该找到一个可以在Acrobat中运行的混合PDF,看看有什么区别)
最后的努力:PM Leonard Rosenthol.他在这里有一个账号.他是Adobe的Acrobat开发者关系人员.告诉他Mark Storer很难过.这应引起他的注意.;)