【问题标题】:Create local link in rotated PdfPCell in iTextSharp在 iTextSharp 的旋转 PdfPCell 中创建本地链接
【发布时间】:2016-03-28 07:11:44
【问题描述】:

我正在尝试使用 iTextSharp 在我的 pdf 中添加指向另一个页面的链接。 旋转单元格中的链接不起作用。其他单元格按预期工作:

FileStream fs = new FileStream("TestPDF.pdf", FileMode.Create, FileAccess.Write, FileShare.None);
Document doc = new Document();
PdfWriter writer = PdfWriter.GetInstance(doc, fs);
doc.Open();

PdfPTable linkTable = new PdfPTable(2);
PdfPCell linkCell = new PdfPCell();

linkCell.HorizontalAlignment = Element.ALIGN_CENTER;
linkCell.Rotation = 90;
linkCell.FixedHeight = 70;

Anchor linkAnchor = new Anchor("Click here");
linkAnchor.Reference = "#target";
Paragraph linkPara = new Paragraph();
linkPara.Add(linkAnchor);
linkCell.AddElement(linkPara);
linkTable.AddCell(linkCell);

PdfPCell linkCell2 = new PdfPCell();
Anchor linkAnchor2 = new Anchor("Click here 2");
linkAnchor2.Reference = "#target";
Paragraph linkPara2 = new Paragraph();
linkPara2.Add(linkAnchor2);
linkCell2.AddElement(linkPara2);
linkTable.AddCell(linkCell2);

linkTable.AddCell(new PdfPCell(new Phrase("cell 3")));
linkTable.AddCell(new PdfPCell(new Phrase("cell 4")));
doc.Add(linkTable);

doc.NewPage();

Anchor destAnchor = new Anchor("top");
destAnchor.Name = "target";
PdfPTable destTable = new PdfPTable(1);
PdfPCell destCell = new PdfPCell();
Paragraph destPara = new Paragraph();
destPara.Add(destAnchor);
destCell.AddElement(destPara);
destTable.AddCell(destCell);
destTable.AddCell(new PdfPCell(new Phrase("cell 2")));
destTable.AddCell(new PdfPCell(new Phrase("cell 3")));
destTable.AddCell(new PdfPCell(new Phrase("cell 4")));
doc.Add(destTable);

doc.Close();

我正在使用“iTextSharp 5.5.8”。我试过 Chunk.SetAction PdfAction.GotoLocalPage 和 Chunk.SetLocalGoto。没有什么对我有用

谢谢。

【问题讨论】:

  • 你的问题是什么?
  • @blagae 哦,对不起,它在 pdftable 之外工作,但在里面是普通文本

标签: c# pdf hyperlink itextsharp itext


【解决方案1】:

包含不适合您的代码会很有用,因此人们可以专注于特定问题。

当链接和目标都在一个表中时(即PdfPCell),我已经验证了创建本地链接。此代码按预期工作:

PdfPTable linkTable = new PdfPTable(2);
PdfPCell linkCell = new PdfPCell();
Anchor linkAnchor = new Anchor("Click here to go to top of next page.");
linkAnchor.Reference = "#target";
Paragraph linkPara = new Paragraph();
linkPara.Add(linkAnchor);
linkCell.AddElement(linkPara);
linkTable.AddCell(linkCell);
linkTable.AddCell(new PdfPCell(new Phrase("cell 2")));
linkTable.AddCell(new PdfPCell(new Phrase("cell 3")));
linkTable.AddCell(new PdfPCell(new Phrase("cell 4")));
doc.Add(linkTable);

doc.NewPage();

Anchor destAnchor = new Anchor("top");
destAnchor.Name = "target";
PdfPTable destTable = new PdfPTable(1);
PdfPCell destCell = new PdfPCell();
Paragraph destPara = new Paragraph();
destPara.Add(destAnchor);
destCell.AddElement(destPara);
destTable.AddCell(destCell);
destTable.AddCell(new PdfPCell(new Phrase("cell 2")));
destTable.AddCell(new PdfPCell(new Phrase("cell 3")));
destTable.AddCell(new PdfPCell(new Phrase("cell 4")));
doc.Add(destTable);

