How to thumbnail a multi-page pdf with paperclip

前端 未结 2 1355
忘掉有多难
忘掉有多难 2021-02-04 18:22

I\'d like to have Paperclip create 2 thumbnails for each page of a multipage PDF file that is uploaded.

I\'m running Paperclip 2.3.1.1 and using this in my Asset model:<

相关标签:
2条回答
  • 2021-02-04 18:40

    I have a half-working solution to this... but it isn't very elegant. I'd really like to come up with something better, but I thought I'd share anyway.

    I started by defining a bunch of new styles, one for each page... up to however many pages I want to be able to handle. (stupid, I know, but I don't know how to access the path interpolations in Paperclip so that each page gets saved/deleted in the store properly unless there is a unique style for each image)

    { ...
    :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]},
    }
    

    Then... I have a custom processor which subclasses from the Thumbnail processor, with some extra logic for running the convert command with the proper page #.

    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
    
    0 讨论(0)
  • 2021-02-04 18:59

    Here how I implemented similar task.

    Document model:

    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
    

    Page model:

    class Page < ActiveRecord::Base
    
      belongs_to :document
    
      has_attached_file :asset
    
      QUALITY = 100
      DENSITY = '80x80'
    
    end
    
    0 讨论(0)
提交回复
热议问题