我正在使用 C++ 开发 PDF 生成器。
在处理过程中,我遇到了图像软掩模的一个大问题。
我将图像放在 PDF 页面的右侧,如上所示。粉红熊是位图图像并具有 Alpha channel 。但是,它还没有 PDF 蒙版。
在我成功地以正确的方式放置图像之后。我需要找到一种方法来删除图像的黑色背景。 (又名 Alpha 处理)
我发现有几个选项可以将其存档,如下所示。
- 单色蒙版。
- 模板掩模。
- 软 mask 。
我的应用程序有渐变图像。因此,软面膜法对我来说是最好的。因此,我按照如下方式实现了它。
图像的黑色背景消失了。看来一切都很好。
但是,当我放大结果时,我意识到存在一些伪影。
左侧是带有 Alpha 的正确图像,右侧是 PDF 结果。
熊的轮廓周围有黑色噪音。(单击图像可显示大图)当我放置矩形图像时,我可以在边缘发现黑色线条。
RGB channel 和A channel 似乎不完全匹配。(好像A channel 大了1~2 px)
我的实现如下。
- 我制作了一个 XObject (SMask)
8 0 obj
<<
/Type /XObject
/Subtype /Image
/Width 693
/Height 972
/BitsPerComponent 8
/Filter /FlateDecode
/ColorSpace /DeviceGray
/Length 137856
>>
stream
- 将 XObject 链接到原始图像。
7 0 obj
<<
/Type /XObject
/Subtype /Image
/Width 693
/Height 972
/BitsPerComponent 8
/Filter /FlateDecode
/ColorSpace /DeviceRGB
/SMask 8 0 R
/Length 261436
>>
stream
这就是我所做的一切。我还需要做更多的事情吗?
我花了一周时间来修复它。但是,即使我在谷歌上搜索,我仍然没有任何想法。
我附上结果文件。
https://www.dropbox.com/s/09ggj28bhzi8f6e/Output.pdf?dl=0
请有人给我一些建议。
**** 更新 ****
我制作了更简单的版本进行测试。
我制作了一个位图。我在图像左侧画了一个白色矩形,如上所示。右侧是空的。
将位图放入 PDF 并通过其 alpha 值应用软掩模后, 白色矩形的边缘有一条黑线。 (左侧绘制白色矩形。右侧是透明的。)
位图的 Alpha channel 与上图完全相同。我已经在 Photoshop 上检查过了。 Alpha channel 中没有任何灰色,并且每个像素与RGB channel 完全匹配。
我附上了 PDF 结果。
最佳答案
这个问题看起来很老,但仍然以防万一有人偶然发现它,我有一个类似的问题,透明图像边缘周围出现细灰线,并发现问题是由于“图像平滑”通过 PDF 查看器。为了进行确认,您可以在 Adobe Acrobat Reader 中打开文档并从首选项中关闭图像平滑功能,线条将会消失 - 但由于它依赖于查看器,因此不能依赖此解决方案。
在多次检查 pdf 规范以确保 Alpha 被正确分割并进行大量在线搜索后,我认为问题在于透明像素实际上是“透明黑色” 或 rgba(0,0,0,0),因此观看者自然会尝试混合边缘上的颜色,从而创建一条灰线。我使用的是从浏览器生成的图像,浏览器将 alpha=0 的任何像素视为“透明黑色”。这些 GitHub 问题中给出了更多详细信息:#issue1 #issue2但提到的解决方案,将像素转换为“透明白色”rgba(255,255,255,0),如果背景和图像更改为黑色,则会导致相同的问题。
我对图像平滑/抗锯齿算法了解不多,但我将每个完全透明像素的 RGB 颜色更改为周围像素的平均值,并且伪像消失了!(保持 alpha 为 0) 运行几次平均函数会得到更平滑的结果,并且由于它们是透明像素,只要没有正在生产硬边。
这只是一次测试运行,可能有更好、更快的图像平滑选项。 imgData 是您的 RGB 像素流,alphaChannel 是软掩模
let iterations = 10;
while (iterations > 0) {
let p = 0,
a = 0;
for (a = 0; a < pixelCount; a++) {
if (alphaChannel[a] !== 0) {
p += colorCount;
continue;
}
const colorSum = {r: 0, g: 0, b: 0};
let count = 0;
for (i = -2; i < 3; i++) {
for (let j = -2; j < 3; j++) {
const index = (a + i + j * this.width) * colorCount;
if (index < 0 || index >= this.width * this.height * colorCount) {
continue
}
colorSum.r += imgData[index];
colorSum.g += imgData[index + 1];
colorSum.b += imgData[index + 2];
count++;
}
}
imgData[p++] = colorSum.r / count;
imgData[p++] = colorSum.g / count;
imgData[p++] = colorSum.b / count;
}
iterations--;
}
关于PDF 图像软掩模伪影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62558338/