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

Add addFont() to SVGDocumentFragment #126

Closed
wants to merge 2 commits into from
Closed

Conversation

njourdane
Copy link

@njourdane njourdane commented Jun 20, 2021

Add addFont() method to the SVGDocumentFragment class.

Related to #82 and #10.

Usage

Add a font to text nodes that match given attributes.

Parameters:

  • string $fontPath The path of the font being added.
  • SVGText $textNode If specified, affects only text node that included in this node.
  • string $fontFamily If specified, affects only texts that have this font family.
  • string $fontWeight If specified, affects only texts that have this font weight.
  • string $fontStyle If specified, affects only texts that have this text style.

Example script

<?php
require_once ("./vendor/autoload.php");
use SVG\SVG;

const FONTS_DIR = '/usr/share/fonts/truetype/ubuntu/';

$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">no filter</text>
		<text y="60"  id="thin" fill="blue">thin</text>
		<text y="40"  class="condensed" stroke="white" stroke-width="1px">condensed</text>
		<text y="80"  font-family="monospace">monospace</text>
		<text y="100" font-weight="bold">bold</text>
		<text y="120" font-style="italic">italic</text>
		<text y="140" font-weight="bold" font-style="italic">bold italic</text>
		<text y="160" font-size="15" font-family="monospace" font-weight="bold">monospace bold</text>
		<text y="180" font-size="15" style="font-family: monospace; font-style: italic">monospace italic</text>
		<text y="200" font-size="15" style="font-family: monospace; font-weight: bold; font-style: italic">monospace bold italic</text>
	</g>
</svg>
');

$doc = $image->getDocument();

// no filter
$doc->addFont(FONTS_DIR . 'Ubuntu-R.ttf');

// filter on id
$doc->addFont(FONTS_DIR . 'Ubuntu-Th.ttf', $doc->getElementById('thin'));

// filter on class
foreach ($doc->getElementsByClassName('condensed') as $node) {
	$doc->addFont(FONTS_DIR . 'Ubuntu-C.ttf', $node);
}

// filter on font family
$doc->addFont(FONTS_DIR . 'UbuntuMono-R.ttf', null, 'monospace');

// // filter on text weight or/and style
$doc->addFont(FONTS_DIR . 'Ubuntu-B.ttf',  null, '', 'bold');
$doc->addFont(FONTS_DIR . 'Ubuntu-RI.ttf',  null, '', '', 'italic');
$doc->addFont(FONTS_DIR . 'Ubuntu-BI.ttf', null, '', 'bold', 'italic');

// filter on font family or/and weight or/and style
$doc->addFont(FONTS_DIR . 'UbuntuMono-B.ttf', null, 'monospace', 'bold');
$doc->addFont(FONTS_DIR . 'UbuntuMono-RI.ttf', null, 'monospace', '', 'italic');
$doc->addFont(FONTS_DIR . 'UbuntuMono-BI.ttf', null, 'monospace', 'bold', 'italic');

$raster = $image->toRasterImage($doc->getWidth(), $doc->getHeight());
imagepng($raster);

Output

out

EDIT: update doc according to new usage in last commit.

@njourdane njourdane changed the title Add addFont() to SVGDocument Add addFont() to SVGDocumentFragment Jun 23, 2021
@meyfa
Copy link
Owner

meyfa commented Mar 3, 2022

Thanks for this PR! Please excuse the terribly long delay... I like this implementation insofar as it integrates well with the existing design. Well done!

Now as to why I hesitate to merge this: Honestly I think our whole approach to fonts in PHP-SVG needs to change. Your code is fine, it's just built on top of a bad foundation, for which I am largely responsible myself. If I understand correctly the reason we need an addFont function is that PHP-SVG has no concept of a default set of user agent fonts, and neither does it support fallback fonts. This is unlike any other SVG client such as the common web browsers.

Really the solution shouldn't be about programmatically modifying the document. Such modifications require the programmer to know the contents of the document. Instead we need to instruct the rasterizer how to resolve font requests generally. For example:

  • The programmer instructs PHP-SVG which font files are available on the system. This can be done globally. It'd be optimal if only the font file path would need to be provided, or perhaps even an entire directory. PHP-SVG would read the file metadata. From there it would, for example, know that the font 'Arial' is available, which is a sans-serif font that is available in regular, bold, and italic variants.
  • When rasterizing SVGs, this information is taken into account automatically, without the programmer having to mutate each document. Assume, for example, that during rasterization, a text node is encountered. The text node specifies font-family: Helvetica; font-weight: bold. The rasterizer will try to resolve this font. Now, 'Helvetica' is not available, but the rasterizer knows about another bold font, which is 'Arial' bold. So that's what will be used.

The code from a user perspective could look something like this:

<?php
require_once ("./vendor/autoload.php");
use SVG\SVG;

const FONTS_DIR = '/usr/share/fonts/truetype/ubuntu/';

SVG::addFont(FONTS_DIR . 'Ubuntu-B.ttf');
SVG::addFont(FONTS_DIR . 'Ubuntu-RI.ttf');
SVG::addFont(FONTS_DIR . 'Ubuntu-BI.ttf');
SVG::addFont(FONTS_DIR . 'UbuntuMono-B.ttf');
SVG::addFont(FONTS_DIR . 'UbuntuMono-RI.ttf');
SVG::addFont(FONTS_DIR . 'UbuntuMono-BI.ttf');
// or perhaps even:
SVG::addFontDirectory(FONTS_DIR);

$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">no filter</text>
		<text y="60"  id="thin" fill="blue">thin</text>
		<text y="40"  class="condensed" stroke="white" stroke-width="1px">condensed</text>
		<text y="80"  font-family="monospace">monospace</text>
		<text y="100" font-weight="bold">bold</text>
		<text y="120" font-style="italic">italic</text>
		<text y="140" font-weight="bold" font-style="italic">bold italic</text>
		<text y="160" font-size="15" font-family="monospace" font-weight="bold">monospace bold</text>
		<text y="180" font-size="15" style="font-family: monospace; font-style: italic">monospace italic</text>
		<text y="200" font-size="15" style="font-family: monospace; font-weight: bold; font-style: italic">monospace bold italic</text>
	</g>
</svg>
');

$raster = $image->toRasterImage($doc->getWidth(), $doc->getHeight());
imagepng($raster);

Again, I want to emphasize that your code is a great addition to the current state of the library. I'm just not happy with that current state and would like to do a complete overhaul, which will make this addition obsolete, I think.

@meyfa meyfa closed this Jun 20, 2022
@meyfa
Copy link
Owner

meyfa commented Dec 28, 2022

I've implemented the above idea in PR #191.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants