有人知道Java的(最好是开源的)PDF布局引擎,能够呈现具有水平分页符的表吗? “水平分页”至少是在BIRT中如何命名该功能,但澄清一下:如果一个表有太多的列以适应可用的页面宽度,我希望表格在多个页面上水平分割,例如:对于10列表,列1-4将在第一页输出,列5-10在第二页上输出。如果表格中有太多的行以垂直放在一页上,这当然也应该在以下页面上重复。
到目前为止,搜索产品一直很困难。我认为这样的功能在其他产品中可能会有不同的名称,因此很难使用谷歌阿姨找到合适的解决方案。
到目前为止,我已经尝试过了:
BIRT声称支持这一点,但实际的实施是如此错误,以至于无法使用。我虽然对于这样的功能是不言而喻的,但是行高在所有页面上保持一致,使得在将页面彼此相邻放置时可以对齐行。但是,BIRT会为每个页面分别计算所需的行高。
Jasper没有支持。
我也考虑过Apache FOP,但我在XSL-FO规范中找不到任何合适的语法。
iText对于此任务通常有点过于“低级别”(难以布局目标PDF文档的其他部分),但似乎没有提供支持。
由于似乎有一些其他的报告或布局引擎,可能适合或不适合我发现有点难以猜测究竟要找什么,我希望有人可能已经有类似的要求并且可以提供正确方向的建议。将产品轻松集成到Java服务器应用程序中相对重要,本机Java库是理想的。
现在,为了使行在所有页面上保持对齐,行高必须按如下方式计算:
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)
答案 0 :(得分:3)
可以使用iText
以您希望的方式显示表格。您需要使用自定义表定位和自定义行和列写入。
我能够调整this iText example水平和垂直地在多个页面上书写。我们的想法是记住在页面上垂直进入的起始行和结束行。我把整个代码放在一起,这样你就可以轻松运行它了。
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倍更高,但代码不会分裂,但也可以适应这一点。
答案 1 :(得分:1)
这里的想法与Dev Blanked相同但使用wkhtmltopdf(https://code.google.com/p/wkhtmltopdf/)和一些javascript,你可以实现你所需要的。当针对此fiddle运行wkhtmltopdf时,您将获得如下所示的结果(pdf页面的屏幕截图)。您可以将“break-after”类放在标题行的任何位置。我们在Java EE Web应用程序中使用wkhtmltopdf服务器端来生成动态报告,性能实际上非常好。
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>
脚本
$(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);
});
});
答案 2 :(得分:0)
您是否尝试过http://code.google.com/p/flying-saucer/。它应该将HTML转换为PDF。
答案 3 :(得分:0)
答案 4 :(得分:0)
Jasper没有支持。
根据Jasper文档,它确实有支持,通过:
如果您真的陷入困境,作为最后的手段,您可以使用Excel / OpenOffice Calc:手动将数据复制到单元格中,根据需要手动格式化,另存为xls格式。然后使用java中的apache POI动态填充/替换所需的数据&amp;打印到文件/ PDF。至少它对色谱柱和色谱柱进行了非常精细的控制。行格式/中断/边距等。