summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDan Allen <dan.j.allen@gmail.com>2022-09-05 04:27:39 -0600
committerGitHub <noreply@github.com>2022-09-05 04:27:39 -0600
commite7f79c606ef6c3c057f53d03c24928aa454818f3 (patch)
tree6d7c2132474514b8713126f78ec7da65d84f9bc5 /lib
parentaae57ce605d7e9a6704ef71a88591bbbf96db9c4 (diff)
resolves #2330 allow PDF optimizer to be pluggable (PR #2332)
Diffstat (limited to 'lib')
-rw-r--r--lib/asciidoctor/pdf/converter.rb5
-rw-r--r--lib/asciidoctor/pdf/optimizer.rb94
-rw-r--r--lib/asciidoctor/pdf/optimizer/rghost.rb73
3 files changed, 111 insertions, 61 deletions
diff --git a/lib/asciidoctor/pdf/converter.rb b/lib/asciidoctor/pdf/converter.rb
index cb1a86a6..ac4dd13b 100644
--- a/lib/asciidoctor/pdf/converter.rb
+++ b/lib/asciidoctor/pdf/converter.rb
@@ -3,6 +3,7 @@
require_relative 'formatted_string'
require_relative 'formatted_text'
require_relative 'index_catalog'
+require_relative 'optimizer'
require_relative 'pdfmark'
require_relative 'roman_numeral'
require_relative 'section_info_by_page'
@@ -37,7 +38,6 @@ module Asciidoctor
CodeRayRequirePath = ::File.join __dir__, 'ext/prawn/coderay_encoder'
RougeRequirePath = ::File.join __dir__, 'ext/rouge'
PygmentsRequirePath = ::File.join __dir__, 'ext/pygments'
- OptimizerRequirePath = ::File.join __dir__, 'optimizer'
AdmonitionIcons = {
caution: { name: 'fas-fire', stroke_color: 'BF3400' },
@@ -420,8 +420,7 @@ module Asciidoctor
@pdfmark = (doc.attr? 'pdfmark') ? (Pdfmark.new doc) : nil
# NOTE: defer instantiating optimizer until we know min pdf version
if (optimize = doc.attr 'optimize') &&
- (optimizer = doc.options[:pdf_optimizer] || (((defined? ::Asciidoctor::PDF::Optimizer) ||
- !(Helpers.require_library OptimizerRequirePath, 'rghost', :warn).nil?) && ::Asciidoctor::PDF::Optimizer))
+ (optimizer = doc.options[:pdf_optimizer] || (Optimizer.for (doc.attr 'pdf-optimizer', 'rghost')))
@optimize = (optimize.include? ',') ?
([:quality, :compliance].zip (optimize.split ',', 2)).to_h :
((optimize.include? '/') ? { compliance: optimize } : { quality: optimize })
diff --git a/lib/asciidoctor/pdf/optimizer.rb b/lib/asciidoctor/pdf/optimizer.rb
index c979a5e4..19ad155e 100644
--- a/lib/asciidoctor/pdf/optimizer.rb
+++ b/lib/asciidoctor/pdf/optimizer.rb
@@ -1,78 +1,56 @@
# frozen_string_literal: true
-require 'pathname'
-require 'rghost'
-require 'rghost/gs_alone'
-require 'tmpdir'
-
-RGhost::GSAlone.prepend (Module.new do
- def initialize params, debug
- (@params = params.dup).push(*(@params.pop.split File::PATH_SEPARATOR))
- @debug = debug
- end
-
- def run
- RGhost::Config.config_platform unless File.exist? RGhost::Config::GS[:path].to_s
- (cmd = @params.slice 1, @params.length).unshift RGhost::Config::GS[:path].to_s
- #puts cmd if @debug
- system(*cmd)
- end
-end)
-
-RGhost::Engine.prepend (Module.new do
- def shellescape str
- str
- end
-end)
-
module Asciidoctor
module PDF
- class Optimizer
- # see https://www.ghostscript.com/doc/current/VectorDevices.htm#PSPDF_IN for details
- (QUALITY_NAMES = {
- 'default' => :default,
- 'screen' => :screen,
- 'ebook' => :ebook,
- 'printer' => :printer,
- 'prepress' => :prepress,
- }).default = :default
-
+ module Optimizer
attr_reader :quality
attr_reader :compatibility_level
attr_reader :compliance
def initialize quality = 'default', compatibility_level = '1.4', compliance = 'PDF'
- @quality = QUALITY_NAMES[quality]
+ @quality = quality
@compatibility_level = compatibility_level
@compliance = compliance
- if (gs_path = ::ENV['GS'])
- ::RGhost::Config::GS[:path] = gs_path
- end
end
def optimize_file target
- ::Dir::Tmpname.create ['asciidoctor-pdf-', '.pdf'] do |tmpfile|
- filename_o = ::Pathname.new target
- filename_tmp = ::Pathname.new tmpfile
- if (pdfmark = filename_o.sub_ext '.pdfmark').file?
- inputs = [target, pdfmark.to_s].join ::File::PATH_SEPARATOR
- else
- inputs = target
- end
- d = { Printed: false, CannotEmbedFontPolicy: '/Warning', CompatibilityLevel: @compatibility_level }
- case @compliance
- when 'PDF/A', 'PDF/A-1', 'PDF/A-2', 'PDF/A-3'
- d[:PDFA] = ((@compliance.split '-', 2)[1] || 1).to_i
- d[:ShowAnnots] = false
- when 'PDF/X', 'PDF/X-1', 'PDF/X-3'
- d[:PDFX] = true
- d[:ShowAnnots] = false
+ raise ::NotImplementedError, %(#{Optimizer} subclass #{self.class} must implement the ##{__method__} method)
+ end
+
+ private_class_method def self.included into
+ into.extend Config
+ end
+
+ module Config
+ def register_for name
+ Optimizer.register self, name.to_s
+ end
+ end
+
+ module Factory
+ @@registry = {}
+
+ def for name
+ if (optimizer = @@registry[name]).nil? && name == 'rghost'
+ if (::Asciidoctor::Helpers.require_library %(#{__dir__}/optimizer/rghost), 'rghost', :warn).nil?
+ @@registry[name] = false
+ else
+ optimizer = @@registry[name] = Optimizer::RGhost
+ end
end
- (::RGhost::Convert.new inputs).to :pdf, filename: filename_tmp.to_s, quality: @quality, d: d
- filename_o.binwrite filename_tmp.binread
+ optimizer || nil
+ end
+
+ def register optimizer, name
+ optimizer ? (@@registry[name] = optimizer) : (@@registry.delete name)
end
- nil
end
+
+ class Base
+ include Optimizer
+ end
+
+ extend Factory
end
end
end
diff --git a/lib/asciidoctor/pdf/optimizer/rghost.rb b/lib/asciidoctor/pdf/optimizer/rghost.rb
new file mode 100644
index 00000000..1f8c34dc
--- /dev/null
+++ b/lib/asciidoctor/pdf/optimizer/rghost.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require_relative '../optimizer' unless defined? ::Asciidoctor::PDF::Optimizer
+require 'pathname'
+require 'rghost'
+require 'rghost/gs_alone'
+require 'tmpdir'
+
+RGhost::GSAlone.prepend (Module.new do
+ def initialize params, debug
+ (@params = params.dup).push(*(@params.pop.split File::PATH_SEPARATOR))
+ @debug = debug
+ end
+
+ def run
+ RGhost::Config.config_platform unless File.exist? RGhost::Config::GS[:path].to_s
+ (cmd = @params.slice 1, @params.length).unshift RGhost::Config::GS[:path].to_s
+ #puts cmd if @debug
+ system(*cmd)
+ end
+end)
+
+RGhost::Engine.prepend (Module.new do
+ def shellescape str
+ str
+ end
+end)
+
+module Asciidoctor
+ module PDF
+ class Optimizer::RGhost < Optimizer::Base
+ # see https://www.ghostscript.com/doc/current/VectorDevices.htm#PSPDF_IN for details
+ (QUALITY_NAMES = {
+ 'default' => :default,
+ 'screen' => :screen,
+ 'ebook' => :ebook,
+ 'printer' => :printer,
+ 'prepress' => :prepress,
+ }).default = :default
+
+ def initialize *_args
+ super
+ if (gs_path = ::ENV['GS'])
+ ::RGhost::Config::GS[:path] = gs_path
+ end
+ end
+
+ def optimize_file target
+ ::Dir::Tmpname.create ['asciidoctor-pdf-', '.pdf'] do |tmpfile|
+ filename_o = ::Pathname.new target
+ filename_tmp = ::Pathname.new tmpfile
+ if (pdfmark = filename_o.sub_ext '.pdfmark').file?
+ inputs = [target, pdfmark.to_s].join ::File::PATH_SEPARATOR
+ else
+ inputs = target
+ end
+ d = { Printed: false, CannotEmbedFontPolicy: '/Warning', CompatibilityLevel: @compatibility_level }
+ case @compliance
+ when 'PDF/A', 'PDF/A-1', 'PDF/A-2', 'PDF/A-3'
+ d[:PDFA] = ((@compliance.split '-', 2)[1] || 1).to_i
+ d[:ShowAnnots] = false
+ when 'PDF/X', 'PDF/X-1', 'PDF/X-3'
+ d[:PDFX] = true
+ d[:ShowAnnots] = false
+ end
+ (::RGhost::Convert.new inputs).to :pdf, filename: filename_tmp.to_s, quality: QUALITY_NAMES[@quality], d: d
+ filename_o.binwrite filename_tmp.binread
+ end
+ nil
+ end
+ end
+ end
+end