Class: HexaPDF::Font::TrueTypeWrapper

Inherits:
Object
  • Object
show all
Defined in:
lib/hexapdf/font/true_type_wrapper.rb

Overview

This class wraps a generic TrueType font object and provides the methods needed for working with the font in a PDF context.

TrueType fonts can be represented in two ways in PDF: As a simple font with Subtype TrueType or as a composite font using a Type2 CIDFont. The wrapper only supports the composite font case because:

  • By using a composite font more than 256 characters can be encoded with one font object.

  • Fonts for vertical writing can potentially be used.

  • The PDF specification recommends using a composite font (see PDF2.0 s9.9.1 at the end).

Additionally, TrueType fonts are always embedded.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(document, font, pdf_object: nil, subset: true) ⇒ TrueTypeWrapper

Creates a new object wrapping the TrueType font for the PDF document.

The optional argument pdf_object can be used to set the PDF font object that this wrapper should be associated with. If no object is set, a suitable one is automatically created.

If subset is true, the font is subset.



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 144

def initialize(document, font, pdf_object: nil, subset: true)
  @wrapped_font = font

  @subsetter = (subset ? HexaPDF::Font::TrueType::Subsetter.new(font) : nil)

  @cmap = font[:cmap].preferred_table
  if @cmap.nil?
    raise HexaPDF::Error, "No mapping table for Unicode characters found for TTF " \
      "font #{font.full_name}"
  end
  @pdf_object = pdf_object || create_pdf_object(document)

  @id_to_glyph = {}
  @codepoint_to_glyph = {}
  @encoded_glyphs = {}
  @last_char_code = 0
end

Instance Attribute Details

#pdf_objectObject (readonly)

Returns the PDF object associated with the wrapper.



136
137
138
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 136

def pdf_object
  @pdf_object
end

#wrapped_fontObject (readonly)

Returns the wrapped TrueType font object.



133
134
135
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 133

def wrapped_font
  @wrapped_font
end

Instance Method Details

#bold?Boolean

Returns true if the font contains bold glyphs.

Returns:

  • (Boolean)


173
174
175
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 173

def bold?
  @wrapped_font.weight > 500
end

#custom_glyph(id, string) ⇒ Object

Returns a custom Glyph object which represents the given string via the given glyph id.

This functionality can be used to associate a single glyph id with multiple, different strings for replacement glyph purposes. When used in such a way, the used glyph id is often 0 which represents the missing glyph.



213
214
215
216
217
218
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 213

def custom_glyph(id, string)
  if id < 0 || id >= @wrapped_font[:maxp].num_glyphs
    raise HexaPDF::Error, "Glyph ID #{id} is invalid for font '#{@wrapped_font.full_name}'"
  end
  Glyph.new(self, id, string)
end

#decode_codepoint(codepoint) ⇒ Object

Returns a glyph object for the given Unicode codepoint.

The configuration option ‘font.on_missing_glyph’ is invoked if no glyph for a given codepoint is available.



231
232
233
234
235
236
237
238
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 231

def decode_codepoint(codepoint)
  @codepoint_to_glyph[codepoint] ||=
    if (gid = @cmap[codepoint])
      glyph(gid, +'' << codepoint)
    else
      @pdf_object.document.config['font.on_missing_glyph'].call(+'' << codepoint, self)
    end
end

#decode_utf8(str) ⇒ Object

Returns an array of glyph objects representing the characters in the UTF-8 encoded string.

See #decode_codepoint for details.



223
224
225
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 223

def decode_utf8(str)
  str.codepoints.map! {|c| @codepoint_to_glyph[c] || decode_codepoint(c) }
end

#encode(glyph) ⇒ Object

Encodes the glyph and returns the code string.



241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 241

def encode(glyph)
  (@encoded_glyphs[glyph] ||=
    begin
      raise HexaPDF::MissingGlyphError.new(glyph) if glyph.kind_of?(InvalidGlyph)
      @subsetter.use_glyph(glyph.id) if @subsetter
      @last_char_code += 1
      # Handle codes for ASCII characters \n (10), \r (13), (, ) (40, 41) and \ (92) specially so that
      # they never appear in the output (PDF serialization would need to escape them)
      if @last_char_code == 10 || @last_char_code == 13 || @last_char_code == 40 || @last_char_code == 92
        @last_char_code += (@last_char_code == 40 ? 2 : 1)
      end
      [[@last_char_code].pack('n'), @last_char_code]
    end)[0]
end

#filenameObject

The filename of the wrapped TrueType font object if it was loaded from a file.



188
189
190
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 188

def filename
  wrapped_font.io.path
end

#font_typeObject

Returns the type of the font, i.e. :TrueType.



163
164
165
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 163

def font_type
  :TrueType
end

#glyph(id, str = nil) ⇒ Object

Returns a Glyph object for the given glyph ID and str pair.

The optional argument str should be the string representation of the glyph. It is possible that multiple strings map to the same glyph (e.g. hyphen and soft-hyphen could be represented by the same glyph).

Note: Although this method is public, it should normally not be used by application code!



199
200
201
202
203
204
205
206
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 199

def glyph(id, str = nil)
  @id_to_glyph[[id, str]] ||=
    if id >= 0 && id < @wrapped_font[:maxp].num_glyphs
      Glyph.new(self, id, str || (+'' << (@cmap.gid_to_code(id) || 0xFFFD)))
    else
      @pdf_object.document.config['font.on_missing_glyph'].call("\u{FFFD}", self)
    end
end

#italic?Boolean

Returns true if the font contains glyphs with an incline (italic or slant).

Returns:

  • (Boolean)


178
179
180
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 178

def italic?
  @wrapped_font.italic_angle.to_i != 0
end

#scaling_factorObject

Returns the scaling factor for converting font units into PDF units.



168
169
170
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 168

def scaling_factor
  @scaling_factor ||= 1000.0 / @wrapped_font[:head].units_per_em
end

#subset?Boolean

Returns true if the wrapped TrueType font will be subset.

Returns:

  • (Boolean)


183
184
185
# File 'lib/hexapdf/font/true_type_wrapper.rb', line 183

def subset?
  !@subsetter.nil?
end