操作 PDF 对象
Manipulate PDF objects
我正在尝试操作 PDF,它用作模板。我正在尝试用我的数据替换 PDF 模板中的 'placeholders'。例如,有人在 Scribus
中制作了一个 PDF 模板,并添加了一个名称为 "company_logo" 的空图像。我的应用程序看到一个名为 "company_logo" 的图像占位符,并在其中添加了公司徽标。
我可以使用 iTextSharp 库浏览 AcroFields 并在文本字段中设置文本(例如),但 AcroFields 不列出图像占位符。我感觉 AcroFields 不是我想要的。
那么如何从 PDF 中获取所有对象的列表(或树)并读取它们的属性(如位置、大小、内容等)。
P.S。我不一定需要使用 iTextSharp,任何其他 PDF 库也可以。最好免费。
一点伪代码让自己更清楚
var object = Pdf.GetObjectById("company_logo");
object.SetValue(myImage);
object.SetPosition(x, y);
从您的伪代码示例中,我们了解到您想要替换包含图像的对象流。有几个关于如何执行此操作的示例。
例如,在 SpecialID example, we create a PDF where we mark a specific image with a special ID. In the ResizeImage 示例中,我们根据该特殊 ID 跟踪该图像并替换流:
object = reader.getPdfObject(i);
if (object == null || !object.isStream())
continue;
stream = (PRStream)object;
if (value.equals(stream.get(key))) {
PdfImageObject image = new PdfImageObject(stream);
BufferedImage bi = image.getBufferedImage();
if (bi == null) continue;
int width = (int)(bi.getWidth() * FACTOR);
int height = (int)(bi.getHeight() * FACTOR);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
AffineTransform at = AffineTransform.getScaleInstance(FACTOR, FACTOR);
Graphics2D g = img.createGraphics();
g.drawRenderedImage(bi, at);
ByteArrayOutputStream imgBytes = new ByteArrayOutputStream();
ImageIO.write(img, "JPG", imgBytes);
stream.clear();
stream.setData(imgBytes.toByteArray(), false, PRStream.NO_COMPRESSION);
stream.put(PdfName.TYPE, PdfName.XOBJECT);
stream.put(PdfName.SUBTYPE, PdfName.IMAGE);
stream.put(key, value);
stream.put(PdfName.FILTER, PdfName.DCTDECODE);
stream.put(PdfName.WIDTH, new PdfNumber(width));
stream.put(PdfName.HEIGHT, new PdfNumber(height));
stream.put(PdfName.BITSPERCOMPONENT, new PdfNumber(8));
stream.put(PdfName.COLORSPACE, PdfName.DEVICERGB);
}
你会在书中找到另一个例子The Best iText Questions on Whosebug where I answered the following question: PDF Convert to Black And White PNGs
我写了 ReplaceImage
示例来展示如何替换图像:
public static 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));
}
}
如您所见,这并不像下面所说的那样微不足道:
var object = Pdf.GetObjectById("company_logo");
object.SetValue(myImage);
正如我在评论中解释的那样,这没有意义:
object.SetPosition(x, y);
我们正在操作的对象是用作图像 XObject 的流。拥有 Image XObjects 的优点是它们可以被重用。例如:如果您在每个页面上都有相同的徽标,那么您只想存储该图像的字节一次并多次重复使用相同的徽标。这意味着具有图像字节的对象对其位置一无所知。该位置在内容流中确定。这取决于CTM。
您是否看过 scribus 脚本功能?
由于您在 scribus 中创建了一个模板,您还可以编写一个简短的 python 脚本,用您的最终数据替换您的占位符并导出最终的 PDF。
从 scribus 1.5 开始,也可以从 commandline.
调用 python 脚本
我正在尝试操作 PDF,它用作模板。我正在尝试用我的数据替换 PDF 模板中的 'placeholders'。例如,有人在 Scribus
中制作了一个 PDF 模板,并添加了一个名称为 "company_logo" 的空图像。我的应用程序看到一个名为 "company_logo" 的图像占位符,并在其中添加了公司徽标。
我可以使用 iTextSharp 库浏览 AcroFields 并在文本字段中设置文本(例如),但 AcroFields 不列出图像占位符。我感觉 AcroFields 不是我想要的。
那么如何从 PDF 中获取所有对象的列表(或树)并读取它们的属性(如位置、大小、内容等)。
P.S。我不一定需要使用 iTextSharp,任何其他 PDF 库也可以。最好免费。
一点伪代码让自己更清楚
var object = Pdf.GetObjectById("company_logo");
object.SetValue(myImage);
object.SetPosition(x, y);
从您的伪代码示例中,我们了解到您想要替换包含图像的对象流。有几个关于如何执行此操作的示例。
例如,在 SpecialID example, we create a PDF where we mark a specific image with a special ID. In the ResizeImage 示例中,我们根据该特殊 ID 跟踪该图像并替换流:
object = reader.getPdfObject(i);
if (object == null || !object.isStream())
continue;
stream = (PRStream)object;
if (value.equals(stream.get(key))) {
PdfImageObject image = new PdfImageObject(stream);
BufferedImage bi = image.getBufferedImage();
if (bi == null) continue;
int width = (int)(bi.getWidth() * FACTOR);
int height = (int)(bi.getHeight() * FACTOR);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
AffineTransform at = AffineTransform.getScaleInstance(FACTOR, FACTOR);
Graphics2D g = img.createGraphics();
g.drawRenderedImage(bi, at);
ByteArrayOutputStream imgBytes = new ByteArrayOutputStream();
ImageIO.write(img, "JPG", imgBytes);
stream.clear();
stream.setData(imgBytes.toByteArray(), false, PRStream.NO_COMPRESSION);
stream.put(PdfName.TYPE, PdfName.XOBJECT);
stream.put(PdfName.SUBTYPE, PdfName.IMAGE);
stream.put(key, value);
stream.put(PdfName.FILTER, PdfName.DCTDECODE);
stream.put(PdfName.WIDTH, new PdfNumber(width));
stream.put(PdfName.HEIGHT, new PdfNumber(height));
stream.put(PdfName.BITSPERCOMPONENT, new PdfNumber(8));
stream.put(PdfName.COLORSPACE, PdfName.DEVICERGB);
}
你会在书中找到另一个例子The Best iText Questions on Whosebug where I answered the following question: PDF Convert to Black And White PNGs
我写了 ReplaceImage
示例来展示如何替换图像:
public static 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));
}
}
如您所见,这并不像下面所说的那样微不足道:
var object = Pdf.GetObjectById("company_logo");
object.SetValue(myImage);
正如我在评论中解释的那样,这没有意义:
object.SetPosition(x, y);
我们正在操作的对象是用作图像 XObject 的流。拥有 Image XObjects 的优点是它们可以被重用。例如:如果您在每个页面上都有相同的徽标,那么您只想存储该图像的字节一次并多次重复使用相同的徽标。这意味着具有图像字节的对象对其位置一无所知。该位置在内容流中确定。这取决于CTM。
您是否看过 scribus 脚本功能? 由于您在 scribus 中创建了一个模板,您还可以编写一个简短的 python 脚本,用您的最终数据替换您的占位符并导出最终的 PDF。
从 scribus 1.5 开始,也可以从 commandline.
调用 python 脚本