
<!-- README.md is generated from README.Rmd. Please edit that file -->

# gdtools

<!-- badges: start -->

[![CRAN
status](https://www.r-pkg.org/badges/version/gdtools)](https://CRAN.R-project.org/package=gdtools)
[![R build
status](https://github.com/davidgohel/gdtools/workflows/R-CMD-check/badge.svg)](https://github.com/davidgohel/gdtools/actions)
[![codecov test
coverage](https://codecov.io/gh/davidgohel/gdtools/branch/main/graph/badge.svg)](https://app.codecov.io/gh/davidgohel/gdtools)
<!-- badges: end -->

`gdtools` addresses four practical problems when working with fonts in
R:

| Problem | gdtools solution |
|----|----|
| Measure text without a device: layout calculations (column widths, text wrapping) need reliable metrics independent of the rendering device | `strings_sizes()` via Cairo |
| Register non-system fonts: Google Fonts or Liberation fonts (bundled) must be made visible to ‘systemfonts’ | `font_set_liberation()`, `font_set_auto()`, `font_set()` |
| Embed fonts in HTML: Shiny, R Markdown and girafe need `htmlDependency` objects so the browser loads the right fonts | `font_set()$dependencies`, `gfontHtmlDependency()`, `liberation*HtmlDependency()` |
| Check font availability: detect missing fonts before rendering, to avoid silent fallbacks | `font_family_exists()`, `sys_fonts()` |

## How font metric calculation works

`gdtools` was originally designed to compute font metrics for R graphic
devices via C-level interfaces (Cairo and FreeType). With the arrival of
the ‘systemfonts’ package, font discovery and matching became much
simpler and the C interface was no longer needed by other packages.

The package has since been refocused. Font metric calculation follows
two steps:

1.  Font lookup: ‘systemfonts’ resolves the family name to a font file.
    Any font registered via `systemfonts::register_font()`,
    `register_gfont()`, or `font_set()` is found.
2.  Metric computation: Cairo reads the font file and computes width,
    ascent, and descent.

The metrics are independent of any graphic device. Whether they match
the final rendering depends on how the device resolves fonts on its
side, this is a device concern.

## Installation

You can install the released version of gdtools from CRAN with:

``` r
install.packages("gdtools")
```

And the development version from GitHub with:

``` r
# install.packages("remotes")
remotes::install_github("davidgohel/gdtools")
```

## Font metrics

The main function for text measurement is `strings_sizes()`. It returns
width, ascent and descent in inches using Cairo. The measurements are
accurate for devices that use Cairo or ‘systemfonts’ for font resolution
(ragg, svglite, ggiraph, `cairo_pdf()`, …); for devices with their own
font engine (`pdf()`, `png()`, …) the metrics may not match the
rendering.

``` r
library(gdtools)
strings_sizes(
  c("a string", "a longer string"),
  fontsize = 24, 
  bold = TRUE, 
  italic = TRUE
)
#>      width    ascent    descent
#> 1 1.203939 0.2413737 0.07259115
#> 2 2.315104 0.2413737 0.07259115
```

All arguments are vectorized:

``` r
strings_sizes(
  c("normal", "bold", "italic", "bold-italic"),
  fontsize = 12,
  bold = c(FALSE, TRUE, FALSE, TRUE),
  italic = c(FALSE, FALSE, TRUE, TRUE)
)
#>       width    ascent     descent
#> 1 0.5094401 0.1195475 0.003173828
#> 2 0.3517253 0.1199544 0.003092448
#> 3 0.3334147 0.1195475 0.002929688
#> 4 0.7870280 0.1206868 0.003092448
```

## Font management

`font_set_auto()` detects the best available system fonts and falls back
to Liberation fonts when needed. It returns a `font_set` object ready to
use with ggplot2, ggiraph, or any ‘systemfonts’-based device:

``` r
library(gdtools)

fonts <- font_set_auto()
fonts
#> Font set
#>   sans:    Arial [system]
#>   serif:   Times New Roman [system]
#>   mono:    Courier New [system]
#>   symbol:  Symbol [system]
#>   4 HTML dependencies
```

For explicit control, `font_set()` lets you pick each role with
`font_google()`, `font_liberation()`, or a plain family name:

``` r
fonts <- font_set(
  sans  = font_google("Open Sans"),
  mono  = font_liberation("mono")
)

fonts$sans          # "Open Sans"
fonts$dsvg_fonts    # named list for dsvg() / girafe()
fonts$dependencies  # list of htmlDependency objects
```

For an offline-only setup, `font_set_liberation()` uses Liberation fonts
for all four roles:

``` r
fonts <- font_set_liberation()
fonts
```

### Going further

#### Google Fonts

A set of lower-level functions is provided to download and cache fonts
from ‘Google Fonts’. They can be used in ‘R Markdown’ documents and
‘Shiny’ applications, as well as with graphic outputs generated by
‘ggiraph’, ‘ragg’ and ‘svglite’, or tabular outputs from ‘flextable’.

``` r
# Download and register with systemfonts (cached for future use)
register_gfont(family = "Open Sans")
```

Use `addGFontHtmlDependency()` to embed a Google Font in an HTML
document, and `gfontHtmlDependency()` to create an `htmltools`
dependency object.

To install a Google Font at the system level (e.g. in a Dockerfile), use
`install_gfont_script()`:

``` r
install_gfont_script("Fira Sans", platform = "debian", file = "install-font.sh")
```

#### Liberation fonts

The package bundles ‘Liberation Sans’, ‘Liberation Serif’ and
‘Liberation Mono’ fonts (SIL Open Font License). They are useful as
cross-platform fallback fonts, for visual tests, or when no internet
connection is available.

`font_set_liberation()` registers all three families with ‘systemfonts’
and produces the matching HTML dependencies in a single call:

``` r
fonts <- font_set_liberation()
fonts$sans
fonts$dependencies
```

The individual functions `register_liberationsans()`,
`register_liberationserif()` and `register_liberationmono()` remain
available when only a specific variant is needed.

## Install from sources on macOS

Please read carefully the official R for macOS instructions:
<https://mac.r-project.org/>

To compile ‘gdtools’ from source, you need `cairo` (which pulls in
`freetype` and `fontconfig` as dependencies) and `gettext` (which
provides `libintl`, required at link time by `fontconfig`). Using
Homebrew is recommended:

    brew install cairo fontconfig gettext

Then configure your `~/.R/Makevars` file with the appropriate paths. For
Apple Silicon Macs (M1/M2/M3/M4), the typical configuration is:

    CFLAGS=-I/opt/homebrew/include
    CPPFLAGS=-I/opt/homebrew/include
    CXXFLAGS=-I/opt/homebrew/include
    CXX11FLAGS=-I/opt/homebrew/include
    LDFLAGS=-L/opt/homebrew/lib

For Intel Macs, paths are usually `/usr/local/include` and
`/usr/local/lib`:

    CFLAGS=-I/usr/local/include
    CPPFLAGS=-I/usr/local/include
    CXXFLAGS=-I/usr/local/include
    CXX11FLAGS=-I/usr/local/include
    LDFLAGS=-L/usr/local/lib

> Note: paths may vary depending on your system configuration. We are
> unable to provide support for installation issues related to macOS
> compilation setup.
