问题
I am using Shrine Gem for image uploads and was wondering how, if possible, can I show a 1st page preview in my template like showing an image per-say. I am ok with using jQuery or other library. Below is my code for the file upload, including my Shrine initializer and uploader file.
view
...
<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>
...
initializer
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
uploader
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
回答1:
If you want to show PDF previews, you'll need to generate them on the server side. In that case it's best to use direct uploads (see the demo for an example of a client side implementation).
You can then generate PDFs preview on direct upload:
# 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
- the
upload_endpoint
sets the:upload
processing action, so that's the meaning ofprocess(:upload)
- we use
rb
forIO.popen
so that Ruby uses binary encoding, which is more safe and cross-platform Kernel#spawn
and any methods that usespawn
(system
,IO.popen
etc.) will raiseErrno::ENOENT
when shell command was not found- we use
*%W[]
instead of just""
so that Ruby avoids the shell (and with that any possible shell escaping issues) and passes the command directly to the OS - we check whether the
preview
file is nonempty because it will be empty in case themutool
command failed (in this case we probably want to fall back to not displaying a preview)
The result of the POST request to the upload_endpoint
will now contain the uploaded file ID of the preview, which you can use to generate the URL to the preview. In your case that would be "/uploads/cache" + id
.
Note that this means you'll have to slightly modify the processing code that is called when cached file is promoted to permanent storage. In the process(:store) do |io, context|
block the io
will now be a hash of versions, so you can access the original cached file via io[:original]
. And be sure to also include the preview file in the result of that block, as you'll likely want to keep it.
process(:store) do |io, context|
original = io[:original].download
# processing...
versions = io.dup
versions[:small] = small
versions[:medium] = medium
# ...
versions
end
来源:https://stackoverflow.com/questions/47641143/rails-5-pdf-preview-with-shrine-gem