Skip to content

Commit

Permalink
Rework font defaults and settings
Browse files Browse the repository at this point in the history
- Allow setting default font with GFLABEL_FONT environment variable
- Default font is now Open Sans, which is now bundled
- Font family file can be directly specified with --font-path

Should resolve/allow to be resolved #4.
  • Loading branch information
ndevenish committed May 17, 2024
1 parent 1094f14 commit 52ef499
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 15 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

- Added `{magnet}` fragment. Thanks to [@PaulBone](https://github.com/PaulBone)
for the contribution.
- Changed text/font handling. Instead of Futura, GFLabel now defaults to a
bundled version of [Open Sans][opensans]. You can still specify your
font of choice with `--font` (if it is a system font), or if you want to
specify a specific font file you can set `--font-path`.
- You can set the default font at an environment level by setting `GFLABEL_FONT`
to the name of the system font that you want to use.

[opensans]: https://github.com/googlefonts/opensans

# GFLabel 0.1.5 (2024-05-12)

Expand Down
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,24 @@ which can be set to `embossed`, `debossed`, or `embedded`:
| Debossed | Instead of being raised, the label contents are cut into the base. You can also print this multicoloured by changing material at specific layer height. | ![](images/style_debossed.png)
| Embedded | The label contents are flush with the surface of the label. This can be printed with a multimaterial system, as it will require material changes within a single layer. You can print this label face-down. To print this, you will need to "Split to Parts" (Bambu/OrcaSlicer) in your slicer and manually change the selected material for the bases. | ![](images/style_embedded.png)

### Text Style, and Fonts

Text is rendered as text on the label, including variable width whitespaces so e.g. a halfspace
will render a halfspace width, which is good for minor separation if you don't want a gap of
specific width.

GFLabel comes with [Open Sans][opensans], and will use this (in regular, bold or italic) if you
don't otherwise specify any font preference.

Options for controlling font rendering are:

| Setting | Description |
| ------------- | ------------|
| `--font NAME` | Specified font directly, by name. This will have to be a font that is generally installed and available on your system. If you don't specify this (or -path), then a packaged version of Open Sans will be used. |
| `--font-path /path/to/font` | Specify font by directly specifying the location of the font file on disk. Takes precedence over `--font`, so if you specify both, this will be used.
| `--font-style STYLE` | Where `STYLE` can be `bolt`, `italic`, or `regular` (the default). If you haven't specified a font file then the underlying font system will make a best-effort attempt to find your selected font in one of these weights.
| `--font-size NUMBER` | Specifies a fixed height (in mm) for the font on the label. Text will always be rendered at this size, even if it causes the text to not fit. Using this can help text-size consistency over many labels, as otherwise the shorter text labels may end up at a larger scale (because they can fill the vertical without over-running it's available space).
| `--font-size-maximum NUMBER` | Specifies a _maximum_ font size. Text won't be allowed to go larger than this, but text can be shrunk to fit if it would otherwise overrun it's label area. This can help text-size disparity over many labels in cases where some of them are much longer, and you can tolerate them being shrunken. This is used to generate the electrical symbol examples.

### Symbols/Fragments

Expand Down Expand Up @@ -343,7 +361,7 @@ gflabel "{<}A\n{measure}{4|}{>}B\n{measure}{1|2}{<}C\n{measure}"

Electronic symbols can be generated using the `{symbol(...)}` fragment.
GFLabel is using the [Chris Pikul Electronic Symbols ][pikul] library kindly
released under MIT Licence.
released under MIT License.

[pikul]: https://github.com/chris-pikul/electronic-symbols

Expand Down Expand Up @@ -395,6 +413,9 @@ incorrectly. This is an unresolved bug in GFLabel.
# Bundled Dependencies

GFLabel uses (and bundles) a couple of dependencies in subdirectories:
- The [Chris Pikul Electronic Symbols ][pikul] library, MIT Licence Copyright (c) 2022 Chris Pikul.
- The [Chris Pikul Electronic Symbols ][pikul] library, MIT License © 2022 Chris Pikul.
- The [Open Sans][opensans] font family, OFL-1.1 License © 2020 The Open Sans Project Authors.


[opensans]: https://github.com/googlefonts/opensans
[pikul]: https://github.com/chris-pikul/electronic-symbols
13 changes: 10 additions & 3 deletions src/gflabel/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@

import argparse
import logging
import os
import sys
from argparse import ArgumentParser
from pathlib import Path
from typing import Any, Sequence

import build123d as bd
Expand Down Expand Up @@ -145,9 +147,9 @@ def run(argv: list[str] | None = None):

parser.add_argument(
"--font",
help="The font to use for rendering. [Default: %(default)s]",
help="The name of the system font to use for rendering. If unspecified, a bundled version of Open Sans will be used. Set GFLABEL_FONT in your environment to change the default.",
type=str,
default="Futura",
default=os.getenv("GFLABEL_FONT"),
)

font_size = parser.add_mutually_exclusive_group()
Expand All @@ -161,14 +163,19 @@ def run(argv: list[str] | None = None):
help="The font size (in mm) to use for rendering. If unset, then the font will use as much vertical space as needed (that also fits within the horizontal area).",
type=float,
)

parser.add_argument(
"--font-style",
help="The font style use for rendering. [Default: %(default)s]",
choices=[x.name.lower() for x in FontStyle],
default="regular",
type=str,
)
parser.add_argument(
"--font-path",
help="Path to font file, if not using a system-level font.",
type=Path,
# default=None,
)
parser.add_argument(
"--margin",
help="The margin area (in mm) to leave around the label contents. Default is per-base.",
Expand Down
9 changes: 3 additions & 6 deletions src/gflabel/fragments.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,9 @@ def __init__(self, text: str):

def render(self, height: float, maxsize: float, options: RenderOptions) -> Sketch:
with BuildSketch() as sketch:
Text(
self.text,
font_size=options.font.get_allowed_height(height),
font=options.font.font,
font_style=options.font.font_style,
)
with options.font.font_options() as f:
print(f"Using {f}")
Text(self.text, font_size=options.font.get_allowed_height(height), **f)
return sketch.sketch


Expand Down
47 changes: 43 additions & 4 deletions src/gflabel/options.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
from __future__ import annotations

import argparse
import contextlib
import importlib
import importlib.resources
import logging
from enum import Enum, auto
from typing import NamedTuple
from typing import Iterator, NamedTuple

from build123d import FontStyle
from build123d import FontStyle, Path

logger = logging.getLogger(__name__)


class LabelStyle(Enum):
Expand All @@ -23,8 +29,10 @@ def __str__(self):


class FontOptions(NamedTuple):
font: str = "Futura"
font_style: FontStyle = FontStyle.BOLD
font: str | None = None
font_style: FontStyle = FontStyle.REGULAR
font_path: Path | None = None

# The font height, in mm. If this is unspecified, then the font will
# be scaled to maximum area height, and then scaled down accordingly.
# Setting this can explicitly cause overflow, as the text will be
Expand All @@ -40,6 +48,36 @@ def get_allowed_height(self, requested_height: float) -> float:
else:
return min(self.font_height_mm or requested_height, requested_height)

@contextlib.contextmanager
def font_options(self) -> Iterator:
"""
Handle loading of any font files, generating the kwargs to pass to build123d.Text
"""

kwargs = {"font_style": self.font_style}
if self.font_path:
kwargs["font_path"] = str(self.font_path)
# Need to work out if path is enough or if we also need name
if self.font:
kwargs["font"] = self.font

with contextlib.ExitStack() as stack:
# If we have no font, and no font path, then use the built-in ones
if not self.font and not self.font_path:
logger.debug("Falling back to internal font OpenSans")
# This is a bit noisy but the way you are supposed to do it
fontfile = stack.enter_context(
importlib.resources.as_file(
importlib.resources.files("gflabel").joinpath(
f"resources/OpenSans-{self.font_style.name.title()}"
)
)
)

kwargs["font_path"] = str(fontfile)

yield kwargs


class RenderOptions(NamedTuple):
line_spacing_mm: float = 0.1
Expand All @@ -63,6 +101,7 @@ def from_args(cls, args: argparse.Namespace) -> RenderOptions:
font_style=font_style,
font_height_mm=args.font_size or args.font_size_maximum,
font_height_exact=not args.font_size_maximum,
font_path=args.font_path,
),
allow_overheight=not args.no_overheight,
column_gap=args.column_gap,
Expand Down
93 changes: 93 additions & 0 deletions src/gflabel/resources/LICENSE_OpenSans
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file added src/gflabel/resources/OpenSans-Bold.ttf
Binary file not shown.
Binary file added src/gflabel/resources/OpenSans-Italic.ttf
Binary file not shown.
Binary file added src/gflabel/resources/OpenSans-Regular.ttf
Binary file not shown.

0 comments on commit 52ef499

Please sign in to comment.