Rails 5 pdf 预览与 Shrine Gem

Rails 5 pdf preview with Shrine Gem

我正在使用 Shrine Gem 上传图片,想知道如果可能的话,我如何才能在我的模板中显示第一页预览,就像每次显示图片一样。我可以使用 jQuery 或其他库。下面是我的文件上传代码,包括我的 Shrine 初始化程序和上传文件。

查看

...
<div class="col-md-4 upload-block">
    <%= f.label :spec_sheet, 'Spec Sheet' %>
      <% if @product.spec_sheet.present? %>
        <div class="product-image">
          <%= image_tag(@product.spec_sheet_url(:thumb)) %>
            <div class="input-checkbox input-checkbox--switch">
              <input name="product[remove_spec_sheet]" type="hidden" value="0">
              <input id="checkbox-switch" type="checkbox" name="product[remove_spec_sheet]">
              <label for="checkbox-switch"></label>
            </div>
            <span>Remove Spec Sheet</span>
        </div>
        <% end %>
          <%= f.hidden_field :spec_sheet, value: @product.cached_spec_sheet_data %>
            <%= f.file_field :spec_sheet %>
  </div>
...

初始化器

require 'shrine'
require 'shrine/storage/file_system'

Shrine.storages = {
    cache: Shrine::Storage::FileSystem.new('public', prefix: 'uploads/cache'),
    store: Shrine::Storage::FileSystem.new('public', prefix: 'uploads/store'),
}

Shrine.plugin :activerecord
Shrine.plugin :remove_attachment
Shrine.plugin :delete_raw
Shrine.plugin :cached_attachment_data # for forms 

上传者

require 'image_processing/mini_magick'
class ImageUploader < Shrine
  MAX_IMAGE_SIZE_MB = 5
  include ImageProcessing::MiniMagick

  plugin :determine_mime_type
  plugin :remove_attachment
  plugin :store_dimensions
  plugin :validation_helpers
  plugin :processing
  plugin :versions
  plugin(:default_url) { |_|  '/img/preview-not-available.jpg' }

  Attacher.validate do
    validate_max_size MAX_IMAGE_SIZE_MB.megabytes, message: "is too large (max is #{MAX_IMAGE_SIZE_MB} MB)"
    validate_mime_type_inclusion %w[image/jpeg image/jpg image/png image/gif]
  end

  process(:store) do |io|
    original = io.download

    size_1500 = resize_to_limit!(original, 1500, 600)
    size_500 = resize_to_limit(size_1500,  500, 500)
    size_300 = resize_to_limit(size_500,  300, 300)

    {original: size_1500, medium: size_500, thumb: size_300 }
  end
end

如果您想显示 PDF 预览,您需要在服务器端生成它们。在这种情况下,最好使用 direct uploads (see the demo 作为客户端实现的示例。

然后您可以在直接上传时生成 PDF 预览:

# config/initializers/shrine.rb
Shrine.plugin :determine_mime_type

# app/models/image_uploader.rb
class ImageUploader < Shrine
  plugin :processing
  plugin :versions

  process(:upload) do |io, context|
    if Shrine.determine_mime_type(io) == "application/pdf"
      preview = Tempfile.new(["shrine-pdf-preview", ".pdf"], binmode: true)
      begin
        IO.popen *%W[mutool draw -F png -o - #{io.path} 1], "rb" do |command|
          IO.copy_stream(command, preview)
        end
      rescue Errno::ENOENT
        fail "mutool is not installed"
      end

      preview.open # flush & rewind
    end

    versions = { original: io }
    versions[:preview] = preview if preview && preview.size > 0
    versions
  end
end
  • upload_endpoint设置了:upload处理动作,所以就是process(:upload)
  • 的意思
  • 我们对IO.popen使用rb,这样Ruby使用二进制编码,更安全,跨平台
  • Kernel#spawn 和任何使用 spawn 的方法(systemIO.popen 等)将在 shell 命令被执行时引发 Errno::ENOENT未找到
  • 我们使用 *%W[] 而不是仅仅 "" 以便 Ruby 避免 shell (以及任何可能的 shell 转义问题)并通过命令直接到 OS
  • 我们检查 preview 文件是否为空,因为万一 mutool 命令失败,它会是空的(在这种情况下,我们可能想回退到不显示预览)

upload_endpoint 的 POST 请求的结果现在将包含预览的上传文件 ID,您可以使用它来生成对预览的 URL .在你的情况下是 "/uploads/cache" + id.

请注意,这意味着您必须稍微修改缓存文件提升为永久存储时调用的处理代码。在 process(:store) do |io, context| 块中,io 现在将是版本的散列,因此您可以通过 io[:original] 访问原始缓存文件。并确保在该块的结果中也包含预览文件,因为您可能希望保留它。

process(:store) do |io, context|
  original = io[:original].download

  # processing...

  versions = io.dup
  versions[:small] = small
  versions[:medium] = medium
  # ...
  versions
end