Class: Prawn::Font::TTF

Inherits:
Prawn::Font show all
Defined in:
lib/prawn/font/ttf.rb

Direct Known Subclasses

DFont

Instance Attribute Summary collapse

Attributes inherited from Prawn::Font

#family, #name, #options

Instance Method Summary collapse

Methods inherited from Prawn::Font

#add_to_current_page, #ascender, #descender, #height, #height_at, #identifier_for, #inspect, #line_gap, load, #normalize_encoding!

Constructor Details

#initialize(document, name, options = {}) ⇒ TTF

Returns a new instance of TTF.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/prawn/font/ttf.rb', line 22

def initialize(document, name, options={})
  super

  @ttf              = read_ttf_file
  @subsets          = TTFunk::SubsetCollection.new(@ttf)

  @attributes       = {}
  @bounding_boxes   = {} 
  @char_widths      = {}   
  @has_kerning_data = @ttf.kerning.exists? && @ttf.kerning.tables.any?

  @ascender         = Integer(@ttf.ascent * scale_factor)
  @descender        = Integer(@ttf.descent * scale_factor)
  @line_gap         = Integer(@ttf.line_gap * scale_factor)
end

Instance Attribute Details

#subsetsObject (readonly)

Returns the value of attribute subsets.



16
17
18
# File 'lib/prawn/font/ttf.rb', line 16

def subsets
  @subsets
end

#ttfObject (readonly)

Returns the value of attribute ttf.



16
17
18
# File 'lib/prawn/font/ttf.rb', line 16

def ttf
  @ttf
end

Instance Method Details

#basenameObject



106
107
108
# File 'lib/prawn/font/ttf.rb', line 106

def basename
  @basename ||= @ttf.name.postscript_name
end

#bboxObject

The font bbox, as an array of integers



58
59
60
# File 'lib/prawn/font/ttf.rb', line 58

def bbox
  @bbox ||= @ttf.bbox.map { |i| Integer(i * scale_factor) }
end

#cap_heightObject



126
127
128
129
130
131
# File 'lib/prawn/font/ttf.rb', line 126

def cap_height
  @cap_height ||= begin
    height = @ttf.os2.exists? && @ttf.os2.cap_height || 0
    height == 0 ? ascender : height
  end
end

#character_count(str) ⇒ Object

Returns the number of characters in str (a UTF-8-encoded string).



195
196
197
198
199
200
201
# File 'lib/prawn/font/ttf.rb', line 195

def character_count(str)
  if str.respond_to?(:encode)
    str.length
  else
    str.unpack("U*").length
  end
end

#compute_width_of(string, options = {}) ⇒ Object

NOTE: string must be UTF8-encoded.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/prawn/font/ttf.rb', line 39

def compute_width_of(string, options={}) #:nodoc:
  scale = (options[:size] || size) / 1000.0
  if options[:kerning]
    kern(string).inject(0) do |s,r|
      if r.is_a?(Numeric)
        s - r
      else 
        r.inject(s) { |s2, u| s2 + character_width_by_code(u) }
      end
    end * scale
  else
    string.unpack("U*").inject(0) do |s,r|
      s + character_width_by_code(r)
    end * scale
  end
end

#encode_text(text, options = {}) ⇒ Object

Perform any changes to the string that need to happen before it is rendered to the canvas. Returns an array of subset “chunks”, where the even-numbered indices are the font subset number, and the following entry element is either a string or an array (for kerned text).

The text parameter must be UTF8-encoded.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/prawn/font/ttf.rb', line 75

def encode_text(text,options={})
  text = text.chomp

  if options[:kerning]
    last_subset = nil
    kern(text).inject([]) do |result, element| 
      if element.is_a?(Numeric)
        result.last[1] = [result.last[1]] unless result.last[1].is_a?(Array)
        result.last[1] << element
        result
      else
        encoded = @subsets.encode(element)

        if encoded.first[0] == last_subset
          result.last[1] << encoded.first[1]
          encoded.shift
        end

        if encoded.any?
          last_subset = encoded.last[0]
          result + encoded
        else
          result
        end
      end
    end
  else
    @subsets.encode(text.unpack("U*"))
  end
