Изменение загруженного файла PDF в приложении Rails

#ruby-on-rails #pdf #pdf-generation #ruby-on-rails-3.1

#ruby-on-rails #PDF #генерация PDF #ruby-on-rails-3.1

Вопрос:

Я работаю над приложением Rails (Rails 3.1) и имею возможность загружать PDF-файл. Затем PDF-файл может быть загружен другими пользователями после входа в систему.

Что я действительно хотел бы сделать, так это добавить имя пользователя текущего зарегистрированного пользователя в нижней части каждой страницы PDF. Итак, внизу каждой страницы в формате PDF будет что-то вроде:

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

Я знаю, как заставить rails выводить PDF-файл из представления (согласно нескольким руководствам), но мне никогда не приходилось изменять уже загруженный PDF-файл.

Примечание: файлы PDF будут выводиться из Powerpoint и / или Keynote, поэтому каждая страница представляет собой «слайд».

Ответ №1:

Чистых решений ruby не существует, но я выполнял те же манипуляции (добавляя метки печати к существующему PDF-файлу) с помощью скрипта python, используя pyPdf и pycairo.

Вы можете найти его на Github, основная часть кода находится в draw-outline.py и outline.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()
  

Комментарии:

1. Я никогда даже не касался Python — я определенно не комбинировал его с Ruby! Является ли это сложным?

2. Если вы не используете расширенные возможности Python и уже разбираетесь в объектно-ориентированном программировании на Ruby, вы освоите его довольно быстро. Болевой точкой будет pycairo, так как нужно понять несколько концепций, но я помогу вам, ваша функция не выглядит очень сложной.