【问题标题】:Manipulate PDF objects操作 PDF 对象
【发布时间】:2015-05-06 14:00:39
【问题描述】:

我正在尝试操作 PDF,它用作模板。我正在尝试用我的数据替换 PDF 模板中的“占位符”。因此有人在Scribus 中制作了一个PDF 模板,并添加了一个名为“company_logo”的空图像。我的应用程序看到一个名为“company_logo”的图像占位符,并在那里添加了公司徽标。

我可以使用 iTextSharp 库浏览 AcroFields 并在文本字段中设置文本(例如),但 AcroFields 没有列出图像占位符。我感觉 AcroFields 不是我想要的。

那么我如何从 PDF 中获取所有对象的列表(或树)并读取它们的属性(如位置、大小、内容等)。

附注我不一定需要使用 iTextSharp,任何其他 PDF 库也可以。最好是免费的。

一点伪代码让自己更清楚

var object = Pdf.GetObjectById("company_logo");
object.SetValue(myImage);
object.SetPosition(x, y);

【问题讨论】:

  • 首先,iTextSharp 不是免费的,它是开源的,并且有很大的不同。其次,你说AcroFields 不是你应该走的路是正确的。第三,如果您将 PDF 视为模板,那么您会遇到一些麻烦。综上所述,请通读the answer here 以获取(不完整)从哪里开始的示例
  • 您的伪代码表明缺乏对 PDF 的理解:图像的位置从未存储在图像中。如果是这样,那将意味着您不能重用 Image XObject。这段 1 分钟的视频解释了何时可以免费使用免费/开源软件以及何时需要商业许可:youtube.com/watch?v=QHF3xcWnSD4
  • PDF 文件中的图像不一定有名称或 ID。您能解释一下 Scribus 是如何将这些名称注入 PDF 的吗?

标签: c# pdf pdf-generation itextsharp pdfsharp


【解决方案1】:

从您的伪代码示例中,我们了解到您想要替换包含图像的对象的流。有几个示例说明如何执行此操作。

例如,在 SpecialID 示例中,我们创建了一个 PDF,其中我们使用特殊 ID 标记特定图像。在 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 StackOverflow 我回答了以下问题: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);

我们正在操作的对象是用作 Image XObjects 的流。拥有 Image XObjects 的优点是它们可以被重用。例如:如果您在每个页面上都有相同的徽标,那么您希望只存储该图像的字节一次并多次重复使用相同的徽标。这意味着具有图像字节的对象对其位置一无所知。位置在内容流中确定。这取决于 CTM。

【讨论】:

    【解决方案2】:

    您是否了解过 scribus 脚本功能? 由于您在 scribus 中创建了模板,因此您还可以编写一个简短的 python 脚本,用最终数据替换占位符并导出最终 PDF。

    从 scribus 1.5 开始,也可以从 commandline 调用 python 脚本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-25
      • 1970-01-01
      • 1970-01-01
      • 2014-03-25
      • 2018-06-17
      相关资源
      最近更新 更多