Class: HexaPDF::Layout::TextFragment

Inherits:
Object
  • Object
show all
Defined in:
lib/hexapdf/layout/text_fragment.rb

Overview

A TextFragment describes an optionally kerned piece of text that shares the same font, font size and other properties.

Its items are either glyph objects of the font or numeric values describing kerning information. All returned measurement values are in text space units. If the items or the style are changed, the #clear_cache has to be called. Otherwise the measurements may not be correct!

The items of a text fragment may be frozen to indicate that the fragment is potentially used multiple times.

The rectangle with the lower-left corner (#x_min, #y_min) and the upper right corner (#x_max, #y_max) describes the minimum bounding box of the whole text fragment and is usually not equal to the box (0, 0)-(#width, #height).

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(items:, style: Style.new) ⇒ TextFragment

Creates a new TextFragment object with the given items and style.



78
79
80
81
# File 'lib/hexapdf/layout/text_fragment.rb', line 78

def initialize(items:, style: Style.new)
  @items = items || []
  @style = style
end

Instance Attribute Details

#itemsObject

The items (glyphs and kerning values) of the text fragment.



69
70
71
# File 'lib/hexapdf/layout/text_fragment.rb', line 69

def items
  @items
end

#styleObject (readonly)

The style to be applied.

Only the following properties are used: Style#font, Style#font_size, Style#horizontal_scaling, Style#character_spacing, Style#word_spacing and Style#text_rise.



75
76
77
# File 'lib/hexapdf/layout/text_fragment.rb', line 75

def style
  @style
end

Class Method Details

.create(text, font:, **options) ⇒ Object

Creates a new TextFragment object for the given text, shapes it and returns it.

The style of the text fragment can be specified using additional options, of which font is mandatory.



63
64
65
66
# File 'lib/hexapdf/layout/text_fragment.rb', line 63

def self.create(text, font:, **options)
  fragment = new(items: font.decode_utf8(text), style: Style.new(font: font, **options))
  TextShaper.new.shape_text(fragment)
end

Instance Method Details

#clear_cacheObject

Clears all cached values.

This method needs to be called if the fragment’s items or attributes are changed!



159
160
161
162
# File 'lib/hexapdf/layout/text_fragment.rb', line 159

def clear_cache
  @x_min = @x_max = @y_min = @y_max = @exact_y_min = @exact_y_max = @width = @height = nil
  self
end

#draw(canvas, x, y) ⇒ Object

Draws the text onto the canvas at the given position.

Before the text is drawn using HexaPDF::Content;:Canvas#show_glyphs, the text properties mentioned in the description of #style are set.



87
88
89
90
91
92
93
94
95
# File 'lib/hexapdf/layout/text_fragment.rb', line 87

def draw(canvas, x, y)
  canvas.move_text_cursor(offset: [x, y])
  canvas.font(style.font, size: style.font_size).
    horizontal_scaling(style.horizontal_scaling).
    character_spacing(style.character_spacing).
    word_spacing(style.word_spacing).
    text_rise(style.text_rise)
  canvas.show_glyphs_only(items)
end

#exact_y_maxObject

The maximum y-coordinate of any item.



124
125
126
127
# File 'lib/hexapdf/layout/text_fragment.rb', line 124

def exact_y_max
  @exact_y_max ||= (@items.max_by(&:y_max)&.y_max || 0) * style.font_size / 1000.0 +
    style.text_rise
end

#exact_y_minObject

The minimum y-coordinate of any item.



118
119
120
121
# File 'lib/hexapdf/layout/text_fragment.rb', line 118

def exact_y_min
  @exact_y_min ||= (@items.min_by(&:y_min)&.y_min || 0) * style.font_size / 1000.0 +
    style.text_rise
end

#heightObject

The height of the text fragment.

It is calculated as the difference of the maximum of the y_max values and the minimum of the y_min values of the items. However, the text rise value is also taken into account so that the baseline is always inside the bounds. For example, if a large negative text rise value is used, the baseline will be equal to the top boundary; if a large positive value is used, it will be equal to the bottom boundary.



145
146
147
# File 'lib/hexapdf/layout/text_fragment.rb', line 145

def height
  @height ||= [y_max, 0].max - [y_min, 0].min
end

#inspectObject

:nodoc:



165
166
167
# File 'lib/hexapdf/layout/text_fragment.rb', line 165

def inspect
  "#<#{self.class.name} #{items.inspect}>"
end

#valignObject

Returns the vertical alignment inside a line which is always :text for text fragments.

See LineFragment for details.



152
153
154
# File 'lib/hexapdf/layout/text_fragment.rb', line 152

def valign
  :text
end

#widthObject

The width of the text fragment.

It is the sum of the widths of its items and is calculated by using the algorithm presented in PDF1.7 s9.4.4. By using kerning values as the first and/or last items, the text contained in the fragment may spill over the left and/or right boundary.



134
135
136
# File 'lib/hexapdf/layout/text_fragment.rb', line 134

def width
  @width ||= @items.sum {|item| style.scaled_item_width(item)}
end

#x_maxObject

The maximum x-coordinate of the last glyph.



103
104
105
# File 'lib/hexapdf/layout/text_fragment.rb', line 103

def x_max
  @x_max ||= calculate_x_max
end

#x_minObject

The minimum x-coordinate of the first glyph.



98
99
100
# File 'lib/hexapdf/layout/text_fragment.rb', line 98

def x_min
  @x_min ||= calculate_x_min
end

#y_maxObject

The maximum y-coordinate, calculated using the scaled ascender of the font.



113
114
115
# File 'lib/hexapdf/layout/text_fragment.rb', line 113

def y_max
  @y_max ||= style.scaled_font_ascender + style.text_rise
end

#y_minObject

The minimum y-coordinate, calculated using the scaled descender of the font.



108
109
110
# File 'lib/hexapdf/layout/text_fragment.rb', line 108

def y_min
  @y_min ||= style.scaled_font_descender + style.text_rise
end