2017-09-28 16:43:37 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
# Some non-image blobs can be previewed: that is, they can be presented as images. A video blob can be previewed by
|
|
|
|
# extracting its first frame, and a PDF blob can be previewed by extracting its first page.
|
|
|
|
#
|
2020-04-02 14:43:49 -04:00
|
|
|
# A previewer extracts a preview image from a blob. Active Storage provides previewers for videos and PDFs.
|
|
|
|
# ActiveStorage::Previewer::VideoPreviewer is used for videos whereas ActiveStorage::Previewer::PopplerPDFPreviewer
|
|
|
|
# and ActiveStorage::Previewer::MuPDFPreviewer are used for PDFs. Build custom previewers by
|
2017-09-28 16:43:37 -04:00
|
|
|
# subclassing ActiveStorage::Previewer and implementing the requisite methods. Consult the ActiveStorage::Previewer
|
|
|
|
# documentation for more details on what's required of previewers.
|
|
|
|
#
|
|
|
|
# To choose the previewer for a blob, Active Storage calls +accept?+ on each registered previewer in order. It uses the
|
|
|
|
# first previewer for which +accept?+ returns true when given the blob. In a Rails application, add or remove previewers
|
|
|
|
# by manipulating +Rails.application.config.active_storage.previewers+ in an initializer:
|
|
|
|
#
|
|
|
|
# Rails.application.config.active_storage.previewers
|
2020-04-02 14:43:49 -04:00
|
|
|
# # => [ ActiveStorage::Previewer::PopplerPDFPreviewer, ActiveStorage::Previewer::MuPDFPreviewer, ActiveStorage::Previewer::VideoPreviewer ]
|
2017-09-28 16:43:37 -04:00
|
|
|
#
|
|
|
|
# # Add a custom previewer for Microsoft Office documents:
|
|
|
|
# Rails.application.config.active_storage.previewers << DOCXPreviewer
|
2020-04-02 14:43:49 -04:00
|
|
|
# # => [ ActiveStorage::Previewer::PopplerPDFPreviewer, ActiveStorage::Previewer::MuPDFPreviewer, ActiveStorage::Previewer::VideoPreviewer, DOCXPreviewer ]
|
2017-09-28 16:43:37 -04:00
|
|
|
#
|
|
|
|
# Outside of a Rails application, modify +ActiveStorage.previewers+ instead.
|
|
|
|
#
|
2018-02-05 20:33:35 -05:00
|
|
|
# The built-in previewers rely on third-party system libraries. Specifically, the built-in video previewer requires
|
2018-05-28 08:23:00 -04:00
|
|
|
# {FFmpeg}[https://www.ffmpeg.org]. Two PDF previewers are provided: one requires {Poppler}[https://poppler.freedesktop.org],
|
|
|
|
# and the other requires {muPDF}[https://mupdf.com] (version 1.8 or newer). To preview PDFs, install either Poppler or muPDF.
|
2017-09-28 16:43:37 -04:00
|
|
|
#
|
|
|
|
# These libraries are not provided by Rails. You must install them yourself to use the built-in previewers. Before you
|
|
|
|
# install and use third-party software, make sure you understand the licensing implications of doing so.
|
|
|
|
class ActiveStorage::Preview
|
|
|
|
class UnprocessedError < StandardError; end
|
|
|
|
|
|
|
|
attr_reader :blob, :variation
|
|
|
|
|
|
|
|
def initialize(blob, variation_or_variation_key)
|
|
|
|
@blob, @variation = blob, ActiveStorage::Variation.wrap(variation_or_variation_key)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Processes the preview if it has not been processed yet. Returns the receiving Preview instance for convenience:
|
|
|
|
#
|
2019-12-02 11:34:01 -05:00
|
|
|
# blob.preview(resize_to_limit: [100, 100]).processed.url
|
2017-09-28 16:43:37 -04:00
|
|
|
#
|
|
|
|
# Processing a preview generates an image from its blob and attaches the preview image to the blob. Because the preview
|
|
|
|
# image is stored with the blob, it is only generated once.
|
|
|
|
def processed
|
|
|
|
process unless processed?
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
# Returns the blob's attached preview image.
|
|
|
|
def image
|
|
|
|
blob.preview_image
|
|
|
|
end
|
|
|
|
|
|
|
|
# Returns the URL of the preview's variant on the service. Raises ActiveStorage::Preview::UnprocessedError if the
|
|
|
|
# preview has not been processed yet.
|
|
|
|
#
|
|
|
|
# This method synchronously processes a variant of the preview image, so do not call it in views. Instead, generate
|
2019-12-02 11:34:01 -05:00
|
|
|
# a stable URL that redirects to the URL returned by this method.
|
|
|
|
def url(**options)
|
2017-09-28 16:43:37 -04:00
|
|
|
if processed?
|
2019-12-02 11:34:01 -05:00
|
|
|
variant.url(**options)
|
2017-09-28 16:43:37 -04:00
|
|
|
else
|
|
|
|
raise UnprocessedError
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-12-02 11:34:01 -05:00
|
|
|
alias_method :service_url, :url
|
|
|
|
deprecate service_url: :url
|
|
|
|
|
2020-05-11 16:21:58 -04:00
|
|
|
# Returns a combination key of the blob and the variation that together identifies a specific variant.
|
|
|
|
def key
|
|
|
|
if processed?
|
|
|
|
variant.key
|
|
|
|
else
|
|
|
|
raise UnprocessedError
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def download(&block)
|
|
|
|
if processed?
|
|
|
|
variant.download(&block)
|
|
|
|
else
|
|
|
|
raise UnprocessedError
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-09-28 16:43:37 -04:00
|
|
|
private
|
|
|
|
def processed?
|
|
|
|
image.attached?
|
|
|
|
end
|
|
|
|
|
|
|
|
def process
|
2019-12-20 15:06:03 -05:00
|
|
|
previewer.preview(service_name: blob.service_name) do |attachable|
|
2019-12-05 09:21:25 -05:00
|
|
|
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
|
|
|
|
image.attach(attachable)
|
|
|
|
end
|
|
|
|
end
|
2017-09-28 16:43:37 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def variant
|
2019-12-06 14:20:38 -05:00
|
|
|
image.variant(variation).processed
|
2017-09-28 16:43:37 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def previewer
|
|
|
|
previewer_class.new(blob)
|
|
|
|
end
|
|
|
|
|
|
|
|
def previewer_class
|
|
|
|
ActiveStorage.previewers.detect { |klass| klass.accept?(blob) }
|
|
|
|
end
|
|
|
|
end
|