Class: Graphomaton::Exporters::Webp

Inherits:
Object
  • Object
show all
Includes:
Graphomaton::ExporterIntrospection
Defined in:
lib/graphomaton/exporters/webp.rb

Defined Under Namespace

Classes: ConversionError

Constant Summary collapse

DEFAULT_CONVERTER =
:auto
DEFAULT_TIMEOUT =
ProcessRunner::DEFAULT_TIMEOUT
DEFAULT_MAX_OUTPUT_BYTES =
ProcessRunner::DEFAULT_MAX_STDOUT_BYTES
PNG_SIGNATURE =
"\x89PNG\r\n\x1A\n".b.freeze
CONVERTER_COMMANDS =
{
  rsvg_magick: [
    ['rsvg-convert', '--format', 'png', '-'],
    ['magick', 'png:-', 'webp:-']
  ],
  magick: ['magick', 'svg:-', 'webp:-'],
  convert: ['convert', 'svg:-', 'webp:-']
}.freeze
CONVERTER_OPTIONS =
([:auto] + CONVERTER_COMMANDS.keys).freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Graphomaton::ExporterIntrospection

#capabilities, #losses_for

Constructor Details

#initialize(automaton) ⇒ Webp

Returns a new instance of Webp.



43
44
45
# File 'lib/graphomaton/exporters/webp.rb', line 43

def initialize(automaton)
  @automaton = automaton
end

Class Method Details

.available?(converter: DEFAULT_CONVERTER) ⇒ Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/graphomaton/exporters/webp.rb', line 28

def self.available?(converter: DEFAULT_CONVERTER)
  !available_command(converter: converter).nil?
end

.available_command(converter: DEFAULT_CONVERTER) ⇒ Object



32
33
34
35
36
37
38
39
40
41
# File 'lib/graphomaton/exporters/webp.rb', line 32

def self.available_command(converter: DEFAULT_CONVERTER)
  resolved_converter = resolve_converter(converter)
  if resolved_converter != :auto
    command = CONVERTER_COMMANDS[resolved_converter]
    return command if command_available?(command)
  end
  return nil if resolved_converter != :auto

  CONVERTER_COMMANDS.values.find { |command| command_available?(command) }
end

.command_available?(command) ⇒ Boolean

Returns:

  • (Boolean)


99
100
101
102
# File 'lib/graphomaton/exporters/webp.rb', line 99

def self.command_available?(command)
  stages = command.first.is_a?(Array) ? command : [command]
  stages.all? { |stage| executable?(stage.first) }
end

.executable?(command) ⇒ Boolean

Returns:

  • (Boolean)


95
96
97
# File 'lib/graphomaton/exporters/webp.rb', line 95

def self.executable?(command)
  !ProcessRunner.which(command).nil?
end

.resolve_converter(converter) ⇒ Object

Raises:

  • (ArgumentError)


104
105
106
107
108
109
# File 'lib/graphomaton/exporters/webp.rb', line 104

def self.resolve_converter(converter)
  resolved = converter.to_sym
  return resolved if CONVERTER_OPTIONS.include?(resolved)

  raise ArgumentError, "Unknown WebP converter: #{converter.inspect}. Available converters: #{CONVERTER_OPTIONS.join(', ')}"
end

Instance Method Details

#export(width = 800, height = 600, theme: Svg::DEFAULT_THEME, converter: DEFAULT_CONVERTER, timeout: DEFAULT_TIMEOUT, max_output_bytes: DEFAULT_MAX_OUTPUT_BYTES, **svg_options) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/graphomaton/exporters/webp.rb', line 47

def export(width = 800, height = 600, theme: Svg::DEFAULT_THEME, converter: DEFAULT_CONVERTER,
           timeout: DEFAULT_TIMEOUT, max_output_bytes: DEFAULT_MAX_OUTPUT_BYTES, **svg_options)
  export_result(
    width,
    height,
    theme: theme,
    converter: converter,
    timeout: timeout,
    max_output_bytes: max_output_bytes,
    **svg_options
  ).output
end

#export_result(width = 800, height = 600, theme: Svg::DEFAULT_THEME, converter: DEFAULT_CONVERTER, timeout: DEFAULT_TIMEOUT, max_output_bytes: DEFAULT_MAX_OUTPUT_BYTES, **svg_options) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/graphomaton/exporters/webp.rb', line 60

def export_result(width = 800, height = 600, theme: Svg::DEFAULT_THEME, converter: DEFAULT_CONVERTER,
                  timeout: DEFAULT_TIMEOUT, max_output_bytes: DEFAULT_MAX_OUTPUT_BYTES, **svg_options)
  command = available_command(converter: converter)
  raise ConversionError, missing_converter_message(converter) unless command

  svg_result = Svg.new(@automaton).export_result(width, height, theme: theme, **svg_options)
  webp, error, status = run_conversion(
    command,
    svg_result.output,
    timeout: timeout,
    max_output_bytes: max_output_bytes
  )
  webp = webp.b

  if status.success? && webp?(webp)
    return RenderResult.new(
      output: webp.freeze,
      diagnostics: svg_result.diagnostics,
      bounds: svg_result.bounds,
      layout: svg_result.layout
    )
  end
  raise ConversionError, invalid_webp_message(command, error) if status.success?

  raise ConversionError, failed_conversion_message(command, error)
rescue ProcessRunner::Error => e
  raise ConversionError, failed_conversion_message(command, e.message)
end