itext7 - максимальный размер шрифта без ограничения содержимого - PullRequest
0 голосов
/ 15 января 2020

РЕДАКТИРОВАТЬ жирным шрифтом

У меня есть таблица, в которой несколько ячеек содержат Paragraph s с произвольно длинным текстом. Ширина таблицы определяется с помощью useAllAvailableWidth, и я также вызываю setAutoLayout.

Я использую инфраструктуру Renderer, чтобы установить размер шрифта Paragraph в максимально возможное значение без обрезания содержимого.

В частности, я sh достигну результатов, аналогичных Максимальный размер шрифта iText , однако эти вопросы были написаны для 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)
        }
    }
}

При использовании этого рендерера в полноценной таблице он «работает» в том смысле, что начинает повторяться, но останавливается слишком рано.

broken end result

Ожидаемая строка вывода в нижней ячейке на первой странице - 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.kt и util/FooRenderer.kt.

Как мне настроить Renderer чтобы предотвратить переполнение ячейки?

1 Ответ

1 голос
/ 16 января 2020

Имея элемент макета, вы можете создать из него поддерево рендера и попытаться выложить его в заданной области. Затем, в зависимости от того, поместился ли элемент полностью в этой области или было недостаточно места, вы можете увеличить или уменьшить размер шрифта и повторить попытку.

Чтобы проверить различные размеры шрифта, бинарный поиск - наш лучший друг и позволяет гигантское ускорение.

Во-первых, вспомогательная функция для рекурсивной установки размера шрифта элемента:

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);
        }
    }
}

Теперь мясистая часть кода. В бинарном теле поиска мы масштабируем все размеры шрифтов элементов и эмулируем макет, чтобы посмотреть, вписывается ли наш элемент (таблица) * 1010 в данную область. Затем мы сдвигаем левую или правую границу поиска и пробуем снова, пока не сойдемся. Вы можете настроить количество итераций (в коде 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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...