end

#family_classObject



139
140
141
# File 'lib/prawn/font/ttf.rb', line 139

def family_class
  @family_class ||= (@ttf.os2.exists? && @ttf.os2.family_class || 0) >> 8
end

#glyph_present?(char) ⇒ Boolean

Returns:

  • (Boolean)


188
189
190
191
# File 'lib/prawn/font/ttf.rb', line 188

def glyph_present?(char)
  code = char.unpack("U*").first
  cmap[code] > 0
end

#has_kerning_data?Boolean

Returns true if the font has kerning data, false otherwise

Returns:

  • (Boolean)


63
64
65
# File 'lib/prawn/font/ttf.rb', line 63

def has_kerning_data?
  @has_kerning_data 
end

#italic_angleObject



115
116
117
118
119
120
121
122
123
124
# File 'lib/prawn/font/ttf.rb', line 115

def italic_angle
  @italic_angle ||= if @ttf.postscript.exists?
    raw = @ttf.postscript.italic_angle
    hi, low = raw >> 16, raw & 0xFF
    hi = -((hi ^ 0xFFFF) + 1) if hi & 0x8000 != 0
    "#{hi}.#{low}".to_f
  else
    0
  end
end

#normalize_encoding(text) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/prawn/font/ttf.rb', line 162

def normalize_encoding(text)
  if text.respond_to?(:encode)
    # if we're running under a M17n aware VM, ensure the string provided is
    # UTF-8 (by converting it if necessary)
    begin
      text.encode("UTF-8")
    rescue
      raise Prawn::Errors::IncompatibleStringEncoding, "Encoding " +
      "#{text.encoding} can not be transparently converted to UTF-8. " +
      "Please ensure the encoding of the string you are attempting " +
      "to use is set correctly"
    end
  else
    # on a non M17N aware VM, use unpack as a hackish way to verify the
    # string is valid utf-8. I thought it was better than loading iconv
    # though.
    begin
      text.unpack("U*")
      return text.dup
    rescue
      raise Prawn::Errors::IncompatibleStringEncoding, "The string you " +
        "are attempting to render is not encoded in valid UTF-8."
    end
  end
end

#pdf_flagsObject



151
152
153
154
155
156
157
158
159
160
# File 'lib/prawn/font/ttf.rb', line 151

def pdf_flags
  @flags ||= begin
    flags = 0
    flags |= 0x0001 if @ttf.postscript.fixed_pitch?
    flags |= 0x0002 if serif?
    flags |= 0x0008 if script?
    flags |= 0x0040 if italic_angle != 0
    flags |= 0x0004 # assume the font contains at least some non-latin characters
  end
end

#script?Boolean

Returns:

  • (Boolean)


147
148
149
# File 'lib/prawn/font/ttf.rb', line 147

def script?
  @script ||= family_class == 10
end

#serif?Boolean

Returns:

  • (Boolean)


143
144
145
# File 'lib/prawn/font/ttf.rb', line 143

def serif?
  @serif ||= [1,2,3,4,5,7].include?(family_class)
end

#stemVObject

not sure how to compute this for true-type fonts…



111
112
113
# File 'lib/prawn/font/ttf.rb', line 111

def stemV
  0
end

#unicode?Boolean

Returns:

  • (Boolean)


18
19
20
# File 'lib/prawn/font/ttf.rb', line 18

def unicode?
  true
end

#x_heightObject



133
134
135
136
137
# File 'lib/prawn/font/ttf.rb', line 133

def x_height
  # FIXME: seems like if os2 table doesn't exist, we could
  # just find the height of the lower-case 'x' glyph?
  @ttf.os2.exists? && @ttf.os2.x_height || 0
end