如何使用 pdfHtml 和 iText 7 划掉 table 单元格

How to cross out a table cell using pdfHtml and iText 7

我正在尝试显示一个划掉的 table 单元格。
我已经尝试了几十种不同的方法。
我最好的解决方案是使用四个线性渐变,每个角一个(因为不支持透明背景)。

这里的问题是,我必须指定 table 单元格的高度,因此当同一行中任何其他单元格中的文本行数多于预期时,十字不再来自一个角落到一个角落。

我也尝试过使用 background-image 并将 background-size 设置为 100% 100%。 但是,pdfHtml 不支持 background-size.
我尝试了多种在 Chrome 中有效的解决方法,但 none 在 pdfHtml 中有效。

有人知道(可能的)解决方案吗?

谢谢,
--Zuzu_Typ--

你试过用 svg 做吗?应该在没有 background-size 属性 的情况下工作。

.diag {
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='none' viewBox='0 0 100 100'><path d='M1 0 L0 1 L99 100 L100 99' fill='black' /><path d='M0 99 L99 0 L100 1 L1 100' fill='black' /></svg>");
  background-repeat: no-repeat;
  background-position: center center;
  border: 1px solid red;
}
<div style="background-color: blue;">
  <div class="diag" style="width: 300px; height: 100px;"></div>
</div>

pdfHTML最终利用了iText的非常灵活的布局机制。您可以通过自定义单元格的呈现逻辑并将该实现插入 pdfHTML.

来实现您的最终目标

首先,自定义单元格渲染器:

private static class CustomCellRenderer extends CellRenderer {
    public CustomCellRenderer(Cell modelElement) {
        super(modelElement);
    }

    @Override
    public IRenderer getNextRenderer() {
        return new CustomCellRenderer((Cell) modelElement);
    }

    @Override
    public void drawBackground(DrawContext drawContext) {
        super.drawBackground(drawContext);
        PdfCanvas canvas = drawContext.getCanvas();
        Rectangle area = getOccupiedAreaBBox();
        canvas.moveTo(area.getLeft(), area.getTop()).lineTo(area.getRight(), area.getBottom());
        canvas.moveTo(area.getLeft(), area.getBottom()).lineTo(area.getRight(), area.getTop());
        canvas.stroke();
    }
}

本质上,我们重用了默认实现,并通过从左下角到右上角和从左上角到右下角画一条线来扩展它。

现在,我们需要为在 pdf 中创建的布局对象使用自定义渲染器HTML。它们是在标签工作者中创建的,因此为 table 单元格定制标签工作者:

private static class CustomTdTagWorker extends TdTagWorker {
    public CustomTdTagWorker(IElementNode element,
            ProcessorContext context) {
        super(element, context);
    }

    @Override
    public IPropertyContainer getElementResult() {
        IPropertyContainer cell = super.getElementResult();
        if (cell instanceof Cell) {
            ((Cell) cell).setNextRenderer(new CustomCellRenderer((Cell) cell));
        }
        return cell;
    }
}

缺少的部分是我们需要配置 pdfHTML 以将我们的自定义标签工作者用于 <td> 单元格以及创建自定义标签工作者工厂的方法:

private static class CustomTagWorkerFactory extends DefaultTagWorkerFactory {
    @Override
    public ITagWorker getCustomTagWorker(IElementNode tag, ProcessorContext context) {
        if (TagConstants.TD.equals(tag.name())) {
            return new CustomTdTagWorker(tag, context);
        }
        return super.getCustomTagWorker(tag, context);
    }
}

唯一缺少的部分是将自定义标签工人工厂传递给 pdfHTML 本身,这是通过转换器属性完成的:

HtmlConverter.convertToPdf(inFile, outFile, new ConverterProperties().setTagWorkerFactory(new CustomTagWorkerFactory()));

用上面的代码进行以下HTML:

<html>
<head>
    <style>
        td, th {
            border: solid 1px;
        }
    table {
      border-collapse: collapse;
    }
    </style>
</head>
<body>
<table>
  <tbody>
    <tr>
    <td>Cell 1</td>
    <td>Cell 2</td>
   </tr>
   <tr>
    <td>Another cell 1</td>
    <td>Another cell 2</td>
   </tr>
  </tbody>
  <tfoot>
    <td>
      Footer 1
    </td>
    <td>
      Footer 2
    </td>
  </tfoot>
</table>
</body>
</html>

我在转换为 PDF 后得到了以下视觉效果: