mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Provide an alternative PDF previewer based on Poppler
mutool is licensed under the Affero GPL, which has strict distribution requirements. Poppler is licensed under the more liberal GPL, making it a good alternative for those who can't use mutool.
This commit is contained in:
parent
060ed201e4
commit
0b717c2045
8 changed files with 104 additions and 35 deletions
|
@ -24,6 +24,7 @@ addons:
|
|||
- ffmpeg
|
||||
- mupdf
|
||||
- mupdf-tools
|
||||
- poppler-utils
|
||||
|
||||
bundler_args: --without test --jobs 3 --retry 3
|
||||
before_install:
|
||||
|
|
|
@ -21,10 +21,9 @@
|
|||
#
|
||||
# Outside of a Rails application, modify +ActiveStorage.previewers+ instead.
|
||||
#
|
||||
# The built-in previewers rely on third-party system libraries:
|
||||
#
|
||||
# * {ffmpeg}[https://www.ffmpeg.org]
|
||||
# * {mupdf}[https://mupdf.com] (version 1.8 or newer)
|
||||
# The built-in previewers rely on third-party system libraries. Specifically, the built-in video previewer requires
|
||||
# {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.
|
||||
#
|
||||
# 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.
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
require "rails"
|
||||
require "active_storage"
|
||||
|
||||
require "active_storage/previewer/pdf_previewer"
|
||||
require "active_storage/previewer/poppler_pdf_previewer"
|
||||
require "active_storage/previewer/mupdf_previewer"
|
||||
require "active_storage/previewer/video_previewer"
|
||||
|
||||
require "active_storage/analyzer/image_analyzer"
|
||||
|
@ -14,7 +15,7 @@ module ActiveStorage
|
|||
isolate_namespace ActiveStorage
|
||||
|
||||
config.active_storage = ActiveSupport::OrderedOptions.new
|
||||
config.active_storage.previewers = [ ActiveStorage::Previewer::PDFPreviewer, ActiveStorage::Previewer::VideoPreviewer ]
|
||||
config.active_storage.previewers = [ ActiveStorage::Previewer::PopplerPDFPreviewer, ActiveStorage::Previewer::MuPDFPreviewer, ActiveStorage::Previewer::VideoPreviewer ]
|
||||
config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer, ActiveStorage::Analyzer::VideoAnalyzer ]
|
||||
config.active_storage.paths = ActiveSupport::OrderedOptions.new
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ActiveStorage
|
||||
class Previewer::MuPDFPreviewer < Previewer
|
||||
class << self
|
||||
def accept?(blob)
|
||||
blob.content_type == "application/pdf" && mutool_exists?
|
||||
end
|
||||
|
||||
def mutool_path
|
||||
ActiveStorage.paths[:mutool] || "mutool"
|
||||
end
|
||||
|
||||
def mutool_exists?
|
||||
return @mutool_exists unless @mutool_exists.nil?
|
||||
|
||||
system mutool_path, out: File::NULL, err: File::NULL
|
||||
|
||||
@mutool_exists = $?.exitstatus == 1
|
||||
end
|
||||
end
|
||||
|
||||
def preview
|
||||
download_blob_to_tempfile do |input|
|
||||
draw_first_page_from input do |output|
|
||||
yield io: output, filename: "#{blob.filename.base}.png", content_type: "image/png"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def draw_first_page_from(file, &block)
|
||||
draw self.class.mutool_path, "draw", "-F", "png", "-o", "-", file.path, "1", &block
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ActiveStorage
|
||||
class Previewer::PDFPreviewer < Previewer
|
||||
def self.accept?(blob)
|
||||
blob.content_type == "application/pdf"
|
||||
end
|
||||
|
||||
def preview
|
||||
download_blob_to_tempfile do |input|
|
||||
draw_first_page_from input do |output|
|
||||
yield io: output, filename: "#{blob.filename.base}.png", content_type: "image/png"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def draw_first_page_from(file, &block)
|
||||
draw mutool_path, "draw", "-F", "png", "-o", "-", file.path, "1", &block
|
||||
end
|
||||
|
||||
def mutool_path
|
||||
ActiveStorage.paths[:mutool] || "mutool"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ActiveStorage
|
||||
class Previewer::PopplerPDFPreviewer < Previewer
|
||||
class << self
|
||||
def accept?(blob)
|
||||
blob.content_type == "application/pdf" && pdftoppm_exists?
|
||||
end
|
||||
|
||||
def pdftoppm_path
|
||||
ActiveStorage.paths[:pdftoppm] || "pdftoppm"
|
||||
end
|
||||
|
||||
def pdftoppm_exists?
|
||||
return @pdftoppm_exists unless @pdftoppm_exists.nil?
|
||||
|
||||
@pdftoppm_exists = system(pdftoppm_path, "-v", out: File::NULL, err: File::NULL)
|
||||
end
|
||||
end
|
||||
|
||||
def preview
|
||||
download_blob_to_tempfile do |input|
|
||||
draw_first_page_from input do |output|
|
||||
yield io: output, filename: "#{blob.filename.base}.png", content_type: "image/png"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def draw_first_page_from(file, &block)
|
||||
# use 72 dpi to match thumbnail dimesions of the PDF
|
||||
draw self.class.pdftoppm_path, "-singlefile", "-r", "72", "-png", file.path, &block
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,15 +3,15 @@
|
|||
require "test_helper"
|
||||
require "database/setup"
|
||||
|
||||
require "active_storage/previewer/pdf_previewer"
|
||||
require "active_storage/previewer/mupdf_previewer"
|
||||
|
||||
class ActiveStorage::Previewer::PDFPreviewerTest < ActiveSupport::TestCase
|
||||
class ActiveStorage::Previewer::MuPDFPreviewerTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@blob = create_file_blob(filename: "report.pdf", content_type: "application/pdf")
|
||||
end
|
||||
|
||||
test "previewing a PDF document" do
|
||||
ActiveStorage::Previewer::PDFPreviewer.new(@blob).preview do |attachable|
|
||||
ActiveStorage::Previewer::MuPDFPreviewer.new(@blob).preview do |attachable|
|
||||
assert_equal "image/png", attachable[:content_type]
|
||||
assert_equal "report.png", attachable[:filename]
|
||||
|
23
activestorage/test/previewer/poppler_pdf_previewer_test.rb
Normal file
23
activestorage/test/previewer/poppler_pdf_previewer_test.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
require "database/setup"
|
||||
|
||||
require "active_storage/previewer/poppler_pdf_previewer"
|
||||
|
||||
class ActiveStorage::Previewer::PopplerPDFPreviewerTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@blob = create_file_blob(filename: "report.pdf", content_type: "application/pdf")
|
||||
end
|
||||
|
||||
test "previewing a PDF document" do
|
||||
ActiveStorage::Previewer::PopplerPDFPreviewer.new(@blob).preview do |attachable|
|
||||
assert_equal "image/png", attachable[:content_type]
|
||||
assert_equal "report.png", attachable[:filename]
|
||||
|
||||
image = MiniMagick::Image.read(attachable[:io])
|
||||
assert_equal 612, image.width
|
||||
assert_equal 792, image.height
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue