PDF 图像软蒙版伪影
PDF image soft mask artifacts
我正在使用 C++ 开发 PDF 生成器。
在过程中,我遇到了图像软掩模的大问题。
我像上面一样在 PDF 页面的右侧放了一张图片。粉红熊是位图图像,具有 Alpha 通道。但是,它还没有PDF掩码。
在我成功将图像正确放置之后。我需要找到一种方法来删除图像的黑色背景。 (a.k.a alpha 处理)
我发现有几个选项可以将其存档,如下所示。
- 单色蒙版。
- 模板掩码。
- 软面膜。
我的应用程序有渐变图像。因此,软面膜方法对我来说是最好的。所以,我如下实现它。
图像的黑色背景消失了。看来一切都很好。
但是,当我放大结果时,我发现有一些瑕疵。
左侧是带有 alpha 的正确图像,右侧是 PDF 结果。
熊的轮廓周围有黑色噪点。(单击图像可显示大图)当我放置矩形图像时,我发现边缘周围有黑线。
好像RGB通道和A通道不完全匹配(好像A通道大了1~2px)
我是这样实现的。
- 我制作了一个 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
我就是这么做的。我需要做更多的事情吗?
我花了一周的时间来修复它。但是,即使我在 google.
上搜索,我仍然没有任何想法
我附上结果文件。
https://www.dropbox.com/s/09ggj28bhzi8f6e/Output.pdf?dl=0
拜托,有人给我一些建议。
**** 更新 ****
我制作了更简单的版本进行测试。
我制作了位图。然后我在图像的左侧绘制了一个白色矩形,如上所示。右边是空的。
将位图放在 PDF 上并通过其 alpha 值应用软蒙版后,
白色矩形的边缘有一条黑线。 (左边画的是白色矩形,右边是透明的。)
位图的alpha通道与上图完全相同。我已经在 Photoshop 上检查过了。 Alpha通道中没有任何灰色,每个像素都与RGB通道完全匹配。
我附上 PDF 结果。
这个问题看起来很老,但仍然有人偶然发现它,我有一个类似的问题,透明图像边缘周围出现灰色细线,我发现这个问题是因为 “图像平滑” 通过 PDF 查看器。为确认,您可以在 Adobe Acrobat Reader 中打开文档并从首选项中关闭图像平滑,线条将消失 - 但由于它依赖于查看器,因此不能依赖此解决方案。
在多次检查 pdf 规范以确保 alpha 被正确分割并进行大量在线搜索后,我认为问题在于透明像素实际上是 "透明黑色" 或 rgba(0,0,0,0) 等观察者自然会尝试混合边缘上的颜色,从而创建一条灰线。我使用的是从浏览器生成的图像,浏览器将 alpha=0 的任何像素视为“透明黑色”。这些 GitHub 问题中给出了更多详细信息:#issue1 #issue2 但是提到的解决方案,将像素转换为“透明白色”rgba(255,255,255,0),如果背景和图像是改为黑色。
我对 image-smoothing/anti-aliasing 算法了解不多,但我 将每个完全透明像素的 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--;
}
我正在使用 C++ 开发 PDF 生成器。
在过程中,我遇到了图像软掩模的大问题。
我像上面一样在 PDF 页面的右侧放了一张图片。粉红熊是位图图像,具有 Alpha 通道。但是,它还没有PDF掩码。
在我成功将图像正确放置之后。我需要找到一种方法来删除图像的黑色背景。 (a.k.a alpha 处理)
我发现有几个选项可以将其存档,如下所示。
- 单色蒙版。
- 模板掩码。
- 软面膜。
我的应用程序有渐变图像。因此,软面膜方法对我来说是最好的。所以,我如下实现它。
图像的黑色背景消失了。看来一切都很好。
但是,当我放大结果时,我发现有一些瑕疵。
左侧是带有 alpha 的正确图像,右侧是 PDF 结果。
熊的轮廓周围有黑色噪点。(单击图像可显示大图)当我放置矩形图像时,我发现边缘周围有黑线。
好像RGB通道和A通道不完全匹配(好像A通道大了1~2px)
我是这样实现的。
- 我制作了一个 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
我就是这么做的。我需要做更多的事情吗?
我花了一周的时间来修复它。但是,即使我在 google.
上搜索,我仍然没有任何想法我附上结果文件。
https://www.dropbox.com/s/09ggj28bhzi8f6e/Output.pdf?dl=0
拜托,有人给我一些建议。
**** 更新 ****
我制作了更简单的版本进行测试。
我制作了位图。然后我在图像的左侧绘制了一个白色矩形,如上所示。右边是空的。
将位图放在 PDF 上并通过其 alpha 值应用软蒙版后, 白色矩形的边缘有一条黑线。 (左边画的是白色矩形,右边是透明的。)
位图的alpha通道与上图完全相同。我已经在 Photoshop 上检查过了。 Alpha通道中没有任何灰色,每个像素都与RGB通道完全匹配。
我附上 PDF 结果。
这个问题看起来很老,但仍然有人偶然发现它,我有一个类似的问题,透明图像边缘周围出现灰色细线,我发现这个问题是因为 “图像平滑” 通过 PDF 查看器。为确认,您可以在 Adobe Acrobat Reader 中打开文档并从首选项中关闭图像平滑,线条将消失 - 但由于它依赖于查看器,因此不能依赖此解决方案。
在多次检查 pdf 规范以确保 alpha 被正确分割并进行大量在线搜索后,我认为问题在于透明像素实际上是 "透明黑色" 或 rgba(0,0,0,0) 等观察者自然会尝试混合边缘上的颜色,从而创建一条灰线。我使用的是从浏览器生成的图像,浏览器将 alpha=0 的任何像素视为“透明黑色”。这些 GitHub 问题中给出了更多详细信息:#issue1 #issue2 但是提到的解决方案,将像素转换为“透明白色”rgba(255,255,255,0),如果背景和图像是改为黑色。
我对 image-smoothing/anti-aliasing 算法了解不多,但我 将每个完全透明像素的 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--;
}