【问题标题】:Alter an uploaded PDF file within a Rails application在 Rails 应用程序中更改上传的 PDF 文件
【发布时间】:2011-12-02 07:04:48
【问题描述】:

我正在开发一个 Rails 应用程序(Rails 3.1)并且能够上传 PDF 文件。其他用户登录后即可下载 PDF 文件。

我真正想做的是将当前登录用户的用户名附加到每个 PDF 页面的底部。所以在 PDF 中每一页的底部都会有这样的内容:

Downloaded from ww.mysite.com by Mr U. Name

我知道如何让 rails 从视图中输出 pdf(根据一些 tutorials),但我从来不需要更改已经上传的 PDF。

附注:PDF 文件将从 Powerpoint 和/或 Keynote 输出 - 所以每一页都是“幻灯片”。

【问题讨论】:

    标签: ruby-on-rails pdf pdf-generation ruby-on-rails-3.1


    【解决方案1】:

    纯 ruby​​ 解决方案不存在,但我一直在使用 python 脚本进行相同类型的操作(向现有 PDF 添加打印标记),使用 pyPdfpycairo

    你可以find it on Github,大部分代码在draw-outline.pyoutline.py

    如果您对此解决方案感兴趣,我可以提取一个快速教程并将其发布在此处。

    更新

    我已经提取了一个快速脚本来将文本添加到任意 PDF 的每一页,它又快又脏,但它应该可以完成这项工作。

    用法:

    Usage: name-generator.py [options] filename
    
    Options:
      -h, --help            show this help message and exit
      -o OUTPUT_FILENAME, --output=OUTPUT_FILENAME
                            output filename, defaults to output.pdf
      -t TEXT, --text=TEXT  text to add
      -s SIZE, --size=SIZE  size of the text, in millimeters
      -x X                  horizontal position of the text in millimeters, the
                            origin is the left side
      -y Y                  vertical position of the text in millimeters, the
                            origin is the top side
    

    代码:

    #!/usr/bin/env python
    from optparse import OptionParser
    import os.path
    
    # Constants
    MM_TO_PT = 2.834645669
    DEFAULT_OUTPUT = "output.pdf"
    
    # Option parsing
    parser = OptionParser("Usage: %prog [options] filename")
    parser.add_option("-o", "--output", type="string", dest="output_filename", default=DEFAULT_OUTPUT, help="output filename, defaults to %s" % DEFAULT_OUTPUT)
    parser.add_option("-t", "--text", type="string", dest="text", help="text to add")
    parser.add_option("-s", "--size", type="float", dest="size", default=10, help="size of the text, in millimeters")
    parser.add_option("-x", type="int", dest="x", default=100, help="horizontal position of the text in millimeters, the origin is the left side")
    parser.add_option("-y", type="int", dest="y", default=100, help="vertical position of the text in millimeters, the origin is the top side")
    
    (options, args) = parser.parse_args()
    
    if len(args) != 1 or not os.path.isfile(args[0]):
      parser.print_help()
      exit()
    
    
    # Pdf manipulation class
    import cairo
    import StringIO
    
    class TextCreator:
    
      def __init__(self, width, height):
        self.width, self.height = width, height
    
        self.output = StringIO.StringIO()
        self.surface = cairo.PDFSurface(
            self.output,
            self.width * MM_TO_PT,
            self.height * MM_TO_PT
        )
    
      def print_text(self, text, size, x, y):
        context = self.create_context()
    
        context.move_to(x, y)
    
        context.set_font_size(size)
        context.show_text(text)
    
        self.surface.flush()
        self.surface.finish()
    
        return self.output
    
      def create_context(self):
        context = cairo.Context(self.surface)
        context.set_source_rgb(0, 0, 0)
        context.set_line_width(0.2)
    
        # Allow drawing on the context using human-friendly units (millimeters)
        context.scale(MM_TO_PT, MM_TO_PT)
    
        return context
    
    
    # Let's get to work
    from pyPdf import PdfFileWriter, PdfFileReader
    
    # Read the input and prepare the output document
    filename = args[0]
    document = PdfFileReader(file(filename, "rb"))
    output = PdfFileWriter()
    
    for page_num in range(document.getNumPages()):
      # Get the page dimensions
      page = document.getPage(page_num)
      box = page.mediaBox
      # PDF dimensions are in points, convert them to millimeters
      width = round(float(box[2]) / MM_TO_PT)
      height = round(float(box[3]) / MM_TO_PT)
    
      # Create a PDF page containing the text
      text_creator = TextCreator(
          width,
          height
      )
      text = text_creator.print_text(options.text, options.size, options.x, options.y)
    
      # Merge the text with the current page and add it to the output
      page.mergePage(PdfFileReader(text).getPage(0))
      output.addPage(page)
    
    
    outputStream = file(options.output_filename, "wb")
    output.write(outputStream)
    outputStream.close()
    

    【讨论】:

    • 我什至从未接触过 Python——我绝对没有将它与 Ruby 结合使用!复杂吗?
    • 如果您不使用高级 Python 功能并且您已经掌握了 Ruby 中的面向对象编程,那么您将很快学会它。痛点将是 pycairo,因为有一些概念需要理解,但我会帮助你,你的功能看起来并不复杂。
    猜你喜欢
    • 1970-01-01
    • 2016-08-17
    • 2021-02-12
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 2019-09-19
    • 2015-10-26
    相关资源
    最近更新 更多