diff options
| author | Dan Allen <dan.j.allen@gmail.com> | 2022-09-05 04:27:39 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-05 04:27:39 -0600 |
| commit | e7f79c606ef6c3c057f53d03c24928aa454818f3 (patch) | |
| tree | 6d7c2132474514b8713126f78ec7da65d84f9bc5 /lib | |
| parent | aae57ce605d7e9a6704ef71a88591bbbf96db9c4 (diff) | |
resolves #2330 allow PDF optimizer to be pluggable (PR #2332)
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/asciidoctor/pdf/converter.rb | 5 | ||||
| -rw-r--r-- | lib/asciidoctor/pdf/optimizer.rb | 94 | ||||
| -rw-r--r-- | lib/asciidoctor/pdf/optimizer/rghost.rb | 73 |
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 |
