| Title: | Bindings to the 'HarfBuzz' and 'Fribidi' Libraries for Text Shaping |
|---|---|
| Description: | Provides access to the text shaping functionality in the 'HarfBuzz' library and the bidirectional algorithm in the 'Fribidi' library. 'textshaping' is a low-level utility package mainly for graphic devices that expands upon the font tool-set provided by the 'systemfonts' package. |
| Authors: | Thomas Lin Pedersen [cre, aut] (ORCID: <https://orcid.org/0000-0002-5147-4711>), Posit Software, PBC [cph, fnd] (ROR: <https://ror.org/03wc8by49>) |
| Maintainer: | Thomas Lin Pedersen <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.0.5.9000 |
| Built: | 2026-06-05 06:16:57 UTC |
| Source: | https://github.com/r-lib/textshaping |
This is a simply functions that returns the available OpenType feature tags
for one or more fonts. See font_feature() for
more information on how to use the different feature with a font.
get_font_features( family = "", italic = FALSE, bold = FALSE, path = NULL, index = 0 )get_font_features( family = "", italic = FALSE, bold = FALSE, path = NULL, index = 0 )
family |
The name of the font families to match |
italic |
logical indicating the font slant |
bold |
|
path, index
|
path and index of a font file to circumvent lookup based on family and style |
A list with an element for each of the input fonts containing the supported feature tags for that font.
# Select a random font on the system sys_fonts <- systemfonts::system_fonts() random_font <- sys_fonts$family[sample(nrow(sys_fonts), 1)] # Get the features get_font_features(random_font)# Select a random font on the system sys_fonts <- systemfonts::system_fonts() random_font <- sys_fonts$family[sample(nrow(sys_fonts), 1)] # Get the features get_font_features(random_font)
Textshaping exists partly to allow all the various scripts that exists in the world to be used in R graphics. This function returns gibberish filler text (lorem ipsum text) in various scripts for testing purpose. Some of these are transliterations of the original lorem ipsum text while others are based an a distribution model.
lorem_text( script = c("latin", "chinese", "arabic", "devanagari", "cyrillic", "kana", "hangul", "greek", "hebrew", "armenian", "georgian"), n = 1 ) lorem_bidi( ltr = c("latin", "chinese", "devanagari", "cyrillic", "kana", "hangul", "greek", "armenian", "georgian"), rtl = c("arabic", "hebrew"), ltr_prop = 0.9, n = 1 )lorem_text( script = c("latin", "chinese", "arabic", "devanagari", "cyrillic", "kana", "hangul", "greek", "hebrew", "armenian", "georgian"), n = 1 ) lorem_bidi( ltr = c("latin", "chinese", "devanagari", "cyrillic", "kana", "hangul", "greek", "armenian", "georgian"), rtl = c("arabic", "hebrew"), ltr_prop = 0.9, n = 1 )
script |
A string giving the script to fetch gibberish for |
n |
The number of paragraphs to fetch. Each paragraph will be its own element in the returned character vector. |
ltr, rtl
|
scripts to use for left-to-right and right-to-left text |
ltr_prop |
The approximate proportion of left-to-right text in the final string |
a character vector of length n
https://generator.lorem-ipsum.info
# Defaults to standard lorem ipsum lorem_text() # Get two paragraphs of hangul (Korean) lorem_text("hangul", 2) # Get gibberish bi-directional text lorem_bidi()# Defaults to standard lorem ipsum lorem_text() # Get two paragraphs of hangul (Korean) lorem_text("hangul", 2) # Get gibberish bi-directional text lorem_bidi()
This function creates a grid grob that renders a math expression.
The grob can be used with standard grid functions like grid::grid.draw(),
combined with other grobs using grid::grobTree(), or used in ggplot2
annotations. Like the standard grid grobs, math_grob() creates a grob
object to pass around while grid.math() both creates the grob and render it
in one pass.
math_grob( math, x = 0.5, y = 0.5, hjust = "left", vjust = "baseline", default.units = "npc", name = NULL, gp = NULL, vp = NULL, family = "math", size = 12, res = 72, inline = TRUE, path = NULL, index = 0, color = "black" ) grid.math( math, x = 0.5, y = 0.5, hjust = "left", vjust = "baseline", default.units = "npc", name = NULL, gp = NULL, vp = NULL, family = "math", size = 12, res = 72, inline = TRUE, path = NULL, index = 0, color = "black", draw = TRUE )math_grob( math, x = 0.5, y = 0.5, hjust = "left", vjust = "baseline", default.units = "npc", name = NULL, gp = NULL, vp = NULL, family = "math", size = 12, res = 72, inline = TRUE, path = NULL, index = 0, color = "black" ) grid.math( math, x = 0.5, y = 0.5, hjust = "left", vjust = "baseline", default.units = "npc", name = NULL, gp = NULL, vp = NULL, family = "math", size = 12, res = 72, inline = TRUE, path = NULL, index = 0, color = "black", draw = TRUE )
math |
A single math expression string. Use raw strings for
cleaner syntax, e.g., |
x, y
|
The position of the grob. Can be a unit object or a numeric value (interpreted as npc units). |
hjust |
Horizontal justification. Either a numeric value (0 = left,
0.5 = center, 1 = right) or a character string ( |
vjust |
Vertical justification. Either a numeric value (0 = bottom,
0.5 = center, 1 = top) or a character string ( |
default.units |
A string indicating the default units to use if
|
name |
A character identifier for the grob. |
gp |
A |
vp |
A |
family |
Font family name. For best results, use a font with an OpenType MATH table such as "STIX Two Math", "Latin Modern Math", "Cambria Math", or "Libertinus Math". Fonts without a MATH table will use fallback positioning constants based on TeX defaults, which produces reasonable but less precise results. Default uses the system's default math font. |
size |
The size in points to use for the font |
res |
The resolution to use when doing the shaping. Should optimally match the resolution used when rendering the glyphs. |
inline |
Logical. If |
path, index
|
path an index of a font file to circumvent lookup based on family and style |
color |
Base color for the equation (default "black"). Individual
elements can override this using |
draw |
Should the created grob be rendered |
A grob object of class "math_grob".
# Create a math grob (baseline at y=0.5) g <- math_grob(r"(\frac{a}{b})", x = 0.5, y = 0.5) # Draw it (requires a device that supports glyph rendering) try(grid::grid.draw(g)) # Center the expression in the viewport g <- math_grob(r"(E = mc^2)", x = 0.5, y = 0.5, hjust = "center", vjust = "center") try(grid::grid.draw(g)) # Combine with other grobs tree <- grid::grobTree( grid::rectGrob(gp = grid::gpar(fill = "lightblue")), math_grob(r"(E = mc^2)", x = 0.5, y = 0.5, hjust = "center", vjust = "center") ) try(grid::grid.draw(tree))# Create a math grob (baseline at y=0.5) g <- math_grob(r"(\frac{a}{b})", x = 0.5, y = 0.5) # Draw it (requires a device that supports glyph rendering) try(grid::grid.draw(g)) # Center the expression in the viewport g <- math_grob(r"(E = mc^2)", x = 0.5, y = 0.5, hjust = "center", vjust = "center") try(grid::grid.draw(g)) # Combine with other grobs tree <- grid::grobTree( grid::rectGrob(gp = grid::gpar(fill = "lightblue")), math_grob(r"(E = mc^2)", x = 0.5, y = 0.5, hjust = "center", vjust = "center") ) try(grid::grid.draw(tree))
This function allows you to preview the layout that shape_math()
calculates. It renders the positioned glyphs and lines (fraction bars,
radical overlines, cancel lines, etc.) using grid graphics, and shows the
position of the baseline relative to the equation. This is primarily
a debugging and visualization tool.
plot_math(shaped, id = 1)plot_math(shaped, id = 1)
shaped |
The output of a call to |
id |
The index of the expression to show if |
This function is called for its side effects
## Not run: shaped <- shape_math(r"(\frac{a}{b})", family = "STIX Two Math") plot_math(shaped) shaped <- shape_math("x^2 + y^2 = z^2", family = "STIX Two Math") plot_math(shaped) ## End(Not run)## Not run: shaped <- shape_math(r"(\frac{a}{b})", family = "STIX Two Math") plot_math(shaped) shaped <- shape_math("x^2 + y^2 = z^2", family = "STIX Two Math") plot_math(shaped) ## End(Not run)
This function allows you to preview the layout that shape_text()
calculates. It is purely meant as a sanity check to make sure that the values
calculated are sensible and shouldn't be used as a plotting function for
rendering text on its own.
plot_shape(shape, id = 1)plot_shape(shape, id = 1)
shape |
The output of a call to |
id |
The index of the text run to show in case |
This function is called for its side effects
arab_text <- lorem_text("arabic", 2) shape <- shape_text( arab_text, max_width = 5, indent = 0.2 ) try( plot_shape(shape) )arab_text <- lorem_text("arabic", 2) shape <- shape_text( arab_text, max_width = 5, indent = 0.2 ) try( plot_shape(shape) )
Parses a LaTeX math expression and returns positioned glyphs for rendering. The function uses HarfBuzz's OpenType MATH table support to properly position mathematical symbols, scripts, fractions, and other structures according to the font's mathematical typesetting rules.
shape_math( math, family = "math", size = 12, res = 72, inline = TRUE, color = "black", path = NULL, index = 0 )shape_math( math, family = "math", size = 12, res = 72, inline = TRUE, color = "black", path = NULL, index = 0 )
math |
A character vector of LaTeX math expressions. Use raw strings
for cleaner syntax, e.g., |
family |
Font family name. For best results, use a font with an OpenType MATH table such as "STIX Two Math", "Latin Modern Math", "Cambria Math", or "Libertinus Math". Fonts without a MATH table will use fallback positioning constants based on TeX defaults, which produces reasonable but less precise results. Default uses the system's default math font. |
size |
The size in points to use for the font |
res |
The resolution to use when doing the shaping. Should optimally match the resolution used when rendering the glyphs. |
inline |
Logical. If |
color |
Base color for the equation (default "black"). Individual
elements can override this using |
path, index
|
path an index of a font file to circumvent lookup based on family and style |
Mathematical typesetting works best with fonts that include an OpenType MATH table, which provides precise positioning parameters for scripts, fractions, radicals, and other structures. When using a font without a MATH table (such as Arial or Times New Roman), the function falls back to default positioning constants based on TeX conventions. The results will be reasonable but may not match the typographic quality of a dedicated math font.
LaTeX math expressions is a huge specification and also includes numerous extensions with additional functionality. Supporting the full set would be unfeasible but textshaping tries hard to cover all but the most esoteric needs. The list of supported functionality is:
\alpha, \beta, \gamma, \delta, \epsilon,
\varepsilon, \zeta, \eta, \theta, \vartheta, \iota, \kappa,
\lambda, \mu, \nu, \xi, \pi, \varpi, \rho, \varrho,
\sigma, \varsigma, \tau, \upsilon, \phi, \varphi, \chi,
\psi, \omega, \Gamma, \Delta, \Theta, \Lambda, \Xi, \Pi,
\Sigma, \Upsilon, \Phi, \Psi, \Omega
+, -, =, \pm, \mp, \times, \div,
\cdot, \ast, \star, \circ, \bullet, \cap, \cup, \vee,
\wedge, \setminus, \oplus, \ominus, \otimes, \oslash, \odot,
\ltimes, \rtimes, \boxplus, \boxminus, \boxtimes
\leq, \le, \geq, \ge, \neq, \ne, \equiv,
\approx, \sim, \simeq, \cong, \propto, \ll, \gg,
\subset, \supset, \subseteq, \supseteq, \in, \ni, \notin,
\perp, \parallel, \mid, \prec, \succ, \preceq, \succeq,
\leqslant, \geqslant, \lesssim, \gtrsim, \vDash, \Vdash,
\triangleq
\to, \rightarrow, \leftarrow, \Rightarrow, \Leftarrow,
\leftrightarrow, \Leftrightarrow, \mapsto, \hookleftarrow,
\hookrightarrow, \uparrow, \downarrow, \Uparrow, \Downarrow,
\updownarrow, \nearrow, \searrow, \swarrow, \nwarrow,
\nleftarrow, \nrightarrow, \nLeftarrow, \nRightarrow,
\nleftrightarrow, \nLeftrightarrow, \leftarrowtail, \rightarrowtail,
\twoheadleftarrow, \twoheadrightarrow, \curvearrowleft,
\curvearrowright
x^2, x_i, x_i^2
\frac{num}{denom}, \dfrac{}{} (display style),
\tfrac{}{} (text style), \cfrac{}{} (continued fraction)
\sqrt{x}, \sqrt[n]{x}
\sum, \prod, \coprod, \int, \iint, \iiint,
\oint, \bigcup, \bigcap, \bigvee, \bigwedge, \bigoplus,
\bigotimes, \bigodot, \biguplus, \bigsqcup
(with _{lower}^{upper} limits). Use \limits to force limits above/below
or \nolimits to force side scripts
\left(, \right), \left[, \right], \left\{,
\right\}, \langle, \rangle, \lfloor, \rfloor, \lceil,
\rceil, \vert, \Vert, \ulcorner, \urcorner, \llcorner,
\lrcorner
\big, \Big, \bigg, \Bigg and variants
\bigl, \bigr, \bigm, \Bigl, \Bigr, \Bigm, etc. for manual
control of delimiter size
\hat{x}, \check{x}, \tilde{x}, \acute{x}, \grave{x},
\dot{x}, \ddot{x}, \dddot{x}, \ddddot{x}, \breve{x}, \bar{x},
\vec{x}, \mathring{x}
\widehat{abc}, \widetilde{abc}, \overline{abc},
\underline{abc}, \overbrace{abc}, \underbrace{abc},
\overrightarrow{AB}, \overleftarrow{AB}, \overleftrightarrow{AB},
\underrightarrow{}, \underleftarrow{}, \underleftrightarrow{}.
Overbrace/underbrace support annotations: \overbrace{x+y}^{n},
\underbrace{x+y}_{n}
\sin, \cos, \tan, \cot, \sec, \csc,
\arcsin, \arccos, \arctan, \arccot, \sinh, \cosh, \tanh,
\coth, \log, \ln, \lg, \exp, \lim, \liminf, \limsup,
\max, \min, \sup, \inf, \det, \dim, \ker, \hom,
\arg, \deg, \gcd, \Pr, \mod
\text{...}
\mathbf{x}, \mathit{x}, \mathrm{x}, \mathsf{x},
\mathtt{x}, \mathcal{X}, \mathscr{X}, \mathfrak{X}, \mathbb{R},
\boldsymbol{x}, \bm{x}
\displaystyle, \textstyle, \scriptstyle,
\scriptscriptstyle to control operator size and limit placement
\begin{matrix}, \begin{pmatrix}, \begin{bmatrix},
\begin{vmatrix}, \begin{Vmatrix}, \begin{Bmatrix}, \begin{smallmatrix}
(with & for column separators and \\ for row separators)
\begin{aligned}, \begin{gathered},
\begin{split}, \begin{array}{lcr} for multi-line equations with
alignment points
\begin{cases}, \begin{rcases}, \begin{dcases},
\begin{drcases}
\binom{n}{k}, \tbinom{n}{k}, \dbinom{n}{k},
\overset{a}{b}, \underset{a}{b}, \stackrel{a}{b}, \atop
\operatorname{name}, \operatorname*{name} (with limits)
\phantom{x} (invisible with full dimensions),
\hphantom{x} (width only), \vphantom{x} (height/depth only)
\textcolor{color}{text}, \color{color}{text},
\colorbox{color}{text}
\cancel{x}, \bcancel{x}, \xcancel{x}, \cancelto{v}{x}
\boxed{expression}
\substack{a \\ b} for multi-line subscripts
\not followed by a symbol (e.g., \not=)
\xrightarrow{above}, \xleftarrow[below]{above},
\xRightarrow{}, \xLeftarrow{}, \xleftrightarrow{}, \xLeftrightarrow{},
\xhookleftarrow{}, \xhookrightarrow{}, \xmapsto{}, \xlongequal{}
\! (negative thin), \, (thin), \: (medium), \; (thick),
\ (space), \quad, \qquad
\smash{x} (zero height and depth), \smash[t]{x} (zero height),
\smash[b]{x} (zero depth) for fine vertical spacing control
\pmod{n} for "(mod n)", \bmod as binary operator,
\pod{n} for "(n)"
\rule{width}{height} for custom-sized horizontal rules
\infty, \partial, \nabla, \forall,
\exists, \nexists, \emptyset, \varnothing, \aleph, \hbar,
\ell, \wp, \Re, \Im, \angle, \triangle, \prime, \ldots,
\cdots, \vdots, \ddots, \neg, \lnot, \bot, \top,
\dagger, \ddagger, \diamond, \square, \checkmark, \imath,
\jmath, \complement, \eth, \hslash, \mho, \dotsb, \dotsc,
\dotsi, \dotsm, \dotso
A list with four element: shape contains the position of each glyph,
relative to the origin in the enclosing textbox. metrics contain metrics
about the full math expression. lines contain line segments (fraction bars,
overlines, cancel lines, etc.). boxes contain position and dimensions of boxes.
shape is a data.frame with the following columns:
Row number within the string
Glyph index in the font
Index of the metrics row (same as string_id)
Index of the input string this glyph belongs to
X position relative to the origin
Y position relative to the baseline (positive is up)
Path to the font file
Index of the font face in the font file
Font size used for this glyph (may differ for scripts)
Horizontal advance width of the glyph
Color for this glyph
metrics is a data.frame with the following columns:
Total width of the expression
Height above the baseline
Depth below the baseline
lines is a data.frame with the following columns:
X position of start point
Y position of start point
X position of end point
Y position of end point
Line thickness
Index of the input string this line belongs to
Color for this line
boxes is a data.frame with the following columns:
X position of the left edge
Y position of the bottom edge
Width of the box
Height of the box
Index of the input string this box belongs to
Fill color for the box
# Simple superscript shape_math("x^2") # Greek letters shape_math(r"(\alpha + \beta)") # Fraction shape_math(r"(\frac{a}{b})") # Display mode sum (inline = FALSE) shape_math(r"(\sum_{i=1}^n i)", inline = FALSE) # Quadratic formula shape_math(r"(x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a})") # Matrix shape_math(r"(\begin{pmatrix} a & b \\\\ c & d \end{pmatrix})") # Binomial coefficient shape_math(r"(\binom{n}{k})") # Cases environment shape_math(r"(f(x) = \begin{cases} 1 & x > 0 \\\\ 0 & x \\leq 0 \end{cases})") # Colored text shape_math(r"(x = \textcolor{red}{-b})") # Cancellation shape_math(r"(\frac{\cancel{2}x}{\cancel{2}} = x)") # Extensible arrow with text shape_math(r"(A \xrightarrow{f} B)")# Simple superscript shape_math("x^2") # Greek letters shape_math(r"(\alpha + \beta)") # Fraction shape_math(r"(\frac{a}{b})") # Display mode sum (inline = FALSE) shape_math(r"(\sum_{i=1}^n i)", inline = FALSE) # Quadratic formula shape_math(r"(x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a})") # Matrix shape_math(r"(\begin{pmatrix} a & b \\\\ c & d \end{pmatrix})") # Binomial coefficient shape_math(r"(\binom{n}{k})") # Cases environment shape_math(r"(f(x) = \begin{cases} 1 & x > 0 \\\\ 0 & x \\leq 0 \end{cases})") # Colored text shape_math(r"(x = \textcolor{red}{-b})") # Cancellation shape_math(r"(\frac{\cancel{2}x}{\cancel{2}} = x)") # Extensible arrow with text shape_math(r"(A \xrightarrow{f} B)")
Performs advanced text shaping of strings including font fallbacks, bidirectional script support, word wrapping and various character and paragraph level formatting settings.
shape_text( strings, id = NULL, family = "", italic = FALSE, weight = "normal", width = "undefined", features = font_feature(), size = 12, res = 72, lineheight = 1, align = "auto", hjust = 0, vjust = 0, max_width = NA, tracking = 0, indent = 0, hanging = 0, space_before = 0, space_after = 0, direction = "auto", path = NULL, index = 0, bold = deprecated() )shape_text( strings, id = NULL, family = "", italic = FALSE, weight = "normal", width = "undefined", features = font_feature(), size = 12, res = 72, lineheight = 1, align = "auto", hjust = 0, vjust = 0, max_width = NA, tracking = 0, indent = 0, hanging = 0, space_before = 0, space_after = 0, direction = "auto", path = NULL, index = 0, bold = deprecated() )
strings |
A character vector of strings to shape |
id |
A vector grouping the strings together. If strings share an id the shaping will continue between strings |
family |
The name of the font families to match |
italic |
logical indicating the font slant |
weight |
The weight to query for, either in numbers ( |
width |
The width to query for either in numbers ( |
features |
A |
size |
The size in points to use for the font |
res |
The resolution to use when doing the shaping. Should optimally match the resolution used when rendering the glyphs. |
lineheight |
A multiplier for the lineheight |
align |
Within text box alignment, either |
hjust, vjust
|
The justification of the textbox surrounding the text |
max_width |
The requested with of the string in inches. Setting this to
something other than |
tracking |
Tracking of the glyphs (space adjustment) measured in 1/1000 em. |
indent |
The indent of the first line in a paragraph measured in inches. |
hanging |
The indent of the remaining lines in a paragraph measured in inches. |
space_before, space_after
|
The spacing above and below a paragraph, measured in points |
direction |
The overall directional flow of the text. The default
( |
path, index
|
path an index of a font file to circumvent lookup based on family and style |
bold |
logical indicating whether the font weight |
A list with two element: shape contains the position of each glyph,
relative to the origin in the enclosing textbox. metrics contain metrics
about the full strings.
shape is a data.frame with the following columns:
The placement of the the first character contributing to the glyph within the string
The index of the glyph in the font file
The index of the string the glyph is part of (referencing a row in the metrics data.frame)
The index of the string the glyph came from (referencing an element in the strings input)
The x offset in pixels from the origin of the textbox
The y offset in pixels from the origin of the textbox
The path to the font file used during shaping of the glyph
The index of the font used to shape the glyph in the font file
The size of the font used during shaping
The advancement amount to the next glyph
The ascend of the font used for the glyph. This does not measure the actual glyph
The descend of the font used for the glyph. This does not measure the actual glyph
metrics is a data.frame with the following columns:
The text the string consist of
The width of the string
The height of the string
The distance from the left edge of the textbox and the leftmost glyph
The distance from the right edge of the textbox and the rightmost glyph
The distance from the top edge of the textbox and the topmost glyph
The distance from the bottom edge of the textbox and the bottommost glyph
The position of the leftmost edge of the textbox related to the origin
The position of the topmost edge of the textbox related to the origin
The horizontal position of the next glyph after the string
The vertical position of the next glyph after the string
The global direction of the string. If TRUE then it is left-to-right, otherwise it is right-to-left
string <- "This is a long string\nLook; It spans multiple lines\nand all" # Shape with default settings shape_text(string) # Mix styles within the same string string <- c( "This string will have\na ", "very large", " text style\nin the middle" ) shape_text(string, id = c(1, 1, 1), size = c(12, 24, 12))string <- "This is a long string\nLook; It spans multiple lines\nand all" # Shape with default settings shape_text(string) # Mix styles within the same string string <- c( "This string will have\na ", "very large", " text style\nin the middle" ) shape_text(string, id = c(1, 1, 1), size = c(12, 24, 12))
This is a very simple alternative to systemfonts::shape_string() that
simply calculates the width of strings without taking any newline into
account. As such it is suitable to calculate the width of words or lines that
have already been split by \n. Input is recycled to the length of
strings.
text_width( strings, family = "", italic = FALSE, weight = "normal", width = "undefined", features = font_feature(), size = 12, res = 72, include_bearing = TRUE, path = NULL, index = 0, bold = deprecated() )text_width( strings, family = "", italic = FALSE, weight = "normal", width = "undefined", features = font_feature(), size = 12, res = 72, include_bearing = TRUE, path = NULL, index = 0, bold = deprecated() )
strings |
A character vector of strings |
family |
The name of the font families to match |
italic |
logical indicating the font slant |
weight |
The weight to query for, either in numbers ( |
width |
The width to query for either in numbers ( |
features |
A |
size |
The size in points to use for the font |
res |
The resolution to use when doing the shaping. Should optimally match the resolution used when rendering the glyphs. |
include_bearing |
Logical, should left and right bearing be included in the string width? |
path, index
|
path an index of a font file to circumvent lookup based on family and style |
bold |
logical indicating whether the font weight |
A numeric vector giving the width of the strings in pixels. Use the
provided res value to convert it into absolute values.
strings <- c('A short string', 'A very very looong string') text_width(strings)strings <- c('A short string', 'A very very looong string') text_width(strings)