首页 > 解决方案 > itext7 - 不剪裁内容的最大字体大小

问题描述

以粗体编辑

我有一个表格,其中几个单元格包含Paragraphs 和一些任意长的文本。表格宽度是通过 确定的useAllAvailableWidth,我也在调用setAutoLayout.

我正在使用Renderer框架将Paragraph's 的字体大小设置为尽可能大的值,而不会剪掉任何内容。

特别是我希望获得与iText Maximum Font Size类似的结果,但是这些问题是为 itext5 编写的。我正在使用itext7

我已阅读此示例并且由于先前的答案,我提出了以下(部分)解决方案:

class FontSizeRenderer(val content: Paragraph) : ParagraphRenderer(content) {
    override fun getNextRenderer() = FontSizeRenderer(content)

    override fun layout(layoutContext: LayoutContext?): LayoutResult {
        val currentFontSize = content.getProperty<UnitValue>(Property.FONT_SIZE).value

        return layoutBinarySearch(layoutContext, 1f, currentFontSize, 20)
    }

    private tailrec fun layoutBinarySearch(layoutContext: LayoutContext?, minFontSize: Float, maxFontSize: Float, iterationThreshold: Int): LayoutResult {
        val currentLayout = super.layout(layoutContext)

        if (iterationThreshold <= 0) {
            return currentLayout
        }

        val currentFontSize = content.getProperty<UnitValue>(Property.FONT_SIZE).value

        return if (currentLayout.status == LayoutResult.FULL) {
            val increment = (currentFontSize + maxFontSize) / 2
            content.setFontSize(increment)

            layoutBinarySearch(layoutContext, currentFontSize, maxFontSize, iterationThreshold - 1)
        } else {
            val decrement = (minFontSize + currentFontSize) / 2
            content.setFontSize(decrement)

            layoutBinarySearch(layoutContext, minFontSize, currentFontSize, iterationThreshold - 1)
        }
    }
}

当在一个成熟的表中使用这个渲染器时,它“有点工作”,因为它开始递归但它停止得太早了。

破碎的最终结果

第一页底部单元格中的预期输出字符串是Scramble: R' U' F R F2 D2 R' B2 U2 R F2 R' B2 R' B F U' L2 B' R' B' U' R F2 R' U' F. 可以在此存储库webscrambles/src/main/kotlin/org/worldcubeassociation/tnoodle/server/webscrambles/pdf文件FmcSolutionSheet.ktutil/FooRenderer.kt.

如何调整我Renderer的以防止 Cell 溢出?

标签: javapdfitext7

解决方案


拥有一个布局元素,您可以从中创建一个渲染器子树,并尝试将其布局在给定区域中。然后根据元素是否完全适合该区域或没有足够的空间,您可以增加或减少字体大小并重试。

为了测试不同的字体大小,二分搜索是我们最好的朋友,并且可以大大加快速度。

首先,一个帮助函数递归地设置元素的字体大小:

private void setFontSizeRecursively(IElement element, float size) {
    element.setProperty(Property.FONT_SIZE, UnitValue.createPointValue(size));
    if (element instanceof com.itextpdf.layout.element.AbstractElement) {
        for (Object child : ((AbstractElement) element).getChildren()) {
            setFontSizeRecursively((IElement) child, size);
        }
    }
}

现在是代码的重要部分。在二分搜索正文中,我们缩放元素的所有字体大小并模拟布局以查看我们的根元素(表格)是否适合给定区域。然后我们移动左或右搜索边界并再次尝试直到我们收敛。您可以根据自己的喜好调整迭代次数(在代码中设置为 20),以权衡准确性/速度。如果您可以根据预期输入做出这样的判断,您还可以调整二进制搜索的左右边界。最后,我们设置我们收敛的字体大小比例并进行最终布局。

PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName));
Document document = new Document(pdfDocument);

Table table = new Table(UnitValue.createPercentArray(new float[] {20, 40, 40}));
for (int i = 0; i < 9; i++) {
    table.addCell(new Cell().add(new Paragraph("Hello random text")));
}

float lFontSize = 1f;
float rFontSize = 100f;

float desiredWidth = 300;
float desiredHeight = 400;

table.setWidth(UnitValue.createPointValue(desiredWidth));

for (int i = 0; i < 20; i++) {
    float midFontSize = (lFontSize + rFontSize) / 2;
    setFontSizeRecursively(table, midFontSize);

    IRenderer tableRenderer = table.createRendererSubTree().setParent(document.getRenderer());
    LayoutResult result = tableRenderer.layout(new LayoutContext(new LayoutArea(1,
            new Rectangle(0, 0, desiredWidth, desiredHeight)))); // You can tweak desired size to fit the table in

    if (result.getStatus() == LayoutResult.FULL) {
        lFontSize = midFontSize;
    } else {
        rFontSize = midFontSize;
    }
}

setFontSizeRecursively(table, lFontSize);
document.add(table);

document.close();

推荐阅读