class HexaPDF::Layout::Style

Parent

A Style is a container for properties that describe the appearance of text or graphics.

Each property except font has a default value, so only the desired properties need to be changed.

Each property has three associated methods:

property_name

Getter method.

property_name(*args) and property_name=

Setter method.

property_name?

Tester method to see if a value has been set or if the default value has already been used.

Public Class Methods

create(style) → style
create(properties_hash) → style

Creates a Style object based on the style argument and returns it:

  • If style is already a Style object, it is just returned.

  • If style is a hash, a new Style object with the style properties specified by the hash

  • is created.

  • If style is nil, a new Style object with only default values is created.

new(**properties)

Creates a new Style object.

The properties hash may be used to set the initial values of properties by using keys equivalent to the property names.

Example:

Style.new(font_size: 15, text_align: :center, text_valign: center)

Public Instance Methods

align(value = nil)

Specifies the horizontal alignment of a box inside the current region. Defaults to :left.

Possible values:

:left

Align the box to the left side of the current region.

:center

Horizontally center the box in the current region.

:right

Align the box to the right side of the current region.

Examples:

composer.text("Left", border: {width: 1})
draw_current_frame_shape("hp-blue")
composer.text("Center", align: :center, border: {width: 1})
draw_current_frame_shape("hp-orange")
composer.text("Right", align: :right, border: {width: 1})
draw_current_frame_shape("hp-teal")

background_alpha(alpha = nil)

The alpha value applied to the background when it is colored, defaults to 1 (i.e. 100% opaque).

See: HexaPDF::Content::Canvas#opacity

Examples:

composer.text("Some text here", background_color: "red", background_alpha: 0.5)

background_color(color = nil)

The color used for backgrounds, defaults to nil (i.e. no background).

Examples:

composer.text("Some text here", background_color: "lightgrey")

border(value = nil)

The border around the contents, defaults to no border for all four sides.

