Неправильная комбинация мягкой маски группы прозрачности и маски изображения PNG - PullRequest
0 голосов
/ 31 октября 2018

У меня есть мягкая маска на основе TransparencyGroup, как описано в 7.5.4 спецификации PDF. Это работает нормально, когда изображение, к которому я применяю маску, является 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 голосов
/ 08 ноября 2018

Таким образом, это будет вероятным случаем, потому что мягкая маска изображения переопределит мягкую маску в графическом состоянии.

Действительно, мягкие маски, установленные с помощью графического состояния, и мягкие маски, установленные с изображением, по сути, работают одинаково, и в то же время может быть только одна активная мягкая маска.

Теперь вопрос сводится к следующему: есть ли в 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...