【问题标题】:Getting "An error exists on this page. Acrobat may not display the page correctly." using ITextSharp WriteSelectedRows获取“此页面上存在错误。Acrobat 可能无法正确显示该页面。”使用 ITextSharp WriteSelectedRows
【发布时间】:2013-08-20 12:48:43
【问题描述】:

我在使用 ITextSharp 创建一些推送到 MVC 浏览器应用程序的表和图像时遇到问题。我想我已经把它缩小到使用 WriteRowsSelected 添加表的范围内。

这是我的代码:

PDFEngine.cs

  private byte[] BuildDocument(MemoryStream documentStream, IEnumerable<CustomPdfData> documents, bool addVoid, float defaultMagnification)
    {

       using (var stream = new MemoryStream())
        {
        var finishedDocument = new Document(new Rectangle(612f, 792f));

        var writer = PdfWriter.GetInstance(finishedDocument, stream);
        writer.ViewerPreferences = PdfWriter.HideWindowUI;
        writer.ViewerPreferences = PdfWriter.HideMenubar;

        // Open the Document for writing
        finishedDocument.Open();


        var zoomer = PdfAction.GotoLocalPage(1, new PdfDestination(PdfDestination.XYZ, -1, -1, defaultMagnification), writer);

        writer.SetOpenAction(zoomer);



        foreach (var document in documents)
        {


            if (document.IsNewPage)
            {
                finishedDocument.NewPage();
            }

            var results = TableEngine.BuildDocument(document);

            // Build Canvas for Table
            //PdfContentByte canvas = writer.DirectContent;
            //canvas.SetTextMatrix(50, 50);

            // Add each table to the canvas at specified coordinates
            for (int tableCounter = 0; tableCounter < results.ITextTables.Count; tableCounter++)
            {
                PdfContentByte canvas = writer.DirectContent;
                canvas.SetTextMatrix(50, 50);

                var xAxis = results.PdfTables[tableCounter].XPosition;
                var yAxis = results.PdfTables[tableCounter].YPosition;
                results.ITextTables[tableCounter].WriteSelectedRows(0, results.PdfTables[tableCounter].ColumnSize, xAxis, yAxis, writer.DirectContent);
            }




        }

        finishedDocument.Close();
        documentStream.Close();
        return stream.ToArray();
    }

CheckBuilder.cs

  /// <summary>
    /// Used to create the fake checks needed for printing to a client
    /// </summary>
    /// <param name="checks">Checks to push to Builder</param>
    /// <returns></returns>
    public byte[] GetFakeChecks(List<HandsCheck> checks)
    {

        var doc = BuildCheck(checks, true, true);
        return CreatePdf(doc, 0.5f, false);
    }

DisplayChecks.cshtml

 <object id="WebBrowser1"  width="615" height="790"  data= "@Url.Action("GetPdfData")" type="application/pdf" />

HomeController.cs

    public FileContentResult GetPdfData()
    {
        int numberofChecks = int.Parse(Workspace.Get<string>("numberofChecks"));

     var pdfCreator = new CheckBuilder();

            var checks = GetAllChecks();
            var newList = new List<Check>();

            for (int counter = 0; counter < numberofChecks; counter++)
            {
                newList.Add(checks[counter]);
            }

            var rawData = pdfCreator.GetFakeChecks(newList);

            return File(rawData, "application/pdf");


        return null;
    }

奇怪的是,它似乎只在我添加超过 1 表时才会发生。有谁知道每张画布是否有任何限制?有谁知道进一步调试可能导致此问题的任何方法?

【问题讨论】:

  • 除了Stream 对象的传递之外,没有什么能引起我的注意。我还没有找到这样做的充分理由,但我看到了很多不这样做的理由。您能否尝试重构为仅使用内部MemoryStream 并使用MS.ToArray() 返回原始字节数组。这也将使您不必担心记住在方法之外关闭流以及调用错误的流方法,例如GetBuffer。
  • 感谢@Chris 的回复。我更新了上面的代码以包含您推荐的重构。我想我按照您的要求做了,但我仍然收到错误消息。奇怪的是,PDF 总是正确显示。我还包含了 HTML 和控制器代码。此外,似乎如果我什至添加第二个表,它会引发相同的错误。我可能需要为多个 WriteSelectedRows 做些什么吗?
  • 另外,如果我在每个 WriteRowsSelected 上添加一个 Newpage 调用,它没有问题,显然这不是预期的效果,但我认为这可能有助于解决这个奇怪的问题
  • 接下来我会尝试几件事。首先,将实际字节写入服务器磁盘,然后将该文件与发送到客户端的二进制文件进行比较。也许 MVC 正在发送一些额外的字节(例如,如果您没有关闭连接)。如果可行,则删除您的特定于域的逻辑并编写一堆表。画布中的表格数量没有限制。实际上,从 PDF 的角度来看,没有“表格”这样的东西,它只是在某些坐标处绘制的文本,碰巧也在附近。
  • 谢谢克里斯,下面的答案就是这样,但退后一步,一步一步尝试是个好主意。

标签: c# .net plugins itextsharp adobe-reader


【解决方案1】:

您在这里引入了 PDF 语法错误:

PdfContentByte canvas = writer.DirectContent;
canvas.SetTextMatrix(50, 50);

使用DirectContent,您可以获取一个对象,该对象允许您将 PDF 语法直接写入内容流。紧接着,你引入了一个文本状态操作符。这是非法的 PDF 语法:

  1. 文本状态运算符仅在文本对象内部有效;即:在BT (BeginText()) 和ET (EndText) 运算符之间。
  2. 为什么需要设置文本矩阵?该行没有意义,因为您是在 writeSelectedRows() 方法中定义表格的位置。

长话短说:删除 canvas.SetTextMatrix(50, 50);,您的 PDF 中至少会少一个语法错误。

我刚刚检查了 iText 代码库,通常您的代码应该抛出“不平衡文本状态”异常。如果没有,要么“健全性检查”不再起作用,要么您使用的是过时的 iTextSharp 版本。

更新

评论 1:

ISO-32000-1 将文本状态定义为图形状态的子集。在图形状态中,您可以更改所有图形对象的线宽、笔触颜色、填充颜色、“当前变换矩阵”等...您可以在图形状态,但没有文字。

文本状态是为文本保留的:你改变文本矩阵,定义前导,字体,......然后你“显示”文本。在 BT 和 ET 块之外使用文本状态运算符是非法的;例如:仅在图形状态下更改文本矩阵是没有意义的,因为在 BT/ET 序列之外没有文本。嵌套 BT 和 ET 对象也是非法的。

评论 2:

就个人而言,我使用 Adob​​e Acrobat(预检功能)来检查损坏的 PDF 的语法。这是最简单的方法,但这并不意味着它很容易。虽然我非常了解 ISO-32000-1,但即使我也并不总是能理解错误消息。

有时 Acrobat 无法打开 PDF 文件,错误是“未知”,或者 Acrobat 是“无法分析 PDF 语法”。例如,请参阅When stamping document - Danish characters disappear and PDF becomes invalid,这是我几天前回答的一个问题。在这种情况下,我尝试使用 iText RUPS 并从内部检查 PDF。在最坏的情况下,您需要在纯文本编辑器中检查 PDF(例如因为即使 RUPS 也无法打开文件)。

评论 3:

当您使用writeSelectedRows() 时,iText(Sharp) 会自动添加BT 和ET 运算符。如果BT 已经存在,某些版本可能会省略BT;如果缺少BT,某些版本的iTextSharp 可能会在使用setTextMatrix() 时添加BT。

长话短说:iText(Sharp) 有时会尝试修复由于编程错误而导致的问题。这些修复并不能完全证明,因为 iText(Sharp) 不能总是猜测开发人员的意图。结果,修复经常失败。士气:应确保不引入 PDF 语法错误。

【讨论】:

  • dude you rock.. 这似乎已经修复了它......我试图按照他们的 API 指南中的一个示例进行操作,显然我混淆了一些东西。我有两个问题。 1.) 你能解释一下为什么 SetTextMatrix 是非法语法吗?仅仅是因为它不在 BT 和 ET 中,还是有更多的原因?我是 PDF 需求领域的新手。
  • 第二个问题是,是否有任何工具或技巧来识别不那么抽象/模糊的实际语法错误?如果有更多信息,我可能会更快到达某个地方。
  • 还有一件事...为什么您认为添加了第一个表而所有后续表都导致了错误?
猜你喜欢
  • 1970-01-01
  • 2023-02-08
  • 2011-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-31
  • 2015-08-26
  • 2011-03-31
相关资源
最近更新 更多