如何使用Paperclip为多页PDF生成缩略图

6

我希望Paperclip可以为上传的多页PDF文件的每一页创建两个缩略图。

我正在使用Paperclip 2.3.1.1,并在我的Asset模型中使用它:

    has_attached_file :asset,
                  :styles => { :medium => "800x600>", :thumb => "100x100>" }

当我上传一个3页的pdf文件时,我希望paperclip会为每一页创建两个缩略图(一个为800x600像素,另一个为100x100像素)。但实际上,我得到了三个文件夹(thumb, medium, original) - original文件夹中包含原始pdf文件,而thumb和medium各自包含一个只包括第一页且所有像素都模糊的pdf文件。
我需要怎么做才能让paperclip为pdf的每一页创建两个缩略图呢?理想情况下,我希望每一页会生成一个像这样的图片(一共生成6张图片):
assets/1/medium/file-0.png
assets/1/medium/file-1.png
assets/1/medium/file-2.png
assets/1/thumb/file-0.png
assets/1/thumb/file-1.png
assets/1/thumb/file-2.png
有人知道如何做吗?我需要定制处理器吗?如果需要,处理器应该长什么样?
谢谢。
2个回答

9
这里是我实现类似任务的方式。
文档模型:
class Document < ActiveRecord::Base

  has_many :pages, :dependent => :destroy

  has_attached_file :asset

  after_asset_post_process :make_pages

  private

  def make_pages
    if valid?
      Paperclip.run('convert', "-quality #{Page::QUALITY} -density #{Page::DENSITY} #{asset.queued_for_write[:original].path} #{asset.queued_for_write[:original].path}%d.png")
      images = Dir.glob("#{asset.queued_for_write[:original].path}*.png").sort_by do |line|
        line.match(/(\d+)\.png$/)[1].to_i
      end

      images.each do |page_image|
        pages.build(:asset => File.open(page_image))
      end
      FileUtils.rm images
    end
  end
end

页面模型:

class Page < ActiveRecord::Base

  belongs_to :document

  has_attached_file :asset

  QUALITY = 100
  DENSITY = '80x80'

end

我尝试了这个解决方案,但是转换命令似乎只为第一页生成1张图片。除此之外,它运行得很好。有什么想法吗? - Matt Smith
1
дҪ еҸҜд»ҘеңЁз»Ҳз«ҜдёӯдҪҝз”ЁImagemagickиҪҜ件еҢ…зҡ„convertе‘Ҫд»ӨиҝӣиЎҢи°ғиҜ•гҖӮ - taro
谢谢,我一直在尝试。但是还没有让它正常工作,只能为第一页生成1张图片。 - Matt Smith
考虑在此处共享您的文档并向Imagemagick专家提问。 - taro
非常好。我建议在构建页面之前添加类似于 pages.destroy_all 的内容,以防文档资产发生更改(这样您就不会有旧图像留在那里了)。 - Nikos

3
我有一个半成品的解决方案,但它不太优雅。我真的想想出更好的方法,但我还是想分享一下。
我开始定义了一堆新样式,每一页都有一个... 直到我想要处理的页面数量。 (很蠢,我知道,但我不知道如何访问Paperclip中的路径插值,以便每个图像都能正确保存/删除,除非有每个图像的唯一样式)
{ ...
:page_0 =>    {:geometry=>'800[0]',   :format=>:png, :processors=>[:multipage_thumbnail]},
:page_1 =>    {:geometry=>'800[1]',   :format=>:png, :processors=>[:multipage_thumbnail]},
:page_2 =>    {:geometry=>'800[2]',   :format=>:png, :processors=>[:multipage_thumbnail]},
:page_3 =>    {:geometry=>'800[3]',   :format=>:png, :processors=>[:multipage_thumbnail]},
:page_4 =>    {:geometry=>'800[4]',   :format=>:png, :processors=>[:multipage_thumbnail]},
:page_5 =>    {:geometry=>'800[5]',   :format=>:png, :processors=>[:multipage_thumbnail]},
}

那么...我有一个自定义处理器,它是从缩略图处理器派生的,其中包含一些额外的逻辑,用于以正确的页面编号运行转换命令。

module Paperclip
  # Handles thumbnailing images that are uploaded.
  class MultipageThumbnail < Thumbnail

    # Creates a Thumbnail object set to work on the +file+ given. It
    # will attempt to transform the image into one defined by +target_geometry+
    # which is a "WxH"-style string. +format+ will be inferred from the +file+
    # unless specified. Thumbnail creation will raise no errors unless
    # +whiny+ is true (which it is, by default. If +convert_options+ is
    # set, the options will be appended to the convert command upon image conversion
    def initialize file, options = {}, attachment = nil
      @page = options[:geometry].match(/\[(\d+)\]/)[1] rescue 0
      @page ||= 0
      options[:geometry] = options[:geometry].sub(/\[\d+\]/, '')
      super
    end

    # Performs the conversion of the +file+ into a thumbnail. Returns the Tempfile
    # that contains the new image.
    def make
      return nil if @page >= page_count

      src = @file
      dst = Tempfile.new([@basename, @format].compact.join("."))
      dst.binmode

      begin
        options = [
          source_file_options,
          "#{ File.expand_path(src.path) }[#{@page}]",
          transformation_command,
          convert_options,
          "#{ File.expand_path(dst.path) }"
        ].flatten.compact

        success = Paperclip.run("convert", *options)
      rescue PaperclipCommandLineError => e
        raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny
      end

      dst
    end

    def page_count
      @page_count ||= begin
        files = Paperclip.run("identify", "#{@file.path}")
        files.split(/\n/).size
      rescue PaperclipCommandLineError
        1
      end
    end

  end
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接