iTextSharp:恢复状态后丢失的剪辑路径

本文关键字:路径 恢复 状态 iTextSharp | 更新日期: 2023-09-27 18:10:46

我正在使用iTextSharp生成PDF文件。我遇到了一个问题,如果我做Clip()之后SaveState()然后RestoreState(),那么我的剪切路径丢失,进一步的绘图不被剪切。

我不知道这是一个bug在iText/iTextSharp,或者如果我做了一些不正确的。下面是示例c#代码:

using (var fileStream = System.IO.File.OpenWrite(@"Problem.PDF"))
{
    var doc = new iTextSharp.text.Document();
    var writer = iTextSharp.text.pdf.PdfWriter.GetInstance(doc, fileStream);
    doc.Open();
    var content = writer.DirectContent;
    // Stroke where the blue box will be drawn
    content.NewPath();
    content.MoveTo(250, 250);
    content.LineTo(250, 350);
    content.LineTo(350, 350);
    content.LineTo(350, 250);
    content.LineTo(250, 250);
    content.SetRGBColorStroke(0, 0, 255);
    content.Stroke();
    // Stroke where the red box will be drawn
    content.NewPath();
    content.MoveTo(250, 150);
    content.LineTo(250, 250);
    content.LineTo(350, 250);
    content.LineTo(350, 150);
    content.LineTo(250, 150);
    content.SetRGBColorStroke(255, 0, 0);
    content.Stroke();
    // Set the clipping box
    content.NewPath();
    content.MoveTo(200, 200);
    content.LineTo(200, 300);
    content.LineTo(300, 300);
    content.LineTo(300, 200);
    content.LineTo(200, 200);
    content.Clip();
    // Save state, then fill the blue box (will be clipped)
    content.SaveState();
    content.NewPath();
    content.MoveTo(250, 250);
    content.LineTo(250, 350);
    content.LineTo(350, 350);
    content.LineTo(350, 250);
    content.LineTo(250, 250);
    content.SetRGBColorFill(0, 0, 255);
    content.Fill();
    // Restore state
    content.RestoreState();
    // Save state again, then fill the red box (will not be clipped... why not?)
    content.SaveState();
    content.NewPath();
    content.MoveTo(250, 150);
    content.LineTo(250, 250);
    content.LineTo(350, 250);
    content.LineTo(350, 150);
    content.LineTo(250, 150);
    content.SetRGBColorFill(255, 0, 0);
    content.Fill();
    content.RestoreState();
    doc.Close();
}

在上面的代码中,我描边了一个红框和一个蓝框,以指示剪切框的绘制位置(为了验证)。那些描边的盒子不应该夹起来。填满的蓝色盒子被正确地夹住。红色填充框没有被剪切,但在我的理解中应该是。

我将ClosePath()添加到各种路径(剪切,填充,描边等),而不改变结果。

我需要在Clip()之后做SaveState()/RestoreState(),因为设置了各种gstate值(不透明度,混合模式等)

我使用iTextSharp 5.5.3和LGPL版本4.1.6进行了测试。

iTextSharp:恢复状态后丢失的剪辑路径

问题是你认为NewPath()意味着"我想开始画一条新路径,这里是我的坐标"。相反,它更多地意味着"我已经画好了我的路径,任何进一步的操作都应该开始一个新的路径。"或从规格:

结束路径对象,但不填充或描边。这个操作符应该是一个路径绘制无操作,主要用于的副作用改变当前的剪辑路径(见8.5.4,"剪辑路径")运营商")。

你几乎可以去掉所有的NewPath()调用,除了最需要的那个,它就在Clip()的后面

content.Clip();
content.NewPath();

这不是iText的bug,也不是任何版本的iTextSharp的bug。您几乎是在手动编写PDF语法操作符一个接一个的操作符。

让我们看一下ISO-32000-1,第8.5.4节,题为"剪切路径操作符",更具体地说,在注2中。我引用:

因为剪辑路径是图形状态的一部分,所以它的效果可以属性来将其定位到特定的图形对象修改裁剪路径和绘制这些对象在一对qQ操作符之间(参见8.4.2,"图形状态")栈")。执行Q运算符将导致剪辑路径为返回到q操作符保存的值剪辑路径被修改。

如果你想知道上面定义中的qQ操作符是什么:q保存状态操作符,Q恢复状态操作符。

我必须承认有些奇怪的事情正在发生。人们会期望在第一个RestoreState()之后剪辑路径仍然是活跃的。如果这个语法没有正确呈现,那么呈现语法的查看器可能做错了什么,丢弃了剪辑路径…