module Cooltrainer::DistorteD::Molecule::Text

Constants

CODEPAGE_FONT

Certain fonts are more suitable for certain codepages, so track each codepage's available fonts…

FONT_CODEPAGE

…as well as the inverse, the numeric codepage for each font:

FONT_FILENAME

Track supported fonts by codepage. Avoid renaming these from the original archives / websites. Try not to go nuts here bloating the size of our Gem for a very niche feature, but I want to ensure good coverage too.

Treat codepage 8859 documents as codepage 1252 to avoid breaking smart- quotes and other printable chars in 1252 that are control chars in 8859. encoding.spec.whatwg.org/#names-and-labels

Numeric key for UTF-8 is codepage 65001 like Win32: docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers

LOWER_WORLD
OUTER_LIMITS

Public Instance Methods

to_pango() click to toggle source

Return a Pango Markup escaped version of the document.

# File lib/distorted/media_molecule/text.rb, line 100
def to_pango
  # https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html#g-markup-escape-text
  escaped = text_file_utf8_content.map{ |c|
    g_markup_escape_char(c)
  }
  if font_spacing == :monospace
    "<tt>" << escaped << "</tt>"
  else
    escaped
  end
end

Protected Instance Methods

font_codepage() click to toggle source

Returns the numeric representation of the codepage covered by our font.

# File lib/distorted/media_molecule/text.rb, line 194
def font_codepage
  FONT_CODEPAGE.dig(vips_font).to_s
end
font_filename() click to toggle source

Returns the basename (with file extension) of our font.

# File lib/distorted/media_molecule/text.rb, line 199
def font_filename
  FONT_FILENAME.dig(vips_font)
end
font_path() click to toggle source

Return the String absolute path to the TTF file

# File lib/distorted/media_molecule/text.rb, line 180
def font_path
  File.join(
    File.dirname(__FILE__),  # molecule
    '..'.freeze,  # distorted
    '..'.freeze,  # lib
    '..'.freeze,  # DistorteD-Floor
    'font'.freeze,
    font_codepage.to_s,
    font_filename,
  )
end
text_file_content() click to toggle source
# File lib/distorted/media_molecule/text.rb, line 114
def text_file_content
  # VIPS makes us provide the text content as a single variable,
  # so we may as well just one-shot File.read() it into memory.
  # https://kunststube.net/encoding/
  @text_file_content ||= File.read(path)
end
text_file_encoding() click to toggle source
# File lib/distorted/media_molecule/text.rb, line 125
def text_file_encoding
  # It's not easy or even possible in some cases to tell the "true" codepage
  # we should use for any given text document, but using character detection
  # is worth a shot if the user gave us nothing.
  #
  # TODO: Figure out if/how we can get IBM437 files to not be detected as ISO-8859-1
  @text_file_encoding ||= Encoding::find(
    abstract(:encoding).to_s ||
    CharlockHolmes::EncodingDetector.detect(text_file_content)[:encoding] ||
    'UTF-8'.freeze
  )
end
text_file_utf8_content() click to toggle source
# File lib/distorted/media_molecule/text.rb, line 121
def text_file_utf8_content
  CharlockHolmes::Converter.convert(text_file_content, text_file_encoding.to_s, 'UTF-8'.freeze)
end
to_vips_image() click to toggle source
# File lib/distorted/media_molecule/text.rb, line 143
def to_vips_image
  # Load font metadata directly from the file so we don't have to
  # duplicate it here to feed to Vips/Pango.
  #
  # irb(main)> font_meta.name.font_name
  # => ["Perfect DOS VGA 437", "\x00P\x00e\x00r\x00f\x00e\x00c\x00t\x00 \x00D\x00O\x00S\x00 \x00V\x00G\x00A\x00 \x004\x003\x007"]
  # irb(main)> font_meta.name.font_family
  # => ["Perfect DOS VGA 437", "\x00P\x00e\x00r\x00f\x00e\x00c\x00t\x00 \x00D\x00O\x00S\x00 \x00V\x00G\x00A\x00 \x004\x003\x007"]
  # irb(main)> font_meta.name.font_subfamily
  # => ["Regular", "\x00R\x00e\x00g\x00u\x00l\x00a\x00r"]
  # irb(main)> font_meta.name.postscript_name
  # => "PerfectDOSVGA437"
  # irb(main)> font_meta.line_gap
  # => 0

  # https://libvips.github.io/libvips/API/current/libvips-create.html#vips-text
  Vips::Image.text(
    # This string must be well-escaped Pango Markup:
    # https://developer.gnome.org/pango/stable/pango-Markup.html
    # However the official function for escaping text is
    # not implemented in Ruby GLib, so we have to do it ourselves.
    to_pango,
    **{
      # String absolute path to TTF
      :fontfile => font_path,
      # It's not enough to just specify the TTF path;
      # we must also specify a font family, subfamily, and size.
      :font => "#{font_name} 16",
      # Space between lines (in Points).
      :spacing => to_ttfunk.line_gap,
      :justify => true,  # Requires libvips 8.8
      :dpi => abstract(:dpi)&.to_i,
    },
  )
end
vips_font() click to toggle source
# File lib/distorted/media_molecule/text.rb, line 138
def vips_font
  # Set the shorthand Symbol key for our chosen font.
  return abstract(:font)&.to_sym || CODEPAGE_FONT[text_file_encoding.code_page].first
end