Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Implement a font registry for text rendering #191

Merged
merged 3 commits into from
Jan 2, 2023
Merged

Conversation

meyfa
Copy link
Owner

@meyfa meyfa commented Dec 28, 2022

Fixes #82
Fixes #168
Fixes #171

This patch removes the artificial SVGFont class as well as the SVGText::setFont(SVGFont $font) method. Instead, it is now possible to register TrueType (.ttf) font files by calling SVG::addFont() with a file path.

A TrueType font file parser is implemented based on Microsoft's OpenType specification. This allows us to choose the best matching font file for a given text element automatically, just like a browser would, based on algorithms from CSS.

Currently, TTF files are supported with all weight levels, and in the italic and non-italic styles. The simple algorithm implemented here tries to match the font family exactly, if possible, falling back to any other font. Generic font families such as "serif" or "monospace" aren't supported yet and will trigger the fallback. Also, the relative weights "bolder" and "lighter" aren't computed and fall back to normal weight.

BREAKING CHANGE: SVGFont class and some methods on SVGText removed.

@meyfa meyfa added the feature New feature or request label Dec 28, 2022
@meyfa meyfa added this to the v0.14.0 milestone Dec 28, 2022
@meyfa
Copy link
Owner Author

meyfa commented Dec 28, 2022

For reference, here is a sample image:

image

Generated by this code:

<?php
require __DIR__ . '/vendor/autoload.php';
use SVG\SVG;

const FONTS_DIR = __DIR__.'/fonts/';

SVG::addFont(FONTS_DIR . 'Ubuntu-Regular.ttf');
SVG::addFont(FONTS_DIR . 'Ubuntu-Bold.ttf');
SVG::addFont(FONTS_DIR . 'Ubuntu-Italic.ttf');
SVG::addFont(FONTS_DIR . 'Ubuntu-BoldItalic.ttf');
SVG::addFont(FONTS_DIR . 'Ubuntu-Light.ttf');
SVG::addFont(FONTS_DIR . 'Ubuntu-LightItalic.ttf');
SVG::addFont(FONTS_DIR . 'UbuntuMono-Regular.ttf');
SVG::addFont(FONTS_DIR . 'UbuntuMono-Bold.ttf');
SVG::addFont(FONTS_DIR . 'UbuntuMono-Italic.ttf');
SVG::addFont(FONTS_DIR . 'UbuntuMono-BoldItalic.ttf');

$image = SVG::fromString('
<svg width="220" height="220">
  <rect x="0" y="0" width="100%" height="100%" fill="lightgray"/>
  <g font-size="15">
    <text y="20">regular</text>
    <text y="40" font-weight="100">light</text>
    <text y="60" font-weight="100" font-style="italic">light italic</text>
    <text y="80" font-weight="bold">bold</text>
    <text y="100" font-style="italic">italic</text>
    <text y="120" font-weight="bold" font-style="italic">bold italic</text>
    <text y="140" font-family="Ubuntu Mono">monospace</text>
    <text y="160" font-size="15" font-family="Ubuntu Mono" font-weight="bold">monospace bold</text>
    <text y="180" font-size="15" style="font-family: Ubuntu Mono; font-style: italic">monospace italic</text>
    <text y="200" font-size="15" style="font-family: Ubuntu Mono; font-weight: bold; font-style: italic">monospace bold italic</text>
  </g>
</svg>
');

header('Content-Type: image/png');
$doc = $image->getDocument();
imagepng($image->toRasterImage($doc->getWidth(), $doc->getHeight()));

Fixes #82, #168, #171.

This patch removes the artificial `SVGFont` class as well as the
`SVGText::setFont(SVGFont $font)` method. Instead, it is now possible
to register TrueType (`.ttf`) font files by calling `SVG::addFont()`
with a file path.

A TrueType font file parser is implemented based on Microsoft's OpenType
specification. This allows us to choose the best matching font file for
a given text element automatically, just like a browser would, based on
algorithms from CSS.

Currently, TTF files are supported in the "Regular", "Bold", "Italic",
and "Bold Italic" variants. The simple algorithm implemented here tries
to match the font family exactly, if possible, falling back to any other
font. Generic font families such as "serif" or "monospace" aren't
supported yet and will trigger the fallback. Also, the relative weights
"bolder" and "lighter" aren't computed and fall back to normal weight.

BREAKING CHANGE: `SVGFont` class and some methods on `SVGText` removed.
By looking at the "OS/2" TTF table in addition to the "name" table, we
can gather additional info about the font weight besides whether a font
is bold or not. By doing so, we gain support for every weight level! :)
@meyfa meyfa merged commit 24beb69 into main Jan 2, 2023
@meyfa meyfa deleted the feat/fonts branch January 2, 2023 18:41
@KWcDP6hz3
Copy link

KWcDP6hz3 commented Jul 4, 2024

Hi @meyfa,
The SVGFont class was also responsible for including the font as @font-face in the document. This seems to be gone with this change. Is that correct, or is there another workaround?
Thanks,

@meyfa
Copy link
Owner Author

meyfa commented Jul 4, 2024

@KWcDP6hz3 This is correct. The previous approach did not make sense from an API design perspective, since the SVGFont was just an SVGStyle in disguise.

If embedding the entire font data within the SVG is something you need, you will have to create a style element containing @font-face manually, based on SVGStyle. The required code can be adapted from the deleted class: https://github.com/meyfa/php-svg/blob/ef0ca1663c33d82b16e329b0daccd2547cb45e48/src/Nodes/Structures/SVGFont.php

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
2 participants