Class: Okab::EmbeddedFont

Inherits:
Object
  • Object
show all
Defined in:
lib/okab/font.rb,
sig/okab.rbs

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(document, font, subset: true) ⇒ EmbeddedFont

Returns a new instance of EmbeddedFont.

Parameters:

  • document (Document)
  • font (Font)
  • subset: (Boolean) (defaults to: true)


29
30
31
32
# File 'lib/okab/font.rb', line 29

def initialize(document, font, subset: true)
  @document, @font, @subset = document, font, !!subset
  @cid_by_character, @characters = {}, {0 => ["\u0000", 0]}
end

Instance Attribute Details

#document ⇒ Document (readonly)

Returns the value of attribute document.

Returns:



27
28
29
# File 'lib/okab/font.rb', line 27

def document
  @document
end

#font ⇒ Font (readonly)

Returns the value of attribute font.

Returns:



27
28
29
# File 'lib/okab/font.rb', line 27

def font
  @font
end

#subset ⇒ Boolean (readonly)

Returns the value of attribute subset.

Returns:

  • (Boolean)


27
28
29
# File 'lib/okab/font.rb', line 27

def subset
  @subset
end

Instance Method Details

#base_name(data) ⇒ String

Parameters:

  • data (String)

Returns:

  • (String)


98
99
100
101
102
# File 'lib/okab/font.rb', line 98

def base_name(data)
  prefix = Digest::SHA256.hexdigest(data).upcase[0, 6].tr("0-9", "A-J")
  family = face.family.to_s.gsub(/[^A-Za-z0-9]/, "")
  "#{prefix}+#{family.empty? ? 'EmbeddedFont' : family}"
end

#characters ⇒ Hash[Integer, [String, Integer]]

Returns:

  • (Hash[Integer, [String, Integer]])


96
# File 'lib/okab/font.rb', line 96

def characters = @characters

#encode(string) ⇒ String

Parameters:

  • string (String)

Returns:

  • (String)


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/okab/font.rb', line 37

def encode(string)
  codepoints = string.codepoints
  cids = []
  codepoints.each_with_index do |codepoint, index|
    next if variation_selector?(codepoint)

    selector = variation_selector?(codepoints[index + 1]) ? codepoints[index + 1] : nil
    glyph = face.glyph_id(codepoint, variation_selector: selector)
    glyph = face.glyph_id(codepoint) if glyph.zero? && selector
    character = [codepoint, *([selector] if selector)].pack("U*")
    key = [character, glyph]
    cid = @cid_by_character[key]
    unless cid
      cid = @characters.length
      raise ArgumentError, "a PDF font cannot encode more than 65,535 characters" if cid > 65_535

      @cid_by_character[key] = cid
      @characters[cid] = [character, glyph]
    end
    cids << cid
  end
  cids.pack("n*")
end

#encode_glyph(glyph, unicode:) ⇒ String

Preserve glyph IDs produced by an external shaper instead of shaping the source text a second time when a vector display list is embedded.

Parameters:

  • glyph (Integer)
  • unicode: (String)

Returns:

  • (String)

Raises:

  • (ArgumentError)


63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/okab/font.rb', line 63

def encode_glyph(glyph, unicode:)
  raise ArgumentError, "invalid glyph ID" unless glyph.is_a?(Integer) && glyph.between?(0, face.glyph_count - 1)
  raise ArgumentError, "glyph text must be valid UTF-8" unless unicode.is_a?(String) && unicode.encoding == Encoding::UTF_8 && unicode.valid_encoding?
  key = [unicode, glyph]
  cid = @cid_by_character[key]
  unless cid
    cid = @characters.length
    raise ArgumentError, "a PDF font cannot encode more than 65,535 characters" if cid > 65_535
    @cid_by_character[key] = cid
    @characters[cid] = [unicode.empty? ? "\uFFFD" : unicode, glyph]
  end
  [cid].pack("n")
end

#face ⇒ Alhena::Font

Returns:

  • (Alhena::Font)


34
# File 'lib/okab/font.rb', line 34

def face = @font.face

#glyph_ids ⇒ Array[Integer]

Returns:

  • (Array[Integer])


77
78
79
# File 'lib/okab/font.rb', line 77

def glyph_ids
  @characters.values.map(&:last).uniq
end

#measure(text, size:) ⇒ Float

Parameters:

  • text (String)
  • size: (Numeric)

Returns:

  • (Float)


35
# File 'lib/okab/font.rb', line 35

def measure(text, size:) = @font.measure(text, size: size)

#subset_font ⇒ [String, Alhena::Font, Hash[Integer, Integer], bool]

Returns:

  • ([String, Alhena::Font, Hash[Integer, Integer], bool])


81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/okab/font.rb', line 81

def subset_font
  if face.cff?
    raise Alhena::UnsupportedFont, "CID CFF embedding requires subset: true" unless @subset

    data = Alhena::Subset.build_cid(face, @characters.values.map(&:last))
    return [data, face, {}, true]
  end

  selected = @subset ? glyph_ids : (0...face.glyph_count).to_a
  data = Alhena::Subset.build(face, selected)
  subset_face = Alhena::Font.new(data)
  old_ids = Alhena::Subset.closure(face, [0, *selected].uniq)
  [data, subset_face, old_ids.each_with_index.to_h, false]
end