Class: Ucode::CodeChart::Verifier::ResvgStrategy

Inherits:
Strategy
  • Object
show all
Defined in:
lib/ucode/code_chart/verifier/resvg_strategy.rb

Overview

Strategy backed by the resvg CLI (resvg --help). Preferred over MutoolStrategy for accuracy and speed when available — resvg is purpose-built for SVG rendering and produces pixel-stable output across platforms.

Same byte-wise diff fallback as MutoolStrategy. PNG output is normalized via resvg's --quantize 8 to reduce byte-level noise across renderer versions.

Constant Summary

Constants inherited from Strategy

Strategy::FAIL_THRESHOLD

Instance Method Summary collapse

Constructor Details

#initialize(runner: Ucode::Glyphs::EmbeddedFonts::Mutool::SystemRunner.new) ⇒ ResvgStrategy

Returns a new instance of ResvgStrategy.

Parameters:



20
21
22
23
# File 'lib/ucode/code_chart/verifier/resvg_strategy.rb', line 20

def initialize(runner: Ucode::Glyphs::EmbeddedFonts::Mutool::SystemRunner.new)
  super()
  @runner = runner
end

Instance Method Details

#available?Boolean

Returns:

  • (Boolean)


25
26
27
# File 'lib/ucode/code_chart/verifier/resvg_strategy.rb', line 25

def available?
  system("which resvg >/dev/null 2>&1")
end

#diff(png_a, png_b) ⇒ Object



51
52
53
54
55
56
57
58
59
60
# File 'lib/ucode/code_chart/verifier/resvg_strategy.rb', line 51

def diff(png_a, png_b)
  bytes_a = File.binread(png_a)
  bytes_b = File.binread(png_b)
  return 100.0 if bytes_a.bytesize != bytes_b.bytesize

  same = bytes_a.each_byte.with_index.count do |byte, idx|
    byte == bytes_b.getbyte(idx)
  end
  (100.0 * (1.0 - same.to_f / bytes_a.bytesize)).round(2)
end

#render_pdf_region(pdf_path, page, _rect, png_path, scale: 2.0) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/ucode/code_chart/verifier/resvg_strategy.rb', line 37

def render_pdf_region(pdf_path, page, _rect, png_path, scale: 2.0)
  # resvg doesn't render PDFs; we rely on mutool to first
  # convert the page region to SVG, then resvg to PNG. Two
  # subprocess hops, but reuses each tool's strength.
  intermediate = Pathname.new("#{png_path}.svg")
  dpi = (72 * scale).round
  @runner.run("mutool", "draw", "-F", "svg", "-o", intermediate.to_s,
              "-r", dpi.to_s, pdf_path.to_s, page.to_s)
  @runner.run("resvg", "--quantize", "8",
              intermediate.to_s, png_path.to_s)
  FileUtils.rm_f(intermediate.to_s)
  Pathname.new(png_path)
end

#render_svg(svg_path, png_path, scale: 2.0) ⇒ Object



29
30
31
32
33
34
35
# File 'lib/ucode/code_chart/verifier/resvg_strategy.rb', line 29

def render_svg(svg_path, png_path, scale: 2.0)
  width = (1000 * scale).round
  @runner.run("resvg", "-w", width.to_s,
              "--quantize", "8",
              svg_path.to_s, png_path.to_s)
  Pathname.new(png_path)
end

#write_diff_artifact(png_a, png_b, dest) ⇒ Object



62
63
64
65
66
67
# File 'lib/ucode/code_chart/verifier/resvg_strategy.rb', line 62

def write_diff_artifact(png_a, png_b, dest)
  data_a = File.binread(png_a)
  data_b = File.binread(png_b)
  Pathname.new(dest).binwrite(data_a + data_b)
  Pathname.new(dest)
end