The value has to be a hash containing any of the keys :width, :color and :style. The width, color and style of the border can be set independently for each side (see Style::Quad#set).

See Border for more details.

Examples:

composer.text("Some text here", border: {
                 width: [6, 3],
                 color: ["green", "blue", "orange"],
                 style: [:solid, :dashed]
              })

calculated_font_size()

The calculated font size, taking superscript and subscript into account.

calculated_strikeout_position()

Returns the correct offset from the baseline for the strikeout line.

calculated_strikeout_thickness()

Returns the correct thickness for the strikeout line.

calculated_text_rise()

The calculated text rise, taking superscript and subscript into account.

calculated_underline_position()

Returns the correct offset from the baseline for the underline.

calculated_underline_thickness()

Returns the correct thickness for the underline.

character_spacing(amount = nil)

The character spacing, defaults to 0 (i.e. no additional character spacing).

See: HexaPDF::Content::Canvas#character_spacing

Examples:

composer.text("More spacing between characters", character_spacing: 1)

clear_cache()

Clears all cached values.

This method needs to be called if the following style properties are changed and values were already cached: font, font_size, character_spacing, word_spacing, horizontal_scaling, ascender, descender.

fill_alpha(alpha = nil)

The alpha value applied to filling operations (e.g. text), defaults to 1 (i.e. 100% opaque).

See: HexaPDF::Content::Canvas#opacity

Examples:

composer.text("This is some semi-transparent text", fill_alpha: 0.5)

fill_color(color = nil)

The color used for filling (e.g. text), defaults to black.

See: HexaPDF::Content::Canvas#fill_color

Examples:

composer.text("This is some red text", fill_color: "red")

fill_horizontal(factor = nil)

If set to a positive number, it specifies that the content of the text item should be repeated and appropriate spacing applied so that the remaining space of the line is completely filled.

If there are multiple text items with this property set for a single line, the remaining space is split between those items using the set factors. For example, if item A has a factor of 1 and item B a factor of 2, the remaining space will be split so that item B will receive twice the space of A.

Notes:

  • This property _must not_ be applied to inline boxes, it only works for text items.

  • If the filling should be done with spaces, the non-breaking space character u{00a0} has to be used.

Examples:

composer.formatted_text(["Left", {text: "\u{00a0}", fill_horizontal: 1},
                         "Right"])
composer.formatted_text(["Typical table of contents entry",
                         {text: ".", fill_horizontal: 1}, "34"])
composer.formatted_text(["Factor 1", {text: "\u{00a0}", fill_horizontal: 1},
                         "Factor 3", {text: "\u{00a0}", fill_horizontal: 3}, "End"])
overlays = [proc {|c, b| c.line(0, b.height / 2.0, b.width, b.height / 2.0).stroke}]
composer.formatted_text([{text: "\u{00a0}", fill_horizontal: 1, overlays: overlays},
                         'Centered',
                         {text: "\u{00a0}", fill_horizontal: 1, overlays: overlays}])

font(name = nil)

The font to be used, must be set to a valid font wrapper object before it can be used.

HexaPDF::Composer handles this property specially in that it resolves a set string or array to a font wrapper object before doing anything else with the style object.

This is the only style property without a default value!

See: HexaPDF::Content::Canvas#font

Examples:

composer.text("Helvetica", font: composer.document.fonts.add("Helvetica"))
composer.text("Courier", font: "Courier")

helvetica_bold = composer.document.fonts.add("Helvetica", variant: :bold)
composer.text("Helvetica Bold", font: helvetica_bold)
composer.text("Courier Bold", font: "Courier bold")
composer.text("Courier Bold also", font: ["Courier", variant: :bold])

font_features(features = nil)

The font features (e.g. kerning, ligatures, …) that should be applied by the shaping engine, defaults to {} (i.e. no font features are applied).

Each feature to be applied is indicated by a key with a truthy value.

See: HexaPDF::Layout::TextShaper#shape_text for available features.

Examples:

composer.style(:base, font: ["Times", custom_encoding: true], font_size: 30)
composer.text("Test flight")
composer.text("Test flight", font_features: {kern: true, liga: true})

font_size(size = nil)

The font size, defaults to 10.

See: HexaPDF::Content::Canvas#font_size

Examples:

composer.text("Default size")
composer.text("Larger size", font_size: 20)

horizontal_scaling(percent = nil)

The horizontal scaling, defaults to 100 (in percent, i.e. normal scaling).

See: HexaPDF::Content::Canvas#horizontal_scaling

Examples:

composer.text("Horizontal scaling", horizontal_scaling: 150)

initialize_copy(other)

Duplicates the complex properties that can be modified, as well as the cache.

Calls superclass method
last_line_gap(enable = false)

Add an appropriately sized gap after the last line of text if enabled, defaults to false.

Examples:

composer.text("This is some longer text that wraps around in two lines.",
              line_spacing: 1.5, last_line_gap: true)
composer.text("There is spacing above this line due to last_line_gap.")

line_height(size = nil)

The font size used for line height calculations, default is nil meaing it defaults to font_size.

This value should never be smaller than the font size since this would lead to overlapping text.

Examples:

composer.text("Line 1")
composer.text("Larger line height", line_height: 30)
composer.text("Line 3")

line_spacing(type = nil, value = nil)
line_spacing(type:, value: 1)

The type of line spacing to be used for text lines, defaults to type :single.

This method can set the line spacing in two ways:

  • Using two positional arguments type and value.

  • Or a hash with the keys type and value.

Note that the last line has no additional spacing after it by default. Set last_line_gap for adding such a spacing.

See LineSpacing for supported types of line spacing.

Examples:

composer.text("This is some longer text that wraps around in two lines.",
              line_spacing: 1.5)
composer.text("This is some longer text that wraps around in two lines.",
              line_spacing: :double)
composer.text("This is some longer text that wraps around in two lines.",
              line_spacing: {type: :proportional, value: 1.2})

margin(value = nil)

The margin around a box, defaults to 0 for all four sides.

See Style::Quad#set for information on how to set the values.

Examples:

composer.text("Some text here", margin: [5, 10], position: :float,
              border: {width: 1})
composer.text("Text starts after floating box and continues below it, " \
              "respecting the margin.", position: :flow)

mask_mode(value = nil)

Specifies how the mask defining the to-be-removed region should be constructed. Defaults to :default.

Possible values:

:default

The actually used value depends on the value of position:

  • For :default the used value is :fill_frame_horizontal.

  • For :float the used value is :box.

  • For :flow the used value is :fill_frame_horizontal.

  • For :absolute the used value is :box.

:none

The mask covers nothing (useful for layering boxes over each other).

Examples:

composer.text('Text on bottom', mask_mode: :none)
composer.text('Text on top', fill_color: 'hp-blue')

:box

The mask covers the box including the margin around the box.

Examples:

composer.text('Box only mask', mask_mode: :box)
draw_current_frame_shape('hp-blue')
composer.text('Text to the right')

:fill_horizontal

The mask covers the box including the margin around the box and the space to the left and right in the current region.

Examples:

composer.text('Standard, whole horizontal space')
draw_current_frame_shape('hp-blue')
composer.text('Text underneath')

:fill_frame_horizontal

The mask covers the box including the margin around the box, the space to the left and right in the frame and the space to the top of the current region.

Examples:

composer.frame.remove_area(Geom2D::Rectangle(100, 50, 10, 50))
composer.text('Mask covers frame horizontally', mask_mode: :fill_frame_horizontal)
draw_current_frame_shape('hp-blue')
composer.text('Text underneath')

:fill_vertical

The mask covers the box including the margin around the box and the space to the top and bottom in the current region.

Examples:

composer.text('Mask covers vertical space', mask_mode: :fill_vertical)
draw_current_frame_shape('hp-blue')
composer.text('Text to the right')

:fill

The mask covers the current region completely.

Examples:

composer.text('Mask covers everything', mask_mode: :fill)
composer.text('On the next page')

overflow(mode = nil)

Specifies how overflowing boxes (e.g. the text of a box or the children of a container) with a given initial height should be handled:

Possible values:

:error

An error is raised (default).

:truncate

Truncates the overflowing parts.

Examples:

composer.text("This is some longer text that does appear in two lines.")
composer.text("This is some longer text that does not appear in two lines.",
              height: 15, overflow: :truncate)

overlays(layers = nil)

A Style::Layers object containing all the layers that should be drawn over the box; defaults to no layers being drawn.

The layers argument needs to be an array of layer objects. To define a layer either use a callable object taking the canvas and the box as arguments; or use a pre-defined layer using an array of the form [:layer_name, **options]. See Style::Layers for details.

Examples:

composer.text("Some text here", overlays: [
  lambda do |canvas, box|
    canvas.stroke_color("red").opacity(stroke_alpha: 0.5).
      line_width(5).line(0, 0, box.width, box.height).stroke
  end,
  [:link, uri: "https://hexapdf.gettalong.org"]
])

padding(value = nil)

The padding between the border and the contents, defaults to 0 for all four sides.

See Style::Quad#set for information on how to set the values.

Examples:

composer.text("Some text here", padding: 10, border: {width: 1})

position(value = nil)

Specifies how a box should be positioned in a frame. Defaults to :default.

The properties align and valign provide alignment information while mask_mode defines how the to-be-removed region should be constructed.

Possible values:

:default

Position the box at the current position. The exact horizontal and vertical position inside the current region is given via the align and valign style properties.

Examples:

composer.box(:base, width: 40, height: 20,
             style: {align: :right, border: {width: 1}})
composer.box(:base, width: 40, height: 20,
             style: {align: :center, valign: :center, border: {width: 1}})

:float

This is the same as :default except that the used value for mask_mode when it is set to :default is :box instead of :fill_frame_horizontal.

Examples:

composer.box(:base, width: 40, height: 20,
             style: {position: :float, border: {width: 1}})
composer.box(:base, width: 40, height: 20,
             style: {position: :float, border: {color: "hp-blue", width: 1}})

:flow

Flows the content of the box inside the frame around objects.

A box needs to indicate whether it supports this value by implementing the supports_position_flow? method and returning true if it does or false if it doesn’t. If a box doesn’t support this value, it is positioned as if the value :default was set.

Notes:

  • The properties align and valign are not used with this value.

  • The rectangular area of the box is the rectangle containing all the flowed content. That rectangle is used for drawing the border, background and so on.

Examples:

composer.box(:base, width: 40, height: 20,
             style: {position: :float, border: {width: 1}})
composer.lorem_ipsum(position: :flow)

[x, y]

Position the box with the bottom-left corner at the given absolute position relative to the bottom-left corner of the frame.

Examples:

composer.text('Absolute', position: [50, 50], border: {width: 1})
draw_current_frame_shape("red")

scaled_character_spacing()

The character spacing scaled appropriately.

scaled_font_ascender()

The ascender of the font scaled appropriately.

scaled_font_descender()

The descender of the font scaled appropriately.

scaled_font_size()

The font size scaled appropriately.

scaled_horizontal_scaling()

The horizontal scaling scaled appropriately.

scaled_item_width(item)

Returns the width of the item scaled appropriately (by taking font size, characters spacing, word spacing and horizontal scaling into account).

The item may be a (singleton) glyph object or an integer/float, i.e. items that can appear inside a TextFragment.

scaled_word_spacing()

The word spacing scaled appropriately.

scaled_y_max()

The maximum y-coordinate, calculated using the scaled ascender of the font and the line height or font size.

scaled_y_min()

The minimum y-coordinate, calculated using the scaled descender of the font and the line height or font size.

strikeout(enable = false)

Renders a line through the text; defaults to false.

Examples:

composer.text("Strikeout text", strikeout: true)

stroke_alpha(alpha = nil)

The alpha value applied to stroking operations (e.g. text outlines), defaults to 1 (i.e. 100% opaque).

See: HexaPDF::Content::Canvas#opacity

Examples:

composer.text("Stroked text", font_size: 40, stroke_alpha: 0.5,
              text_rendering_mode: :stroke)

stroke_cap_style(style = nil)

The line cap style used for stroking operations (e.g. text outlines), defaults to :butt. The returned values is always a normalized line cap style value.

See: HexaPDF::Content::Canvas#line_cap_style

Examples:

composer.text("Stroked text", font_size: 40, stroke_cap_style: :round,
              text_rendering_mode: :stroke)

stroke_color(color = nil)

The color used for stroking (e.g. text outlines), defaults to black.

See: HexaPDF::Content::Canvas#stroke_color

Examples:

composer.text("Stroked text", font_size: 40, stroke_color: "red",
              text_rendering_mode: :stroke)

stroke_dash_pattern(pattern = nil)

The line dash pattern used for stroking operations (e.g. text outlines), defaults to a solid line.

See: HexaPDF::Content::Canvas#line_dash_pattern

Examples:

composer.text("Stroked text", font_size: 40, stroke_dash_pattern: [4, 2],
              text_rendering_mode: :stroke)

stroke_join_style(style = nil)

The line join style used for stroking operations (e.g. text outlines), defaults to :miter. The returned values is always a normalized line joine style value.

See: HexaPDF::Content::Canvas#line_join_style

Examples:

composer.text("Stroked text", font_size: 40, stroke_join_style: :bevel,
              text_rendering_mode: :stroke)

stroke_miter_limit(limit = nil)

The miter limit used for stroking operations (e.g. text outlines) when stroke_join_style is :miter, defaults to 10.0.

See: HexaPDF::Content::Canvas#miter_limit

Examples:

composer.text("Stroked text", font_size: 40, stroke_join_style: :bevel,
              stroke_miter_limit: 1, text_rendering_mode: :stroke)

stroke_width(width = nil)

The line width used for stroking operations (e.g. text outlines), defaults to 1.

See: HexaPDF::Content::Canvas#line_width

Examples:

composer.text("Stroked text", font_size: 40, stroke_width: 2,
              text_rendering_mode: :stroke)

subscript(enable = false)

Render the text as subscript, i.e. lower and in a smaller font size; defaults to false.

If superscript is set, it will be deactivated.

Examples:

composer.formatted_text(["Some ", {text: "subscript text", subscript: true}])

superscript(enable = false)

Render the text as superscript, i.e. higher and in a smaller font size; defaults to false.

If subscript is set, it will be deactivated.

Examples:

composer.formatted_text(["Some ", {text: "superscript text", superscript: true}])

text_align(direction = nil)

The horizontal alignment of text, defaults to :left.

Possible values:

:left

Left-align the text, i.e. the right side is rugged.

:center

Center the text horizontally.

:right

Right-align the text, i.e. the left side is rugged.

:justify

Justify the text, except for those lines that end in a hard line break.

Examples:

text = "Lorem ipsum dolor sit amet. " * 2
composer.style(:base, border: {width: 1})
composer.text(text, text_align: :left)
composer.text(text, text_align: :center)
composer.text(text, text_align: :right)
composer.text(text, text_align: :justify)

text_indent(amount = nil)

The indentation to be used for the first line of a sequence of text lines, defaults to 0.

Examples:

composer.text("This is some longer text that wraps around in two lines.",
              text_indent: 10)

text_line_wrapping_algorithm(algorithm = nil) {|items, width_block| block }

The line wrapping algorithm that should be used, defaults to TextLayouter::SimpleLineWrapping.

When setting the algorithm, either an object that responds to call or a block can be used. See TextLayouter::SimpleLineWrapping#call for the needed method signature.

text_rendering_mode(mode = nil)

The text rendering mode, i.e. whether text should be filled, stroked, clipped, invisible or a combination thereof, defaults to :fill. The returned value is always a normalized text rendering mode value.

See: HexaPDF::Content::Canvas#text_rendering_mode

Examples:

composer.text("Test flight", font_size: 40, text_rendering_mode: :stroke)

text_rise(amount = nil)

The text rise, i.e. the vertical offset from the baseline, defaults to 0.

See: HexaPDF::Content::Canvas#text_rise

Examples:

composer.formatted_text(["Normal", {text: "Up in the air", text_rise: 5}])

text_segmentation_algorithm(algorithm = nil) {|items| block }

The algorithm to use for text segmentation purposes, defaults to TextLayouter::SimpleTextSegmentation.

When setting the algorithm, either an object that responds to call(items) or a block can be used.

text_valign(direction = nil)

The vertical alignment of items (normally text) inside a text box, defaults to :top.

For :center and :bottom alignment the box will fill the whole available height. If this is not wanted, an explicit height will need to be set for the box.

This property is ignored when using position :flow for a text box.

Possible values:

:top

Vertically align the items to the top of the box.

:center

Vertically align the items in the center of the box.

:bottom

Vertically align the items to the bottom of the box.

Examples:

composer.style(:base, border: {width: 1})
composer.text("Top aligned", height: 20, text_valign: :top)
composer.text("Center aligned", height: 20, text_valign: :center)
composer.text("Bottom aligned", text_valign: :bottom)

underlays(layers = nil)

A Style::Layers object containing all the layers that should be drawn under the box; defaults to no layers being drawn.

The layers argument needs to be an array of layer objects. To define a layer either use a callable object taking the canvas and the box as arguments; or use a pre-defined layer using an array of the form [:layer_name, **options]. See Style::Layers for details.

Examples:

composer.text("Some text here", underlays: [
  lambda do |canvas, box|
    canvas.stroke_color("red").opacity(stroke_alpha: 0.5).
      line_width(5).line(0, 0, box.width, box.height).stroke
  end,
  [:link, uri: "https://hexapdf.gettalong.org"]
])

underline(enable = false)

Renders a line underneath the text; defaults to false.

Examples:

composer.text("Underlined text", underline: true)

update(**properties) → style

Updates the style’s properties using the key-value pairs specified by the properties hash.

valign(value = nil)

Specifies the vertical alignment of a box inside the current region. Defaults to :top.

Possible values:

:top

Align the box to the top side of the current region.

:center

Vertically center the box in the current region.

:bottom

Align the box to the bottom side of the current region.

Examples:

composer.text("Top", mask_mode: :fill_vertical, border: {width: 1})
composer.text("Center", valign: :center, mask_mode: :fill_vertical, border: {width: 1})
composer.text("Bottom", valign: :bottom, border: {width: 1})

word_spacing(amount = nil)

The word spacing, defaults to 0 (i.e. no additional word spacing).

See: HexaPDF::Content::Canvas#word_spacing

Examples:

composer.text("More word spacing", word_spacing: 20)