透明组软蒙版和PNG图像蒙版的错误组合

时间:2018-10-31 15:26:26

标签: itext

我有一个基于TransparencyGroup的软蒙版,如PDF规范的7.5.4中所述。当我将蒙版应用于的图像是JPG时,它可以正常工作,但是当它具有自己的蒙版(如PNG)时,它会失败。

doc = new Document(new Rectangle(ToPdf(210), ToPdf(297)));
pdf = PdfWriter.GetInstance(doc, new FileStream("test.pdf", FileMode.Create));
pdf.PdfVersion = PdfWriter.VERSION_1_4;
pdf.CompressionLevel = PdfStream.NO_COMPRESSION;

doc.Open();
var dc = pdf.DirectContent;

dc.Rectangle(0, 0, ToPdf(210), ToPdf(297));
dc.SetColorFill(BaseColor.BLUE);
dc.Fill();

dc.SaveState();
var mask = Image.GetInstance("mask.jpg");
mask.ScaleAbsoluteHeight(ToPdf(100));
mask.ScaleAbsoluteWidth(ToPdf(100));
mask.SetAbsolutePosition(0, 0);

var transparency = dc.CreateTemplate(ToPdf(100), ToPdf(100));
transparency.Group = new PdfTransparencyGroupEx { ColorSpace = PdfName.DEVICEGRAY };
transparency.AddImage(mask);

var softmask = new PdfSoftMask(PdfName.MASK) {
  Subtype = new PdfName("Luminosity"),
  Group = transparency.IndirectReference,
};
dc.SetGState(new PdfGStateEx {
  SoftMask = softmask,
  AlphaIsShape = false,
});

var picture = Image.GetInstance("test.png"); // or test.jpg
//picture.Smask = false;
picture.ScaleAbsoluteHeight(ToPdf(100));
picture.ScaleAbsoluteWidth(ToPdf(100));
picture.SetAbsolutePosition(0, 0);
dc.AddImage(picture);
dc.RestoreState();

doc.Close();

遮罩只是带有喷泉填充的灰度图像:

Mask.jpg

使用PNG,图片会显示错误的背景:

enter image description here

助手:

public static float ToPdf(double mm) => (float)(mm / 25.4 * 72.0);

public class PdfGStateEx : PdfGState {
  public PdfObject SoftMask {
    set => Put(PdfName.SMASK, value);
  }
}

public class PdfTransparencyGroupEx : PdfTransparencyGroup {
  public PdfName ColorSpace {
    set => Put(PdfName.CS, value);
  }
}

public class PdfSoftMask : PdfDictionary {
  public PdfSoftMask(PdfName type)
    : base(type) {
  }

  public PdfName Subtype {
    set => Put(PdfName.S, value);
  }

  public PdfIndirectReference Group {
    set => Put(new PdfName("G"), value);
  }

  public PdfArray BackdropColor {
    set => Put(PdfName.BC, value);
  }
}

测试文件

一些分析

在所有情况下,图像均已正确嵌入:

/GS1 gs
q 283.46 0 0 283.46 0 0 cm /img1 Do Q

其中的软掩膜字典是:

<<
  /AIS false
  /SMask
  <<
    /G 1 0 R
    /S /Luminosity
    /Type /Mask
  >>
>>

引用透明组XObject:

<<
  /BBox [0 0 283.46 283.46]
  /FormType 1
  /Group
  <<
    /CS /DeviceGray
    /S /Transparency
  >>
  /Length 38
  /Matrix [1 0 0 1 0 0]
  /Resources
  <<
    /XObject
    <<
      /img0 2 0 R
    >>
  >>
  /Subtype /Form
  /Type /XObject
>>

到目前为止没有区别。一个PNG版本实际上清除了SMask条目,然后PNG的固有掩码消失了,这是可以预期的。

因此,可能是这种情况,因为图像的软遮罩将在图形状态下覆盖软遮罩。现在问题归结为:iText中是否支持混合两个遮罩(一个遮罩来自PNG,一个遮罩来自我自己的遮罩),或者在将其提供给iText之前我需要单独执行此操作吗?

1 个答案:

答案 0 :(得分:1)

  

因此,很可能是这种情况,因为图像的软遮罩将在图形状态下覆盖软遮罩。

实际上,通过图形状态设置的软掩膜和为图像设置的软掩膜基本上以相同的方式运行,并且同时只能有一个活动的软掩膜。

  

现在问题归结为:iText中是否支持混合两个遮罩(一个遮罩来自PNG,一个遮罩来自我自己的遮罩),还是在将其提供给iText之前需要单独做?

否, iText中不支持混合两个遮罩; iText仅从外部来源读取图像并将其嵌入PDF或(在提取过程中)从PDF读取图像以导出到某些外部目标,而不会进行进一步处理。

但是仍然不需要在将其提供给iText之前单独进行操作,您可以将此混合操作留给PDF查看器!同时只能有一个活动的软蒙版,您可以使用嵌套透明组来组合不同的透明效果。

只需在代码中替换

dc.AddImage(picture);

作者

var group = dc.CreateTemplate(ToPdf(100), ToPdf(100));
group.Group = new PdfTransparencyGroupEx();
group.AddImage(picture);
dc.AddTemplate(group, 0, 0);

(即,不要将带有软掩膜的图像直接添加到内容中,而是将其添加到单独的透明度组中,然后将该透明度组添加到内容中。)

结果将像这样更改:

without groups -> with groups


顺便说一句,您可以使用实际的连续渐变而不是带有渐变的位图来提高透明蒙版的质量(尤其是在更高的分辨率或缩放级别时)。只需替换

transparency.AddImage(mask);

作者

PdfShading shading = PdfShading.SimpleAxial(pdf, 0, 0, ToPdf(100), 0, BaseColor.BLACK, BaseColor.WHITE);
transparency.PaintShading(shading);