英文:
How to cross out a table cell using pdfHtml and iText 7
问题
我正在尝试显示一个带有删除线的表格单元格。
我尝试了数十种不同的方法。
我最好的解决方案是使用四个线性渐变,每个角一个(因为不支持透明背景)。
问题在于,我必须指定表格单元格的高度,因此当同一行中的任何其他单元格中的文本行数多于预期时,删除线不再从角到角。
我还尝试使用background-image
和background-size
设置为100% 100%
。
但是,pdfHtml不支持background-size
。
我尝试了多种在Chrome中有效的解决方法,但在pdfHtml中都无效。
有人知道(可能的)解决方案吗?
谢谢,
--Zuzu_Typ--
英文:
I'm trying to display a crossed-out table cell.
I've tried dozens of different approaches.
My best solution was using four linear-gradients, one for each corner (because there is no support for transparent backgrounds).
The issue here is, that I have to specify the height of the table cell, thus when the text in any other cell in the same row has more lines than expected, the cross is no longer from corner to corner.
I've also tried using a background-image
with background-size
set to 100% 100%
.
However, pdfHtml does not support background-size
.
I've tried multiple workarounds that work in Chrome, but none work in pdfHtml.
Does anybody know a (possible) solution?
Thanks,
--Zuzu_Typ--
答案1
得分: 0
你试过使用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>
英文:
Have you tried doing it with svg? Should work without the background-size property as well.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-css -->
.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;
}
<!-- language: lang-html -->
<div style="background-color: blue;">
<div class="diag" style="width: 300px; height: 100px;"></div>
</div>
<!-- end snippet -->
答案2
得分: 0
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();
}
}
基本上,我们重用了默认实现并扩展了它,以绘制从左下角到右上角的一条线以及从左上角到右下角的一条线。
现在,我们需要在pdfHTML中为创建的布局对象使用自定义渲染器。它们在标签工作者中创建,所以我们需要自定义一个表格单元格的标签工作者:
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后,得到以下视觉结果:
英文:
pdfHTML eventually utilizes iText's layout mechanism which is quite flexible. You can achieve your end goal by customizing the rendering logic for a cell and plug that implementation into pdfHTML.
First off, custom cell renderer:
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();
}
}
Essentially, we have reused the default implementation and extended it with drawing a line from bottom left corner to the right top one and from the top left one to the bottom right corner.
Now, we need to use the custom renderer for layout objects that are created in pdfHTML. They are created in tag workers, so customizing a tag worker for a table cell:
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;
}
}
The missing piece is that we need to configure pdfHTML to use our custom tag worker for <td>
cells and the way to do so it to create a custom tag worker factory:
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);
}
}
The only missing piece is to pass the custom tag worker factory to pdfHTML itself and this is done via converter properties:
HtmlConverter.convertToPdf(inFile, outFile, new ConverterProperties().setTagWorkerFactory(new CustomTagWorkerFactory()));
With the code above for the following HTML:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-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>
<!-- end snippet -->
I got the following visual result after converting to PDF:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论