版本5.5.4+中的ItextSharp字体颜色问题

时间:2015-03-16 21:29:46

标签: c# itext

我有一些代码可以创建一个红色"戳"使用红色字体颜色:

    string StampDate = DateTime.Now.ToString("MM/dd/yyyy");
    string FontPath = Server.MapPath("/assets/Fonts");
    string OrigFile = Server.MapPath("/test.pdf");
    const int OpacityPercent = 80;
    const float PDFPaidFontSize = 28;
    const float PDFCopyX = 170;
    const float PDFPaidX = 385;
    const float PDFY = 20;
    const float PDFDateXOffset = 7;
    const float PDFDateYOffset = 12;
    const float PDFDateFontSize = 10;
    const string PaidStampTxt = "PAID";
    const string CopyStampTxt = "COPY";
    const string ArialFilename = "arialbd.ttf";
    PdfStamper stamper = null;
    PdfReader reader = null;
    PdfReader.unethicalreading = true;
    MemoryStream streamPDF;
    try
    {
        reader = new PdfReader(OrigFile);
        streamPDF = new MemoryStream();
        stamper = new PdfStamper(reader, streamPDF);
        for (int i = 1; i <= reader.NumberOfPages; i++)
        {
            PdfGState gstate = new PdfGState();
            gstate.FillOpacity = gstate.StrokeOpacity = OpacityPercent / 100F;
            PdfContentByte overContent = stamper.GetOverContent(i);
            overContent.SaveState();
            overContent.SetGState(gstate);
            overContent.SetColorFill(BaseColor.RED);
            overContent.BeginText();
            BaseFont font = BaseFont.CreateFont(BaseFont.TIMES_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
            overContent.SetFontAndSize(font, PDFPaidFontSize);
            overContent.ShowTextAligned(PdfContentByte.ALIGN_LEFT, CopyStampTxt, PDFCopyX, PDFY, 0);
            overContent.ShowTextAligned(PdfContentByte.ALIGN_LEFT, PaidStampTxt, PDFPaidX, PDFY, 0);
            overContent.SetColorFill(BaseColor.BLACK);
            font = BaseFont.CreateFont(Path.Combine(FontPath, ArialFilename), BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
            overContent.SetFontAndSize(font, PDFDateFontSize);
            overContent.ShowTextAligned(PdfContentByte.ALIGN_LEFT, StampDate, PDFPaidX + PDFDateXOffset, PDFY - PDFDateYOffset, 0);
            overContent.EndText();
            overContent.RestoreState();
        }
    }
    finally
    {
        if (stamper != null)
        {
            stamper.Close();
        }
        if (reader != null)
        {
            reader.Close();
        }
    }
    byte[] pdf = streamPDF.ToArray();
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.Buffer = false;
    Response.Clear();
    Response.ClearContent();
    Response.ClearHeaders();
    Response.Charset = string.Empty;
    Response.ContentType = "application/pdf";
    Response.AddHeader("content-length", pdf.Length.ToString());
    Response.AddHeader("Content-Disposition", "inline;filename=test.pdf;");
    Response.BinaryWrite(pdf);
    Response.Close();

生成的pdf文本为灰色而不是红色。 当我恢复到版本5.5.3时,它再次显示为红色。我尝试过5.5.4和5.5.5,他们似乎都有同样的问题。

我的问题是:这是一个错误还是我需要将我的代码更改为更新的代码?

编辑:这似乎只是某些pdf文件的问题。更改字体和pdf文件版本似乎没有效果。

比较有效的pdf和不起作用的pdf(我都不能公开分享)我注意到不起作用的pdf是带标记的pdf,启用了快速Web视图,并由adobe pdf库生成。工作的pdf不是标记的pdf,没有启用快速Web视图,并且是由itextsharp创建的。

由于我无法控制源pdf文件的内容,因此我恢复到了似乎一直有效的早期版本的itextsharp。

1 个答案:

答案 0 :(得分:4)

重现问题的第一次尝试

我刚刚执行了这些值的代码:

        int OpacityPercent = 70;
        int PDFPaidFontSize = 20;
        string CopyStampTxt = "COPY";
        string PaidStampTxt = "PAID";
        int PDFCopyX = 100;
        int PDFPaidX = 250;
        int PDFY = 500;
        string FontPath = @"C:\Windows\Fonts";
        string ArialFilename = "ariali.ttf";
        int PDFDateFontSize = 30;
        string StampDate = "TODAY";
        int PDFDateXOffset = 0;
        int PDFDateYOffset = 35;

使用简单的源PDF,结果PDF如下所示:

enter image description here

与你的观察相反

  

生成的pdf文字为灰色而不是红色。

生成的文本颜色偏红(白色部分透明的红色)。

我使用iTextSharp 5.5.5测试。

要获得灰色而不是红色,因此,您的变量值或源PDF必须有一些特殊内容,这不是一般的iTextSharp问题。

使用OP提供的文件重现问题

在第一次尝试重现该问题后,OP提供了一个示例文件Test.pdf,实际上,对于此文件,相同代码的结果是:

enter image description here

因此,确实存在一个问题。

分析

两种情况下添加的内容流操作的比较显示:

  • 首次尝试使用我的示例PDF:

    /Xi0 gs
    1 0 0 rg
    BT
    /Xi1 20 Tf
    1 0 0 1 100 500 Tm
    (COPY) Tj
    
  • 使用OP的示例文件进行第二次尝试:

    /Xi0 gs
    1 0 0 rg
    BT
    0 g
    /Xi1 20 Tf
    1 0 0 1 100 500 Tm
    (COPY) Tj
    

因此,尽管使用了相同的代码,但在后一种情况下还有一个0 g操作,并且操作选择黑色作为填充颜色。

这令人非常惊讶。因此,我查看了iText代码和代码历史记录以获得解释(我选择了iText / Java代码,因为这是原始开发发生的地方,可以更彻底地检查更改)。

事实上,PdfContentByte.beginText以:

结尾
if (isTagged()) {
    try {
        restoreColor();
    } catch (IOException ioe) {

    }
}

背景

因此,在标记PDF的情况下,该方法“重置颜色”。为什么?

查看代码历史记录会给出一些提示

  • 修订版5499 标记PDF支持:将图形和文本保存在一个画布中。尚未准备好......

  • 修订版5515 现在iText可以将文本和图形写入1个画布。为此,您应将PdfDocument.putTextAndGraphicsTogether设置为true。

    此处上面的块首先出现略有差异

    if (autoControlTextBlocks) {
        try {
            restoreColor();
        } catch (IOException ioe) {
    
        }
    }
    

    即。此处仅在autoControlTextBlockstrue时才会恢复颜色。

  • ...

  • 修订版5533 writer.isTagged属性现在决定是将所有内容写入一个画布还是单独写入。

    此处标志autoControlTextBlocks已被关联作者的isTagged调用所取代。

我的解释:

  • 为了正确支持标记的PDF,将图形和文本保存在一个画布中是必要的或者至少是有利的(以前它们是在不同的画布中创建的,最终被连接起来,所以相关的图形

  • 。文本在内容上彼此相距遥远
  • 为了在高级代码中保持图形和文本的最小开销,在PdfContentByte中添加了一个新的 autoControlTextBlocks 模式,可以根据需要自动启动和停止文本对象。为文本保存和恢复单独的颜色集。

  • 这种模式似乎已被选为支持iText中标记内容的手段,而它似乎并未被认为对其他上下文有用。因此,此模式现在自动用于标记文件。

在我看来,这种选择不是最佳选择。 PdfContentByte是公开发布的iText API的一部分,并且公开宣传(作为“内容过多”),用于对生成的或预先存在的PDF进行低级调整。引入这样的副作用违反了API合同,至少这会让人们无法升级。

变通

只需使用

切换颜色设置和文本对象启动操作的顺序
...
overContent.BeginText();
overContent.SetColorFill(BaseColor.RED);
...

结果

enter image description here

分辨率

如果我正确解释了最终签到,则应在iText版本5.5.6中修复此问题。

提交 301a45b57dcef37ae0ec3625fbdd6caaf4004a3a

删除了PdfContentByte类(DEV-1371)中已标记的pdf文档的保存和恢复颜色的弃用逻辑。