Drop the OsmAnd-recolor map theme, add offline labels and a lighter palette nudge
Remove osmand-style.js (the per-layer color-patching approach) and its docs entirely — back to the plain OpenFreeMap "liberty" style online, and protomaps-themes-base's stock theme offline as the base. Offline maps previously had no text labels at all: the protomaps-themes-base layers() call never passed a lang option, which is required to include its label layers. Fixed, backed by vendored Noto Sans Regular/Italic/Medium glyph PBFs (ranges 0-255 and 256-511 only — Basic Latin + Latin-1 Supplement + Latin Extended-A, enough for accented Central European place names; other scripts won't render offline). Verified against the actual offline.pmtiles vector layer schema that the name/name:en/script fields this expects are present. Also nudge a handful of OFFLINE_THEME color roles (background, water, wood, buildings, the two road-importance tiers) towards the online style's actual palette (sampled from its style JSON) so switching Online/Offline doesn't look like two different apps — deliberately partial, not the removed full recolor.
This commit is contained in:
1 parent
06ea8ea141
commit
0887ccbfe7
12 files changed
+163
-217
No files matched your search
+1
-2
@@ -10,8 +10,7 @@ The project's shape is still open — this is the initial scaffold.
|
|||||||
== Status
|
== Status
|
||||||
|
|
||||||
Early scaffold. The web application serves a vector map (MapLibre GL
|
Early scaffold. The web application serves a vector map (MapLibre GL
|
||||||
JS), styled to resemble https://osmand.net/map[OsmAnd's own map], with
|
JS), with an online style and an optional offline style backed by a local
|
||||||
an online style and an optional offline style backed by a local
|
|
||||||
PMTiles file, an animated RainViewer radar overlay, GPX
|
PMTiles file, an animated RainViewer radar overlay, GPX
|
||||||
upload/display (points and tracks, organized in folders), and a live
|
upload/display (points and tracks, organized in folders), and a live
|
||||||
position marker from a local GNSS receiver via gpsd.
|
position marker from a local GNSS receiver via gpsd.
|
||||||
|
|||||||
+27
-47
@@ -70,59 +70,39 @@ support) just returns byte ranges of the file; pmtiles.js in the
|
|||||||
browser reads the archive's own directory and requests only the bytes
|
browser reads the archive's own directory and requests only the bytes
|
||||||
it needs for the tiles on screen.
|
it needs for the tiles on screen.
|
||||||
|
|
||||||
=== Known limitation: no offline text labels
|
=== Offline text labels and color palette
|
||||||
|
|
||||||
The offline style only renders `protomaps-themes-base`'s non-label
|
Label rendering in MapLibre needs a "glyphs" server serving font PBF
|
||||||
layers (roads, buildings, land use, water — no place names or street
|
ranges (256 Unicode code points each); `data/offline.pmtiles`'s fields
|
||||||
labels). Label rendering in MapLibre needs a "glyphs" server serving
|
(`name`, `name:en`, `script`, ...) match what
|
||||||
font PBF ranges, which would mean vendoring a font glyph set locally
|
`protomaps-themes-base`'s `layers(source, theme, { lang: "en" })`
|
||||||
too; that has not been done, to keep the initial scope manageable.
|
expects for its label layers (verified against the actual PMTiles
|
||||||
Revisit this if labelled offline maps turn out to matter in practice.
|
vector layer schema), so passing that option turns labels on. The
|
||||||
|
glyphs themselves are vendored under `public/vendor/fonts/` — Noto
|
||||||
|
Sans Regular/Italic/Medium, ranges `0-255` and `256-511`
|
||||||
|
(Basic Latin + Latin-1 Supplement + Latin Extended-A, SIL OFL
|
||||||
|
licensed, from
|
||||||
|
https://github.com/protomaps/basemaps-assets[protomaps/basemaps-assets]),
|
||||||
|
covering accented Latin place names (Slovak, Czech, Polish, German,
|
||||||
|
...). Labels in other scripts (Cyrillic, Greek, CJK, ...) won't render
|
||||||
|
offline, since those glyph ranges aren't vendored.
|
||||||
|
|
||||||
|
`public/js/map.js`'s `OFFLINE_THEME` also nudges a handful of color
|
||||||
|
roles (background, water, wood, buildings, the two road-importance
|
||||||
|
tiers) from `protomaps-themes-base`'s stock "light" theme towards the
|
||||||
|
online "liberty" style's actual palette (sampled from its style JSON),
|
||||||
|
so Online/Offline don't look like two different apps. This is
|
||||||
|
deliberately partial — most roles (labels, casings, minor terrain
|
||||||
|
fills, ...) are left at their theme defaults — not the kind of
|
||||||
|
full per-layer recolor a previous iteration of this app did (and
|
||||||
|
removed, along with any dependency on OsmAnd's own tile server, which
|
||||||
|
this app cannot use per OsmAnd's terms restricting tile use to "personal,
|
||||||
|
non-commercial use within OsmAnd applications and platforms").
|
||||||
|
|
||||||
No PMTiles file ships with the repository — it is expected to be
|
No PMTiles file ships with the repository — it is expected to be
|
||||||
supplied locally (see `docs/development.adoc`) and stays gitignored
|
supplied locally (see `docs/development.adoc`) and stays gitignored
|
||||||
because such extracts are typically large binary files.
|
because such extracts are typically large binary files.
|
||||||
|
|
||||||
=== Visual style
|
|
||||||
|
|
||||||
Both styles are recolored, by `public/js/osmand-style.js`, to
|
|
||||||
approximate the look of https://osmand.net/map[OsmAnd's own web map]
|
|
||||||
(cream background, green forests, orange roads, purple admin
|
|
||||||
boundaries) — deliberately *not* by using OsmAnd's tile server
|
|
||||||
directly: its terms restrict tile use to "personal, non-commercial use
|
|
||||||
within OsmAnd applications and platforms", which this app isn't.
|
|
||||||
|
|
||||||
One shared color palette drives two independent recolorings:
|
|
||||||
|
|
||||||
* *Online*: `onlineStyle()` fetches OpenFreeMap's raw "liberty" style
|
|
||||||
JSON and patches `paint` colors on its layers in place — matching a
|
|
||||||
layer to a category (water, wood, park, landuse, building, major/
|
|
||||||
minor road, boundary) by its id, then walking that layer's color
|
|
||||||
properties (`background-color`, `fill-color`, `line-color`,
|
|
||||||
`fill-extrusion-color`, and any `*-outline-color`) and replacing
|
|
||||||
every color-shaped leaf — including inside `interpolate`/other
|
|
||||||
expressions — with the category's palette color, leaving non-color
|
|
||||||
leaves (operators, zoom stops, `["get", ...]`) untouched. Labels and
|
|
||||||
railways are left at their original colors — only categorized layer
|
|
||||||
types (`background`/`fill`/`line`/`fill-extrusion`) are touched at
|
|
||||||
all, so `symbol` layers (all labels/icons) are never in scope.
|
|
||||||
Result is cached after the first fetch.
|
|
||||||
* *Offline*: `offlineTheme()` overrides the relevant color roles on a
|
|
||||||
`protomaps-themes-base` `Theme` object (starting from
|
|
||||||
`namedTheme("light")`), leaving roles it doesn't set (labels — moot,
|
|
||||||
see above — rail, tunnels, POI colors) at their defaults.
|
|
||||||
|
|
||||||
=== Known limitation: coarser road colors offline
|
|
||||||
|
|
||||||
protomaps-themes-base's `Theme` only has two paint-relevant road tiers
|
|
||||||
(`major` / `minor_a`+`minor_b`, plus `link` for ramps) versus
|
|
||||||
OpenFreeMap's finer-grained classes (`road_motorway`,
|
|
||||||
`road_trunk_primary`, `road_secondary_tertiary`, `road_minor`, ...).
|
|
||||||
Mapping `major` to the palette's road-major orange colors more roads
|
|
||||||
orange offline than online (protomaps' "major" bucket is broader than
|
|
||||||
just motorway/trunk/primary) — a real difference in how coarse the two
|
|
||||||
underlying style systems are, not a bug in the recoloring itself.
|
|
||||||
|
|
||||||
== Weather radar overlay
|
== Weather radar overlay
|
||||||
|
|
||||||
`public/js/radar.js` adds a "Radar" map control that overlays recent
|
`public/js/radar.js` adds a "Radar" map control that overlays recent
|
||||||
|
|||||||
@@ -23,6 +23,20 @@ BSD-3-Clause licensed.
|
|||||||
| https://github.com/protomaps/basemaps
|
| https://github.com/protomaps/basemaps
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
Offline map text labels need font glyphs too (see
|
||||||
|
`docs/architecture.adoc`), vendored under `public/vendor/fonts/` —
|
||||||
|
SIL Open Font License, not BSD-3-Clause like the above:
|
||||||
|
|
||||||
|
[cols="1,2"]
|
||||||
|
|===
|
||||||
|
| Asset | Source
|
||||||
|
|
||||||
|
| Noto Sans Regular/Italic/Medium glyph PBFs (ranges `0-255`,
|
||||||
|
`256-511` only)
|
||||||
|
| https://github.com/protomaps/basemaps-assets[protomaps/basemaps-assets]
|
||||||
|
(`fonts/`, `OFL.txt` included alongside)
|
||||||
|
|===
|
||||||
|
|
||||||
The online map style (not vendored, fetched at runtime when the
|
The online map style (not vendored, fetched at runtime when the
|
||||||
"Online" layer is selected) is
|
"Online" layer is selected) is
|
||||||
https://tiles.openfreemap.org/styles/liberty[OpenFreeMap "liberty"],
|
https://tiles.openfreemap.org/styles/liberty[OpenFreeMap "liberty"],
|
||||||
|
|||||||
+28
-8
@@ -7,24 +7,41 @@ import {
|
|||||||
import { RadarControl } from "/js/radar.js";
|
import { RadarControl } from "/js/radar.js";
|
||||||
import { GpxPanelControl } from "/js/gpx.js";
|
import { GpxPanelControl } from "/js/gpx.js";
|
||||||
import { GnssControl } from "/js/gnss.js";
|
import { GnssControl } from "/js/gnss.js";
|
||||||
import { onlineStyle, offlineTheme } from "/js/osmand-style.js";
|
|
||||||
import { LAYERS_ICON } from "/js/icons.js";
|
import { LAYERS_ICON } from "/js/icons.js";
|
||||||
import { notifySidePanelOpen, onlyOneSidePanelOpen } from "/js/panels.js";
|
import { notifySidePanelOpen, onlyOneSidePanelOpen } from "/js/panels.js";
|
||||||
|
|
||||||
const CENTER = [17.1077, 48.1486];
|
const CENTER = [17.1077, 48.1486];
|
||||||
const ZOOM = 13;
|
const ZOOM = 13;
|
||||||
|
const ONLINE_STYLE = "https://tiles.openfreemap.org/styles/liberty";
|
||||||
|
|
||||||
const protocol = new pmtiles.Protocol();
|
const protocol = new pmtiles.Protocol();
|
||||||
addProtocol("pmtiles", protocol.tile);
|
addProtocol("pmtiles", protocol.tile);
|
||||||
|
|
||||||
// No label layers here (see docs/architecture.adoc): rendering text needs a
|
// A few color roles nudged from protomaps-themes-base's stock "light" theme
|
||||||
// glyphs server, which the offline style deliberately does not depend on.
|
// towards the online OpenFreeMap "liberty" style's actual palette (sampled
|
||||||
|
// from its style JSON — see docs/architecture.adoc), so switching between
|
||||||
|
// Online/Offline doesn't look like two different apps. Not a full recolor:
|
||||||
|
// most roles (labels, casings, minor terrain fills, ...) are left at their
|
||||||
|
// theme defaults.
|
||||||
|
const OFFLINE_THEME = {
|
||||||
|
...protomaps_themes_base.namedTheme("light"),
|
||||||
|
background: "#f8f4f0",
|
||||||
|
earth: "#f8f4f0",
|
||||||
|
water: "#9ebdff",
|
||||||
|
wood_a: "#ace38c",
|
||||||
|
wood_b: "#ace38c",
|
||||||
|
buildings: "#dcd9d6",
|
||||||
|
highway: "#f2934a",
|
||||||
|
major: "#ffeeaa",
|
||||||
|
link: "#ffeeaa",
|
||||||
|
};
|
||||||
|
|
||||||
function offlineStyle() {
|
function offlineStyle() {
|
||||||
const theme = offlineTheme(protomaps_themes_base.namedTheme("light"));
|
|
||||||
const pmtilesUrl = `${window.location.origin}/tiles/offline.pmtiles`;
|
const pmtilesUrl = `${window.location.origin}/tiles/offline.pmtiles`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
version: 8,
|
version: 8,
|
||||||
|
glyphs: `${window.location.origin}/vendor/fonts/{fontstack}/{range}.pbf`,
|
||||||
sources: {
|
sources: {
|
||||||
offline: {
|
offline: {
|
||||||
type: "vector",
|
type: "vector",
|
||||||
@@ -32,7 +49,10 @@ function offlineStyle() {
|
|||||||
attribution: "© OpenStreetMap contributors",
|
attribution: "© OpenStreetMap contributors",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
layers: protomaps_themes_base.layers("offline", theme),
|
// lang: "en" pulls in labels_layers (see docs/architecture.adoc) — only
|
||||||
|
// the Latin-script glyph ranges are vendored, so labels using other
|
||||||
|
// scripts won't render offline.
|
||||||
|
layers: protomaps_themes_base.layers("offline", OFFLINE_THEME, { lang: "en" }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +103,7 @@ class LayerToggleControl {
|
|||||||
|
|
||||||
const map = new MaplibreMap({
|
const map = new MaplibreMap({
|
||||||
container: "map",
|
container: "map",
|
||||||
style: await onlineStyle(),
|
style: ONLINE_STYLE,
|
||||||
center: CENTER,
|
center: CENTER,
|
||||||
zoom: ZOOM,
|
zoom: ZOOM,
|
||||||
});
|
});
|
||||||
@@ -108,9 +128,9 @@ new GpxPanelControl(map).mount(sidebar);
|
|||||||
new RadarControl(map).mount(sidebar);
|
new RadarControl(map).mount(sidebar);
|
||||||
new GnssControl(map).mount(sidebar);
|
new GnssControl(map).mount(sidebar);
|
||||||
|
|
||||||
async function applyStyle(name) {
|
function applyStyle(name) {
|
||||||
layerToggle.setActive(name);
|
layerToggle.setActive(name);
|
||||||
map.setStyle(name === "offline" ? offlineStyle() : await onlineStyle());
|
map.setStyle(name === "offline" ? offlineStyle() : ONLINE_STYLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a local PMTiles file is present, prefer it as the default style — its
|
// If a local PMTiles file is present, prefer it as the default style — its
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
// Approximates the look of OsmAnd's own map render (osmand.net/map — muted
|
|
||||||
// earth tones, cream background, orange roads) without depending on their
|
|
||||||
// tile server: OsmAnd's terms restrict tile use to "personal, non-commercial
|
|
||||||
// use within OsmAnd applications and platforms", which this app isn't.
|
|
||||||
//
|
|
||||||
// One shared palette drives two independent recolorings so Online and
|
|
||||||
// Offline look consistent: OpenFreeMap's "liberty" vector style (paint
|
|
||||||
// colors patched in place, see recolorLayer) for Online, and a custom
|
|
||||||
// protomaps-themes-base Theme (see offlineTheme) for Offline.
|
|
||||||
|
|
||||||
const PALETTE = {
|
|
||||||
background: "#f1ecd7",
|
|
||||||
water: "#aad3df",
|
|
||||||
wood: "#c8dfb0",
|
|
||||||
park: "#d3e8b8",
|
|
||||||
landuse: "#ece4c6",
|
|
||||||
building: "#d9cead",
|
|
||||||
buildingOutline: "#c7bb92",
|
|
||||||
roadMajor: "#eb9d43",
|
|
||||||
roadMajorCasing: "#c9822c",
|
|
||||||
roadMinor: "#fdf8ee",
|
|
||||||
roadMinorCasing: "#cfc09a",
|
|
||||||
boundary: "#a98fc2",
|
|
||||||
};
|
|
||||||
|
|
||||||
const LIBERTY_STYLE_URL = "https://tiles.openfreemap.org/styles/liberty";
|
|
||||||
let cachedOnlineStyle = null;
|
|
||||||
|
|
||||||
// Fetches OpenFreeMap's "liberty" style and recolors it in place. Cached —
|
|
||||||
// the recoloring is pure, and re-fetching on every Online/Offline toggle
|
|
||||||
// would be wasteful.
|
|
||||||
export async function onlineStyle() {
|
|
||||||
if (cachedOnlineStyle) return cachedOnlineStyle;
|
|
||||||
|
|
||||||
const response = await fetch(LIBERTY_STYLE_URL);
|
|
||||||
const style = await response.json();
|
|
||||||
style.layers = style.layers.map(recolorLayer);
|
|
||||||
cachedOnlineStyle = style;
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overrides the color roles that define the "look" on top of a
|
|
||||||
// protomaps-themes-base Theme (e.g. namedTheme("light")), leaving roles it
|
|
||||||
// doesn't set (labels, rail, tunnels, POI colors) at their defaults.
|
|
||||||
export function offlineTheme(baseTheme) {
|
|
||||||
return {
|
|
||||||
...baseTheme,
|
|
||||||
background: PALETTE.background,
|
|
||||||
earth: PALETTE.background,
|
|
||||||
water: PALETTE.water,
|
|
||||||
wood_a: PALETTE.wood,
|
|
||||||
wood_b: PALETTE.wood,
|
|
||||||
park_a: PALETTE.park,
|
|
||||||
park_b: PALETTE.park,
|
|
||||||
scrub_a: PALETTE.park,
|
|
||||||
scrub_b: PALETTE.park,
|
|
||||||
pedestrian: PALETTE.landuse,
|
|
||||||
industrial: PALETTE.landuse,
|
|
||||||
school: PALETTE.landuse,
|
|
||||||
hospital: PALETTE.landuse,
|
|
||||||
buildings: PALETTE.building,
|
|
||||||
highway_casing_early: PALETTE.roadMajorCasing,
|
|
||||||
highway_casing_late: PALETTE.roadMajorCasing,
|
|
||||||
highway: PALETTE.roadMajor,
|
|
||||||
major_casing_early: PALETTE.roadMajorCasing,
|
|
||||||
major_casing_late: PALETTE.roadMajorCasing,
|
|
||||||
major: PALETTE.roadMajor,
|
|
||||||
link_casing: PALETTE.roadMajorCasing,
|
|
||||||
link: PALETTE.roadMajor,
|
|
||||||
minor_casing: PALETTE.roadMinorCasing,
|
|
||||||
minor_service_casing: PALETTE.roadMinorCasing,
|
|
||||||
minor_a: PALETTE.roadMinor,
|
|
||||||
minor_b: PALETTE.roadMinor,
|
|
||||||
other: PALETTE.roadMinor,
|
|
||||||
minor_service: PALETTE.roadMinor,
|
|
||||||
boundaries: PALETTE.boundary,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const FILL_PROP = /^(background-color|fill-color|line-color|fill-extrusion-color)$/;
|
|
||||||
const OUTLINE_PROP = /outline-color$/;
|
|
||||||
|
|
||||||
const FILL_COLOR = {
|
|
||||||
background: PALETTE.background,
|
|
||||||
water: PALETTE.water,
|
|
||||||
wood: PALETTE.wood,
|
|
||||||
park: PALETTE.park,
|
|
||||||
landuse: PALETTE.landuse,
|
|
||||||
building: PALETTE.building,
|
|
||||||
roadMajor: PALETTE.roadMajor,
|
|
||||||
roadMinor: PALETTE.roadMinor,
|
|
||||||
boundary: PALETTE.boundary,
|
|
||||||
};
|
|
||||||
|
|
||||||
const OUTLINE_COLOR = {
|
|
||||||
building: PALETTE.buildingOutline,
|
|
||||||
roadMajor: PALETTE.roadMajorCasing,
|
|
||||||
roadMinor: PALETTE.roadMinorCasing,
|
|
||||||
park: "#bcdb9a",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Maps a "liberty" style layer id to one of the categories above, based on
|
|
||||||
// the id naming conventions OpenFreeMap's style uses (verified against its
|
|
||||||
// actual layer list — see docs/architecture.adoc). Returns null for
|
|
||||||
// anything left at its original color: labels/icons (all "symbol" layers,
|
|
||||||
// filtered by type below before this even runs), railways, and minor
|
|
||||||
// terrain fills (ice/wetland/sand) that aren't part of OsmAnd's signature
|
|
||||||
// look.
|
|
||||||
function categoryFor(layerId) {
|
|
||||||
if (layerId === "background") return "background";
|
|
||||||
if (/rail/.test(layerId)) return null;
|
|
||||||
if (/^water/.test(layerId)) return "water";
|
|
||||||
if (/^landcover_wood/.test(layerId)) return "wood";
|
|
||||||
if (/^(park|landcover_grass)/.test(layerId)) return "park";
|
|
||||||
if (/^landuse/.test(layerId)) return "landuse";
|
|
||||||
if (/^building/.test(layerId)) return "building";
|
|
||||||
if (/^(road|bridge|tunnel)_(motorway|trunk_primary)/.test(layerId)) return "roadMajor";
|
|
||||||
if (/^(road|bridge|tunnel)_/.test(layerId)) return "roadMinor";
|
|
||||||
if (/^boundary/.test(layerId)) return "boundary";
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RECOLORABLE_TYPES = new Set(["background", "fill", "line", "fill-extrusion"]);
|
|
||||||
|
|
||||||
function recolorLayer(layer) {
|
|
||||||
if (!RECOLORABLE_TYPES.has(layer.type) || !layer.paint) return layer;
|
|
||||||
|
|
||||||
const category = categoryFor(layer.id);
|
|
||||||
if (!category) return layer;
|
|
||||||
|
|
||||||
const paint = { ...layer.paint };
|
|
||||||
for (const [prop, value] of Object.entries(paint)) {
|
|
||||||
if (OUTLINE_PROP.test(prop) && OUTLINE_COLOR[category]) {
|
|
||||||
paint[prop] = replaceColors(value, OUTLINE_COLOR[category]);
|
|
||||||
} else if (FILL_PROP.test(prop)) {
|
|
||||||
paint[prop] = replaceColors(value, FILL_COLOR[category]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ...layer, paint };
|
|
||||||
}
|
|
||||||
|
|
||||||
const COLOR_PATTERN = /^#[0-9a-f]{3,8}$/i;
|
|
||||||
const COLOR_FN_PATTERN = /^(rgb|hsl)a?\(/i;
|
|
||||||
|
|
||||||
// Walks a paint value — a flat color string, or a MapLibre expression like
|
|
||||||
// ["interpolate", ["linear"], ["zoom"], 5, "hsl(26,87%,62%)", 6, "#fc8"] —
|
|
||||||
// and swaps every color-shaped string for `newColor`, leaving operators,
|
|
||||||
// zoom/get references and numbers untouched. Generic across expression
|
|
||||||
// types (interpolate/match/case/step/...) since it never inspects the
|
|
||||||
// expression's operator, only whether each leaf looks like a color.
|
|
||||||
function replaceColors(value, newColor) {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
return COLOR_PATTERN.test(value) || COLOR_FN_PATTERN.test(value) ? newColor : value;
|
|
||||||
}
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
return value.map((item) => replaceColors(item, newColor));
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Vendored
+93
@@ -0,0 +1,93 @@
|
|||||||
|
Copyright 2022 The Noto Project Authors (https://github.com/notofonts)
|
||||||
|
|
||||||
|
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://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
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.
|
||||||
Reference in new issue
Block a user