【讨论】:

  • 我使用与您完全相同的代码,我刚刚发现因为我将单元格旋转了 90,然后链接消失了。我会更新我的问题。
  • @BuiCaoTu 也许您使用的是过时的 iText 版本。也许你说的是几年前修复的错误......
  • @BrunoLowagie 我更新了 iTextSharp 5.5.8,还是不行,我用我正在使用的完整代码编辑了
  • @rhens 你能检查一下当涉及到轮换时会发生什么?这似乎是您的代码与 OP 的代码之间的重要区别。
  • @Tubc 由于轮换似乎有所不同,您是否检查过链接是否位于页面上的不同区域?
【解决方案2】:

实际上 iText(Sharp) 确实也为旋转单元格中的锚点创建了一个 Link 注释,但它的坐标完全错误:

/Rect[-0.003 0 53.34 12]

这些坐标甚至是部分离页,这可能解释了某些 PDF 查看器的特殊行为。

原因

(我分析了具有相同问题的 iText Java 代码,因为我更熟悉 Java。不过,匹配的 iTextSharp C# 代码非常相似。)

原因是处理PdfChunkPdfDocument 代码假定当前坐标系是使用MediaBox 数据初始化的原始用户空间坐标系。因此,它使用当前坐标而不进行任何转换来生成本地 Link 注释:

float xMarker = text.getXTLM();
float baseXMarker = xMarker;
float yMarker = text.getYTLM();
...
if (chunk.isAttribute(Chunk.LOCALGOTO)) {
    float subtract = lastBaseFactor;
    if (nextChunk != null && nextChunk.isAttribute(Chunk.LOCALGOTO))
        subtract = 0;
    if (nextChunk == null)
        subtract += hangingCorrection;
    localGoto((String)chunk.getAttribute(Chunk.LOCALGOTO), xMarker, yMarker, xMarker + width - subtract, yMarker + fontSize);
}

(PdfDocument.writeLineToContent(PdfLine, PdfContentByte, PdfContentByte, Object[], float))

不幸的是,单元格旋转是通过用户坐标系更改来实现的,例如旋转 90°:

ct.setSimpleColumn(-0.003f, -0.001f, netWidth + 0.003f, calcHeight);
...
pivotY = cell.getTop() + yPos - currentMaxHeight + cell.getEffectivePaddingBottom();
switch (cell.getVerticalAlignment()) {
    case Element.ALIGN_BOTTOM:
        pivotX = cell.getLeft() + xPos + cell.getWidth() - cell.getEffectivePaddingRight();
        break;
    case Element.ALIGN_MIDDLE:
        pivotX = cell.getLeft() + xPos + (cell.getWidth() + cell.getEffectivePaddingLeft() - cell.getEffectivePaddingRight() + calcHeight) / 2;
        break;
    default: //top
        pivotX = cell.getLeft() + xPos + cell.getEffectivePaddingLeft() + calcHeight;
        break;
}
saveAndRotateCanvases(canvases, 0, 1, -1, 0, pivotX, pivotY);

(PdfPRow.writeCells(int, int, float, float, PdfContentByte[], boolean))

因此,上面调用的用于旋转锚块的 PdfDocument 代码将定位在通常完全错误的位置。

顺便说一句,这不仅涉及本地 Link 注释,还涉及为块生成的各种注释。一个特别邪恶的例子是通用标签:如果页面事件监听器对GenericTag 事件作出反应,它可以在调用期间使用坐标进行某些绘图操作,但不能作为相对于MediaBox的坐标>.


对此的修复很可能需要向PdfDocument 发出任何坐标系更改的信号,并更新那里的代码以在将坐标用于不受这些变换影响的目的时考虑此信息。特别是 GenericTag 事件应该被扩展以接收转换后的坐标和原始坐标。

我建议将此修复留给 iText 开发。

【讨论】:

  • 感谢您的分析。我已经为这个错误创建了一个内部开发票。
  • 您好,好久不见,您打算修复这个错误吗?
  • @Tubc 恐怕这个错误仍然存​​在,它甚至存在于 iText 7 中,参见。 this Java test.
猜你喜欢
  • 2013-11-18
  • 2016-09-19
  • 2011-02-10
  • 2010-12-02
  • 1970-01-01
  • 2014-09-21
  • 1970-01-01
  • 2016-01-12
  • 1970-01-01
相关资源
最近更新 更多