2017-09-28 16:43:37 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module ActiveStorage
|
|
|
|
# This is an abstract base class for previewers, which generate images from blobs. See
|
2018-07-29 11:48:05 -04:00
|
|
|
# ActiveStorage::Previewer::MuPDFPreviewer and ActiveStorage::Previewer::VideoPreviewer for
|
|
|
|
# examples of concrete subclasses.
|
2017-09-28 16:43:37 -04:00
|
|
|
class Previewer
|
|
|
|
attr_reader :blob
|
|
|
|
|
|
|
|
# Implement this method in a concrete subclass. Have it return true when given a blob from which
|
|
|
|
# the previewer can generate an image.
|
|
|
|
def self.accept?(blob)
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
|
|
|
def initialize(blob)
|
|
|
|
@blob = blob
|
|
|
|
end
|
|
|
|
|
|
|
|
# Override this method in a concrete subclass. Have it yield an attachable preview image (i.e.
|
2019-12-20 15:06:03 -05:00
|
|
|
# anything accepted by ActiveStorage::Attached::One#attach). Pass the additional options to
|
|
|
|
# the underlying blob that is created.
|
|
|
|
def preview(**options)
|
2017-09-28 16:43:37 -04:00
|
|
|
raise NotImplementedError
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2018-05-16 22:12:31 -04:00
|
|
|
# Downloads the blob to a tempfile on disk. Yields the tempfile.
|
2018-05-16 22:50:08 -04:00
|
|
|
def download_blob_to_tempfile(&block) #:doc:
|
2019-03-28 18:47:42 -04:00
|
|
|
blob.open tmpdir: tmpdir, &block
|
2018-05-16 22:12:31 -04:00
|
|
|
end
|
|
|
|
|
2017-09-28 16:43:37 -04:00
|
|
|
# Executes a system command, capturing its binary output in a tempfile. Yields the tempfile.
|
|
|
|
#
|
2018-05-28 08:23:00 -04:00
|
|
|
# Use this method to shell out to a system library (e.g. muPDF or FFmpeg) for preview image
|
2017-09-28 16:43:37 -04:00
|
|
|
# generation. The resulting tempfile can be used as the +:io+ value in an attachable Hash:
|
|
|
|
#
|
|
|
|
# def preview
|
2017-10-22 13:16:59 -04:00
|
|
|
# download_blob_to_tempfile do |input|
|
2017-09-28 16:43:37 -04:00
|
|
|
# draw "my-drawing-command", input.path, "--format", "png", "-" do |output|
|
|
|
|
# yield io: output, filename: "#{blob.filename.base}.png", content_type: "image/png"
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
# end
|
2017-11-02 15:07:04 -04:00
|
|
|
#
|
2019-03-28 18:47:42 -04:00
|
|
|
# The output tempfile is opened in the directory returned by #tmpdir.
|
2017-12-31 13:08:36 -05:00
|
|
|
def draw(*argv) #:doc:
|
2018-06-03 20:19:57 -04:00
|
|
|
open_tempfile do |file|
|
|
|
|
instrument :preview, key: blob.key do
|
2018-01-10 21:46:55 -05:00
|
|
|
capture(*argv, to: file)
|
|
|
|
end
|
2018-06-03 20:19:57 -04:00
|
|
|
|
|
|
|
yield file
|
2017-09-28 16:43:37 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-06-03 20:19:57 -04:00
|
|
|
def open_tempfile
|
2019-03-28 18:47:42 -04:00
|
|
|
tempfile = Tempfile.open("ActiveStorage-", tmpdir)
|
2018-01-26 19:48:32 -05:00
|
|
|
|
|
|
|
begin
|
|
|
|
yield tempfile
|
|
|
|
ensure
|
|
|
|
tempfile.close!
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-06-03 20:19:57 -04:00
|
|
|
def instrument(operation, payload = {}, &block)
|
|
|
|
ActiveSupport::Notifications.instrument "#{operation}.active_storage", payload, &block
|
|
|
|
end
|
|
|
|
|
2017-09-28 16:43:37 -04:00
|
|
|
def capture(*argv, to:)
|
|
|
|
to.binmode
|
2017-12-31 13:02:15 -05:00
|
|
|
IO.popen(argv, err: File::NULL) { |out| IO.copy_stream(out, to) }
|
2017-09-28 16:43:37 -04:00
|
|
|
to.rewind
|
|
|
|
end
|
2017-11-30 23:54:03 -05:00
|
|
|
|
2017-12-31 13:08:36 -05:00
|
|
|
def logger #:doc:
|
2017-11-30 23:54:03 -05:00
|
|
|
ActiveStorage.logger
|
|
|
|
end
|
2018-05-16 22:55:09 -04:00
|
|
|
|
2019-03-28 18:47:42 -04:00
|
|
|
def tmpdir #:doc:
|
2018-05-16 22:55:09 -04:00
|
|
|
Dir.tmpdir
|
|
|
|
end
|
2017-09-28 16:43:37 -04:00
|
|
|
end
|
|
|
|
end
|