最近在做一个与 pdf 处理相关的事情,希望能用 ruby 处理 pdf,做到例如拼合,拆分,在 pdf 上添加图片生成新的 pdf 等功能。不知道各位有没有这方面的相关经验?
Focus Solutions, Inc 做这方面有很多年的经验了
pdftk 和 iText 都可以做 merge,甚至 Prawn 也可以做合并,但是 Prawn 最慢,不用考虑。 pdftk 可以直接在系统中装了直接用命令行。 iText 需要 Rjb,但是合并速度更快效率更高。看代码
def self.itext_merge(filenames, output)
class_pdfreader = Rjb::import('com.lowagie.text.pdf.PdfReader')
class_pdfcopyfields = Rjb::import('com.lowagie.text.pdf.PdfCopyFields')
class_filestream = Rjb::import('java.io.FileOutputStream')
filestream = class_filestream.new(output)
copy = class_pdfcopyfields.new(filestream)
failure_list = []
filenames.each do |f|
# remove double quote
if match = /"(.*)"/.match(f)
f = match[1]
end
if File.exists?(f)
begin
copy.addDocument(class_pdfreader.new(f))
rescue => e
failure_list << f
Rails.logger.info "PdfMerger: Invalid PDF: #{f}"
end
else
failure_list << f
Rails.logger.info "PdfMerger: File does not exist: #{f}"
end
end
copy.close()
# pages = class_pdfreader.new(output).getNumberOfPages
Rails.logger.info "failed pdf: #{failure_list}" if failure_list.present?
return failure_list.empty?
rescue Exception => e
Rails.logger.info "itext_merge failure: #{e.message}"
return false
end
def self.pdftk_merge(filenames, output)
#pdftk a.pdf b.pdf output c.pdf dont_ask
response = `pdftk #{filenames.join(" ")} output #{output.to_s} dont_ask`
Rails.logger.info(response) if response.present?
not (response =~ /Error/)
end
需要看你的需求,2 个方案 wkhtmltopdf 或者 Prawn 区别 Prawn,写代码费劲,需要计算文字大小,格式,预留位置等,支持多重 font-type WkhtmltoPDF,写代码方便,不方便控制字体,宽度,分页等。
以上两个都是从 0 生成 PDF,如果你是要修改 pdf,添加一个图片的话还可以使用 PDF::Stamper, 其实 Stamper 也是使用 iText 的。 你可以自己改下代码。 比如 添加二维码
# barcodes:
# [
# {:token => "xsfsdfsdfdsf", :format => "Code128", :page => 1}
# ]
def self.embed_barcode(input_pdf_path, output_pdf_path = nil, barcodes = [])
output_pdf_path ||= Rails.root.join("tmp/set_barcode_output_#{rand(10000000)}.pdf")
stamper = PDF::Stamper.new(input_pdf_path.to_s)
barcodes.each do |barcode|
page = barcode[:page]
page_height = stamper.get_page_height(page)
page_width = stamper.get_page_width(page)
img = generate_barcode_img(barcode[:format], barcode[:token])
stamper.add_image(img, page)
end
stamper.save_as(output_pdf_path)
output_pdf_path
end
#Format: Code128 , DataMatrix
def self.generate_barcode_img(format, token)
builder = Barby.const_get(format)
barcode = builder.new(token)
outputter = Barby::PngOutputter.new(barcode)
outputter.margin = 0
img_path = Rails.root.join("tmp/barcode_#{format}_#{token}.png")
img_size_opts = case format
when "Code128", "Code128A", "Code128B", "Code128C"
{:height => 16}
when "DataMatrix"
{}
end
File.open(img_path, "w") {|f| f.write outputter.to_png(img_size_opts) }
img_path
end
def add_image(image_path, page, x = nil,y = nil)
image = Rjb::import('com.lowagie.text.Image')
img = image.getInstance(image_path)
img.setAbsolutePosition(x || 550, y || 40);
#img.scalePercent(20);
cb = @stamp.getOverContent(page)
cb.addImage(img)
end
如果你对 PDF 还有更详细需求,可以找我们