使用 iText 替换 BIRT 生成的报告中的单个图像
Replacing a single image from a BIRT generated report with iText
我正在使用 BIRT 生成带有 PDF 输出的简单报告。本文档有一些空白(用特定颜色的占位符图像填充,在 BIRT 中作为嵌入图像插入),我想用用户提供的图像替换。
BIRT 在幕后使用 iText,所以我决定也使用 iText,在它的版本 5 中。文档如下所示:
现在,我写这段代码只是为了填补第一个空白:
private void replaceStream(PRStream orig, PdfStream stream) throws IOException {
orig.clear();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
stream.writeContent(baos);
orig.setData(baos.toByteArray(), false);
for (PdfName name : stream.getKeys()) {
orig.put(name, stream.get(name));
}
}
private void placeSignature(File source, File target, File signature)
throws IOException, DocumentException {
PdfReader reader = new PdfReader(source.getPath());
PdfObject obj;
for (int i = 1; i <= reader.getXrefSize(); i++) {
obj = reader.getPdfObject(i);
if (obj != null && obj.isStream()) {
PRStream stream = (PRStream) obj;
byte[] b;
try {
b = PdfReader.getStreamBytes(stream);
} catch (UnsupportedPdfException e) {
b = PdfReader.getStreamBytesRaw(stream);
}
BufferedImage img = ImageIO.read(new ByteArrayInputStream(b));
if (img != null) {
boolean signaturePlaceholder = true;
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
// Check if image is a placeholder, matches a colour
if (img.getRGB(x, y) != -65) {
signaturePlaceholder = false;
}
}
}
if (signaturePlaceholder) {
Image img2 = Image.getInstance(signature.getPath());
PdfImage newImg = new PdfImage(img2, "", null);
replaceStream(stream, newImg);
System.out.println("Replaced!");
break;
}
}
}
}
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(target));
stamper.close();
reader.close();
}
@Test
public void testReplace() throws IOException, DocumentException {
placeSignature(new File("src/test/resources/signature_test2.pdf"),
new File("target/signature_test2.pdf"),
new File("src/test/resources/signature.jpg"));
}
然而,当运行测试时,我得到的结果是:
PDF 流似乎在所有图像标签之间共享。但是,我只想更改第一个内容。如果我使用另一张图片来填补任何空白(例如,尺寸不同),它不会被替换。
问题是,在解析 PDF 时是否有解决此问题的方法,或者我是否需要在 BIRT 中创建报告时为每个占位符使用不同的图像。
这是示例 PDF 文件的the link。
您的 PDF 中的页面仅包含单个图像 XObject 资源,该资源用于单个表单 XObject 资源,该资源在页面内容流中使用了三次。
因此,在您替换唯一的图像资源后,页面上的所有(间接)使用都显示替换图像。
如果您想使用 iText 更改此设置,则必须编辑内容流并将 XObject 使用的表单指令替换为使用新图像。但是您首先必须确定您要替换那些 XObject 用法中的哪些。
非常重要,特别是如果 Birt 模板有一定的灵活性。
我建议您为报告模板中的不同位置使用不同的图像(使用不同的标记颜色)。当然,这样的占位符图像越多,这就变得越来越困难,特别是如果数字是动态的并且可以变得任意大,例如具有未知但可能有大量条目的数据集中的每个数据集条目一个。
我正在使用 BIRT 生成带有 PDF 输出的简单报告。本文档有一些空白(用特定颜色的占位符图像填充,在 BIRT 中作为嵌入图像插入),我想用用户提供的图像替换。
BIRT 在幕后使用 iText,所以我决定也使用 iText,在它的版本 5 中。文档如下所示:
现在,我写这段代码只是为了填补第一个空白:
private void replaceStream(PRStream orig, PdfStream stream) throws IOException {
orig.clear();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
stream.writeContent(baos);
orig.setData(baos.toByteArray(), false);
for (PdfName name : stream.getKeys()) {
orig.put(name, stream.get(name));
}
}
private void placeSignature(File source, File target, File signature)
throws IOException, DocumentException {
PdfReader reader = new PdfReader(source.getPath());
PdfObject obj;
for (int i = 1; i <= reader.getXrefSize(); i++) {
obj = reader.getPdfObject(i);
if (obj != null && obj.isStream()) {
PRStream stream = (PRStream) obj;
byte[] b;
try {
b = PdfReader.getStreamBytes(stream);
} catch (UnsupportedPdfException e) {
b = PdfReader.getStreamBytesRaw(stream);
}
BufferedImage img = ImageIO.read(new ByteArrayInputStream(b));
if (img != null) {
boolean signaturePlaceholder = true;
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
// Check if image is a placeholder, matches a colour
if (img.getRGB(x, y) != -65) {
signaturePlaceholder = false;
}
}
}
if (signaturePlaceholder) {
Image img2 = Image.getInstance(signature.getPath());
PdfImage newImg = new PdfImage(img2, "", null);
replaceStream(stream, newImg);
System.out.println("Replaced!");
break;
}
}
}
}
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(target));
stamper.close();
reader.close();
}
@Test
public void testReplace() throws IOException, DocumentException {
placeSignature(new File("src/test/resources/signature_test2.pdf"),
new File("target/signature_test2.pdf"),
new File("src/test/resources/signature.jpg"));
}
然而,当运行测试时,我得到的结果是:
PDF 流似乎在所有图像标签之间共享。但是,我只想更改第一个内容。如果我使用另一张图片来填补任何空白(例如,尺寸不同),它不会被替换。
问题是,在解析 PDF 时是否有解决此问题的方法,或者我是否需要在 BIRT 中创建报告时为每个占位符使用不同的图像。
这是示例 PDF 文件的the link。
您的 PDF 中的页面仅包含单个图像 XObject 资源,该资源用于单个表单 XObject 资源,该资源在页面内容流中使用了三次。
因此,在您替换唯一的图像资源后,页面上的所有(间接)使用都显示替换图像。
如果您想使用 iText 更改此设置,则必须编辑内容流并将 XObject 使用的表单指令替换为使用新图像。但是您首先必须确定您要替换那些 XObject 用法中的哪些。
非常重要,特别是如果 Birt 模板有一定的灵活性。
我建议您为报告模板中的不同位置使用不同的图像(使用不同的标记颜色)。当然,这样的占位符图像越多,这就变得越来越困难,特别是如果数字是动态的并且可以变得任意大,例如具有未知但可能有大量条目的数据集中的每个数据集条目一个。