Подтвердить что ты не робот

Таблицы в формате PDF с горизонтальными разрывами страниц

Знает ли кто-нибудь (желательно с открытым исходным кодом) механизм компоновки PDF для Java, способный отображать таблицы с горизонтальными разрывами страниц? "Горизонтальное разбиение страницы" - это, по крайней мере, то, как функция названа в BIRT, но для уточнения: если в таблице слишком много столбцов, чтобы соответствовать ширине доступной страницы, я хочу, чтобы таблица была разделена по горизонтали на нескольких страницах, например. для таблицы из 10 столбцов столбцы 1-4 должны выводиться на первой странице и столбцы 5-10 на второй странице. Разумеется, это также следует повторять на следующих страницах, если в таблице слишком много строк, чтобы поместить вертикально на одну страницу.

До сих пор было довольно сложно искать продукты. Я считаю, что такую ​​функцию можно назвать по-разному в других продуктах, что затрудняет использование тети Google для поиска подходящего решения.

До сих пор я пробовал:

  • BIRT утверждает, что поддерживает это, но фактическая реализация настолько ошибочна, что ее нельзя использовать. Я уверен, что для такой функциональности очевидно, что высота строки поддерживается на всех страницах, что позволяет выравнивать строки при размещении страниц рядом друг с другом. Однако BIRT рассчитывает требуемую высоту строки отдельно для каждой страницы.

  • У Джаспера нет поддержки.

  • Я также рассматривал Apache FOP, но я не нашел подходящего синтаксиса для этого в спецификации XSL-FO.

  • iText обычно немного слишком "низкоуровневый" для этой задачи (что затрудняет компоновку других частей предполагаемых документов PDF), но, похоже, не предлагает поддержки.

Так как, похоже, есть несколько десятков других механизмов создания отчетов или компоновки, которые могут или не подходят, и мне трудно понять, что именно нужно искать, я надеялся, что у кого-то, возможно, уже есть аналогичные требования, и может по крайней мере, предложение в правильном направлении. Относительно важно, чтобы продукт можно было легко интегрировать в серверное приложение Java, идеальная библиотека Java.

Expected Layout

Теперь, чтобы строки были выровнены по всем страницам, высота строк должна быть рассчитана следующим образом:

Row1.height = max(A1.height, B1.height, C1.height, D1.height)
Row2.height = max(A2.height, B2.height, C2.height, D2.height)

В то время как BIRT, похоже, делает что-то вроде:

Page1.Row1.height = max(A1.height, B1.height)
Page2.Row1.height = max(C1.height, D1.height)
Page1.Row2.height = max(A2.height, B2.height)
Page2.Row2.height = max(C2.height, D2.height)

Second Layout

4b9b3361

Ответ 1

Можно отобразить таблицу так, как вы хотите, с помощью iText. Вам необходимо использовать собственное позиционирование таблицы и пользовательскую запись строк и столбцов.

Я смог адаптировать этот пример iText для записи на нескольких страницах по горизонтали и по вертикали. Идея состоит в том, чтобы запомнить начальную и конечную строки, которые попадают вертикально на страницу. Я поместил весь код, чтобы вы могли легко запустить его.

public class Main {
    public static final String RESULT = "results/part1/chapter04/zhang.pdf";

    public static final float PAGE_HEIGHT = PageSize.A4.getHeight() - 100f;

    public void createPdf(String filename)
            throws IOException, DocumentException {

        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer
                = PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();

        //setup of the table: first row is a really tall one
        PdfPTable table = new PdfPTable(new float[] {1, 5, 5, 1});

        StringBuilder sb = new StringBuilder();

        for(int i = 0; i < 50; i++) {
            sb.append("tall text").append(i + 1).append("\n");
        }

        for(int i = 0; i < 4; i++) {
            table.addCell(sb.toString());
        }

        for (int i = 0; i < 50; i++) {
            sb = new StringBuilder("some text");
            table.addCell(sb.append(i + 1).append(" col1").toString());

            sb = new StringBuilder("some text");
            table.addCell(sb.append(i + 1).append(" col2").toString());

            sb = new StringBuilder("some text");
            table.addCell(sb.append(i + 1).append(" col3").toString());

            sb = new StringBuilder("some text");
            table.addCell(sb.append(i + 1).append(" col4").toString());
        }

        // set the total width of the table
        table.setTotalWidth(600);
        PdfContentByte canvas = writer.getDirectContent();

        ArrayList<PdfPRow> rows = table.getRows();

        //check every row height and split it if is taller than the page height
        //can be enhanced to split if the row is 2,3, ... n times higher than the page  
        for (int i = 0; i < rows.size(); i++) {
            PdfPRow currentRow = rows.get(i);

            float rowHeight = currentRow.getMaxHeights();

            if(rowHeight > PAGE_HEIGHT) {
                PdfPRow newRow = currentRow.splitRow(table,i, PAGE_HEIGHT);
                if(newRow != null) {
                    rows.add(++i, newRow);
                }
            }
        }

        List<Integer[]> chunks = new ArrayList<Integer[]>();

        int startRow = 0;
        int endRow = 0;
        float chunkHeight = 0;

        //determine how many rows gets in one page vertically
        //and remember the first and last row that gets in one page
        for (int i = 0; i < rows.size(); i++) {
            PdfPRow currentRow = rows.get(i);

            chunkHeight += currentRow.getMaxHeights();

            endRow = i;   

            //verify against some desired height
            if (chunkHeight > PAGE_HEIGHT) {
                //remember start and end row
                chunks.add(new Integer[]{startRow, endRow});
                startRow = endRow;
                chunkHeight = 0;
                i--;
            }
        }

        //last pair
        chunks.add(new Integer[]{startRow, endRow + 1});

        //render each pair of startRow - endRow on 2 pages horizontally, get to the next page for the next pair
        for(Integer[] chunk : chunks) {
            table.writeSelectedRows(0, 2, chunk[0], chunk[1], 236, 806, canvas);
            document.newPage();
            table.writeSelectedRows(2, -1, chunk[0], chunk[1], 36, 806, canvas);

            document.newPage();
        }


        document.close();
    }

    public static void main(String[] args) throws IOException, DocumentException {
        new Main().createPdf(RESULT);
    }
}

Я понимаю, что, возможно, iText слишком низкий уровень только для отчетов, но он может использоваться рядом со стандартными средствами отчетности для особых потребностей, таких как.

Обновление: Теперь строки, которые выше высоты страницы, сначала разбиваются. Код не выполняет разделение, если строка 2, 3,..., n раз выше, но также может быть адаптирована для этого.

Ответ 2

Та же идея, что и Dev Blanked, но используя wkhtmltopdf (https://code.google.com/p/wkhtmltopdf/) и некоторый javascript, вы можете достичь того, что вам нужно. При запуске wkhtmltopdf против этого fiddle вы получите результат, показанный ниже (снимок экрана pdf-страниц). Вы можете поместить класс "break-after" в любом месте строки заголовка. Мы используем серверную часть wkhtmltopdf в веб-приложении Java EE для создания динамических отчетов, и производительность на самом деле очень хорошая.

HTML

<body>
        <table id="table">
            <thead>
                <tr><th >Header 1</th><th class="break-after">Header 2</th><th>Header 3</th><th>Header 4</th></tr>
            </thead>
            <tbody>
                <tr valign="top">
                    <td>A1<br/>text<br/>text</td>
                    <td>B1<br/>text</td>
                    <td>C1</td>
                    <td>D1</td>
                </tr>
                <tr valign="top">
                    <td>A2</td>
                    <td>B2<br/>text<br/>text<br/>text</td>
                    <td>C2</td>
                    <td>D2<br/>text</td>
                </tr>
            </tbody>
        </table>
    </body>

Script

$(document).ready(function() {
    var thisTable = $('#table'),
        otherTable= thisTable.clone(false, true),
        breakAfterIndex = $('tr th', thisTable).index($('tr th.break-after', thisTable)),
        wrapper = $('<div/>');

    wrapper.css({'page-break-before': 'always'});
    wrapper.append(otherTable);
    thisTable.after(wrapper);
    $('tr', thisTable).find('th:gt(' + breakAfterIndex + ')').remove(); 
    $('tr', thisTable).find('td:gt(' + breakAfterIndex + ')').remove(); 
    $('tr', otherTable).find('th:lt(' + (breakAfterIndex + 1) + ')').remove(); 
    $('tr', otherTable).find('td:lt(' + (breakAfterIndex + 1) + ')').remove();

    $('tr', table).each(function(index) {
        var $this =$(this),
            $otherTr = $($('tr', otherTable).get(index)),
            maxHeight = Math.max($this.height(), $otherTr.height());
        $this.height(maxHeight);
        $otherTr.height(maxHeight);      
    });
});

Screenshot of the resulting PDF

Ответ 4

Мой совет - использовать трансформатор FOP.

Здесь вы можете увидеть некоторые примеры и способы их использования.

Здесь вы можете найти несколько примеров с fop и таблицами.

Ответ 5

У Джаспера нет поддержки.

Согласно документации Jasper, у нее есть поддержка, через:

  • элемент разрыва столбца (т.е. элемент break с атрибутом type = column). Это можно разместить в любом месте отчета.
  • атрибут isStartNewColumn для групп/заголовков

См. http://books.google.com.au/books?id=LWTbssKt6MUC&pg=PA165&lpg=PA165&dq=jasper+reports+ % 22column + перерыв% 22 & источник = бл & отс = aSKZfqgHR5 & сиг = KlH4_OiLP-cNsBPGJ7yzWPYgH_k & гл = еп & са = Х & е = h_1kUb6YO6uhiAeNk4GYCw & redir_esc = у # v = OnePage & д = столбец %20break & F = ложным

Если вы действительно застряли, в качестве последнего средства вы можете использовать Excel/OpenOffice Calc: вручную скопировать данные в ячейки, вручную отформатировать их по своему усмотрению, сохранить как формат xls. Затем используйте apache POI из java для динамического заполнения/замены требуемых данных и печати в файл /PDF. По крайней мере, он дает очень тонкий контроль форматирования столбцов и строк/разрывов/полей и т.д.