Update images
This commit is contained in:
@@ -1,22 +1,31 @@
|
||||
"""Generate a markdown font preview page and images for SD font families."""
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import yaml
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent / 'assets' / 'sd-fonts'
|
||||
OUTPUT_DIR = Path(__file__).resolve().parent.parent / 'docs' / 'images' / 'sd-font-previews'
|
||||
MD_PATH = Path(__file__).resolve().parent.parent / 'docs' / 'sd-fonts-preview.md'
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
ROOT = REPO_ROOT / 'assets' / 'sd-fonts'
|
||||
OUTPUT_DIR = REPO_ROOT / 'docs' / 'images' / 'sd-font-previews'
|
||||
MD_PATH = REPO_ROOT / 'docs' / 'sd-fonts-preview.md'
|
||||
YAML_PATH = REPO_ROOT / 'lib' / 'EpdFont' / 'scripts' / 'sd-fonts.yaml'
|
||||
CACHE_DIR = Path(__file__).resolve().parent / 'font-cache'
|
||||
SAMPLE_TEXT = 'Everyone has the right to freedom of thought...'
|
||||
DEFAULT_FONT_SIZE = 28
|
||||
IMAGE_SIZE = (1080, 220)
|
||||
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
try:
|
||||
font = ImageFont.truetype('arial.ttf', DEFAULT_FONT_SIZE)
|
||||
except Exception:
|
||||
font = ImageFont.load_default()
|
||||
with YAML_PATH.open('r', encoding='utf-8') as yaml_file:
|
||||
manifest = yaml.safe_load(yaml_file)
|
||||
|
||||
family_map = {family['name']: family for family in manifest['families']}
|
||||
|
||||
families = [p.name for p in sorted(ROOT.iterdir()) if p.is_dir()]
|
||||
|
||||
lines = [
|
||||
'# SD Font Preview',
|
||||
'',
|
||||
@@ -26,11 +35,65 @@ lines = [
|
||||
'|---|---|',
|
||||
]
|
||||
|
||||
|
||||
def download_font(url: str, cache_dir: Path) -> Path:
|
||||
parsed = urllib.parse.urlparse(url)
|
||||
filename = Path(parsed.path).name
|
||||
output_path = cache_dir / filename
|
||||
if not output_path.exists():
|
||||
print(f'Downloading {url}...')
|
||||
urllib.request.urlretrieve(url, output_path)
|
||||
return output_path
|
||||
|
||||
|
||||
def resolve_instanced_font_path(family_name: str, style_name: str) -> Optional[Path]:
|
||||
instanced_dir = REPO_ROOT / 'lib' / 'EpdFont' / 'scripts' / 'instanced_fonts' / family_name
|
||||
if not instanced_dir.exists():
|
||||
return None
|
||||
matches = sorted(instanced_dir.glob(f'{style_name}*.ttf'))
|
||||
return matches[0] if matches else None
|
||||
|
||||
|
||||
def resolve_font_path(family_name: str) -> Optional[Path]:
|
||||
family = family_map.get(family_name)
|
||||
if family is None:
|
||||
return None
|
||||
|
||||
styles = family.get('styles', {})
|
||||
regular = styles.get('regular') or next(iter(styles.values()), None)
|
||||
if regular is None:
|
||||
return None
|
||||
|
||||
if 'path' in regular:
|
||||
local_path = REPO_ROOT / 'lib' / 'EpdFont' / regular['path']
|
||||
if local_path.exists():
|
||||
return local_path
|
||||
|
||||
instanced = resolve_instanced_font_path(family_name, 'regular')
|
||||
if instanced is not None:
|
||||
return instanced
|
||||
|
||||
if 'url' in regular:
|
||||
return download_font(regular['url'], CACHE_DIR)
|
||||
return None
|
||||
|
||||
|
||||
for family in families:
|
||||
font_path = resolve_font_path(family)
|
||||
try:
|
||||
if font_path is None:
|
||||
raise FileNotFoundError('No source font found')
|
||||
font = ImageFont.truetype(str(font_path), DEFAULT_FONT_SIZE)
|
||||
except Exception as exc:
|
||||
print(f'Warning: unable to load font for {family}: {exc}. Falling back to default font.')
|
||||
font = ImageFont.load_default()
|
||||
|
||||
text = f'{family} - {SAMPLE_TEXT}'
|
||||
image = Image.new('RGB', IMAGE_SIZE, color=(255, 255, 255))
|
||||
draw = ImageDraw.Draw(image)
|
||||
text_width, text_height = draw.textsize(text, font=font)
|
||||
bbox = draw.textbbox((0, 0), text, font=font)
|
||||
text_width = bbox[2] - bbox[0]
|
||||
text_height = bbox[3] - bbox[1]
|
||||
x = 20
|
||||
y = (IMAGE_SIZE[1] - text_height) // 2
|
||||
draw.text((x, y), text, fill='black', font=font)
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6297ef3a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# SD Font Preview Generation\n",
|
||||
"\n",
|
||||
"This notebook scans `./assets/sd-fonts`, generates preview images for each available SD font family, and creates a markdown listing page that embeds those images."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "adfac037",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from pathlib import Path\n",
|
||||
"from PIL import Image, ImageDraw, ImageFont\n",
|
||||
"from IPython.display import display, Markdown, Image as DisplayImage\n",
|
||||
"\n",
|
||||
"root_dir = Path('assets/sd-fonts')\n",
|
||||
"output_image_dir = Path('docs/images/sd-font-previews')\n",
|
||||
"output_image_dir.mkdir(parents=True, exist_ok=True)\n",
|
||||
"output_markdown_path = Path('docs/sd-fonts-preview.md')\n",
|
||||
"\n",
|
||||
"print(f'Root font directory: {root_dir.resolve()}')\n",
|
||||
"print(f'Preview image output directory: {output_image_dir.resolve()}')\n",
|
||||
"print(f'Markdown output path: {output_markdown_path.resolve()}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "305e0f28",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Discover available font families\n",
|
||||
"font_families = [p.name for p in sorted(root_dir.iterdir()) if p.is_dir()]\n",
|
||||
"print(f'Found {len(font_families)} font families:')\n",
|
||||
"for family in font_families:\n",
|
||||
" print(f' - {family}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5771f18f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sample_text = 'Everyone has the right to freedom of thought...'\n",
|
||||
"preview_texts = {family: f'{family} - {sample_text}' for family in font_families}\n",
|
||||
"\n",
|
||||
"for family, text in preview_texts.items():\n",
|
||||
" print(f'{family}: {text}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "86bf3966",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Render and save preview images\n",
|
||||
"font_size = 28\n",
|
||||
"try:\n",
|
||||
" default_font = ImageFont.truetype('arial.ttf', font_size)\n",
|
||||
"except Exception:\n",
|
||||
" default_font = ImageFont.load_default()\n",
|
||||
"\n",
|
||||
"image_width = 1080\n",
|
||||
"image_height = 220\n",
|
||||
"\n",
|
||||
"for family, text in preview_texts.items():\n",
|
||||
" image = Image.new('RGB', (image_width, image_height), 'white')\n",
|
||||
" draw = ImageDraw.Draw(image)\n",
|
||||
" text_width, text_height = draw.textsize(text, font=default_font)\n",
|
||||
" x = 20\n",
|
||||
" y = (image_height - text_height) // 2\n",
|
||||
" draw.text((x, y), text, fill='black', font=default_font)\n",
|
||||
" output_path = output_image_dir / f'{family}.png'\n",
|
||||
" image.save(output_path)\n",
|
||||
" print(f'Saved {output_path}')\n",
|
||||
"\n",
|
||||
"print('All preview images generated.')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d5636615",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Generate markdown listing with embedded preview images\n",
|
||||
"lines = [\n",
|
||||
" '# SD Font Preview',\n",
|
||||
" '',\n",
|
||||
" 'This page lists the available SD font families under `assets/sd-fonts` and embeds rendered preview images for each family.',\n",
|
||||
" '',\n",
|
||||
" '| Font Family | Preview |',\n",
|
||||
" '|---|---|',\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"for family in font_families:\n",
|
||||
" image_rel_path = f'images/sd-font-previews/{family}.png'\n",
|
||||
" lines.append(f'| {family} |  |')\n",
|
||||
"\n",
|
||||
"output_markdown_path.write_text('\\n'.join(lines) + '\\n', encoding='utf-8')\n",
|
||||
"print(f'Generated markdown page at {output_markdown_path}')\n",
|
||||
"\n",
|
||||
"# Display a preview of the generated markdown in the notebook\n",
|
||||
"display(Markdown('\\n'.join(lines[:8]) + '\\n...'))"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b9bce3b3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# SD Font Preview Generation\n",
|
||||
"\n",
|
||||
"This notebook scans `./assets/sd-fonts`, generates preview images for each available SD font family, and creates a markdown listing page that embeds those images."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "30e78310",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "NameError",
|
||||
"evalue": "name '__file__' is not defined",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
|
||||
"\u001b[31mNameError\u001b[39m Traceback (most recent call last)",
|
||||
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[9]\u001b[39m\u001b[32m, line 15\u001b[39m\n\u001b[32m 13\u001b[39m output_markdown_path = repo_root / \u001b[33m'\u001b[39m\u001b[33mdocs\u001b[39m\u001b[33m'\u001b[39m / \u001b[33m'\u001b[39m\u001b[33msd-fonts-preview.md\u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m 14\u001b[39m manifest_path = repo_root / \u001b[33m'\u001b[39m\u001b[33mlib\u001b[39m\u001b[33m'\u001b[39m / \u001b[33m'\u001b[39m\u001b[33mEpdFont\u001b[39m\u001b[33m'\u001b[39m / \u001b[33m'\u001b[39m\u001b[33mscripts\u001b[39m\u001b[33m'\u001b[39m / \u001b[33m'\u001b[39m\u001b[33msd-fonts.yaml\u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m---> \u001b[39m\u001b[32m15\u001b[39m cache_dir = Path(\u001b[34;43m__file__\u001b[39;49m).resolve().parent / \u001b[33m'\u001b[39m\u001b[33mfont-cache\u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m 16\u001b[39m cache_dir.mkdir(parents=\u001b[38;5;28;01mTrue\u001b[39;00m, exist_ok=\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[32m 18\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m manifest_path.open(\u001b[33m'\u001b[39m\u001b[33mr\u001b[39m\u001b[33m'\u001b[39m, encoding=\u001b[33m'\u001b[39m\u001b[33mutf-8\u001b[39m\u001b[33m'\u001b[39m) \u001b[38;5;28;01mas\u001b[39;00m manifest_file:\n",
|
||||
"\u001b[31mNameError\u001b[39m: name '__file__' is not defined"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import urllib.request\n",
|
||||
"import urllib.parse\n",
|
||||
"from pathlib import Path\n",
|
||||
"from typing import Optional\n",
|
||||
"from PIL import Image, ImageDraw, ImageFont\n",
|
||||
"from IPython.display import display, Markdown\n",
|
||||
"import yaml\n",
|
||||
"\n",
|
||||
"repo_root = Path.cwd().resolve().parent\n",
|
||||
"root_dir = repo_root / 'assets' / 'sd-fonts'\n",
|
||||
"output_image_dir = repo_root / 'docs' / 'images' / 'sd-font-previews'\n",
|
||||
"output_image_dir.mkdir(parents=True, exist_ok=True)\n",
|
||||
"output_markdown_path = repo_root / 'docs' / 'sd-fonts-preview.md'\n",
|
||||
"manifest_path = repo_root / 'lib' / 'EpdFont' / 'scripts' / 'sd-fonts.yaml'\n",
|
||||
"cache_dir = repo_root / 'scripts' / 'font-cache'\n",
|
||||
"cache_dir.mkdir(parents=True, exist_ok=True)\n",
|
||||
"\n",
|
||||
"with manifest_path.open('r', encoding='utf-8') as manifest_file:\n",
|
||||
" manifest = yaml.safe_load(manifest_file)\n",
|
||||
"\n",
|
||||
"family_map = {family['name']: family for family in manifest['families']}\n",
|
||||
"\n",
|
||||
"print(f'Repo root: {repo_root}')\n",
|
||||
"print(f'Root font directory: {root_dir.resolve()}')\n",
|
||||
"print(f'Preview image output directory: {output_image_dir.resolve()}')\n",
|
||||
"print(f'Markdown output path: {output_markdown_path.resolve()}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "217146fe",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Found 23 font families:\n",
|
||||
" - Alegreya\n",
|
||||
" - Arimo\n",
|
||||
" - AtkinsonHyperlegibleNext\n",
|
||||
" - Bitter\n",
|
||||
" - Gelasio\n",
|
||||
" - GentiumBookPlus\n",
|
||||
" - IBMPlexMono\n",
|
||||
" - IBMPlexSans\n",
|
||||
" - IBMPlexSerif\n",
|
||||
" - Inter\n",
|
||||
" - LexicaUltralegible\n",
|
||||
" - Literata\n",
|
||||
" - Lora\n",
|
||||
" - Merriweather\n",
|
||||
" - NotoSansExtended\n",
|
||||
" - NotoSerifExtended\n",
|
||||
" - OpenDyslexic\n",
|
||||
" - Readerly\n",
|
||||
" - SourceCodePro\n",
|
||||
" - SourceSans3\n",
|
||||
" - SourceSerif4\n",
|
||||
" - Spectral\n",
|
||||
" - Vollkorn\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ename": "NameError",
|
||||
"evalue": "name 'Optional' is not defined",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
|
||||
"\u001b[31mNameError\u001b[39m Traceback (most recent call last)",
|
||||
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[8]\u001b[39m\u001b[32m, line 18\u001b[39m\n\u001b[32m 14\u001b[39m urllib.request.urlretrieve(url, local_path)\n\u001b[32m 15\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m local_path\n\u001b[32m---> \u001b[39m\u001b[32m18\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mresolve_instanced_font_path\u001b[39m(family_name: \u001b[38;5;28mstr\u001b[39m, style_name: \u001b[38;5;28mstr\u001b[39m) -> \u001b[43mOptional\u001b[49m[Path]:\n\u001b[32m 19\u001b[39m instanced_dir = repo_root / \u001b[33m'\u001b[39m\u001b[33mlib\u001b[39m\u001b[33m'\u001b[39m / \u001b[33m'\u001b[39m\u001b[33mEpdFont\u001b[39m\u001b[33m'\u001b[39m / \u001b[33m'\u001b[39m\u001b[33mscripts\u001b[39m\u001b[33m'\u001b[39m / \u001b[33m'\u001b[39m\u001b[33minstanced_fonts\u001b[39m\u001b[33m'\u001b[39m / family_name\n\u001b[32m 20\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m instanced_dir.exists():\n",
|
||||
"\u001b[31mNameError\u001b[39m: name 'Optional' is not defined"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Discover available font families\n",
|
||||
"font_families = [p.name for p in sorted(root_dir.iterdir()) if p.is_dir()]\n",
|
||||
"print(f'Found {len(font_families)} font families:')\n",
|
||||
"for family in font_families:\n",
|
||||
" print(f' - {family}')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def download_font(url: str, cache_dir: Path) -> Path:\n",
|
||||
" parsed = urllib.parse.urlparse(url)\n",
|
||||
" filename = Path(parsed.path).name\n",
|
||||
" local_path = cache_dir / filename\n",
|
||||
" if not local_path.exists():\n",
|
||||
" print(f'Downloading {url}...')\n",
|
||||
" urllib.request.urlretrieve(url, local_path)\n",
|
||||
" return local_path\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def resolve_instanced_font_path(family_name: str, style_name: str) -> Optional[Path]:\n",
|
||||
" instanced_dir = repo_root / 'lib' / 'EpdFont' / 'scripts' / 'instanced_fonts' / family_name\n",
|
||||
" if not instanced_dir.exists():\n",
|
||||
" return None\n",
|
||||
" matches = sorted(instanced_dir.glob(f'{style_name}*.ttf'))\n",
|
||||
" return matches[0] if matches else None\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def resolve_font_path(family_name: str) -> Optional[Path]:\n",
|
||||
" family = family_map.get(family_name)\n",
|
||||
" if family is None:\n",
|
||||
" return None\n",
|
||||
" styles = family.get('styles', {})\n",
|
||||
" style = styles.get('regular') or next(iter(styles.values()), None)\n",
|
||||
" if style is None:\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
" if 'path' in style:\n",
|
||||
" local_path = repo_root / 'lib' / 'EpdFont' / style['path']\n",
|
||||
" if local_path.exists():\n",
|
||||
" return local_path\n",
|
||||
"\n",
|
||||
" instanced = resolve_instanced_font_path(family_name, 'regular')\n",
|
||||
" if instanced is not None:\n",
|
||||
" return instanced\n",
|
||||
"\n",
|
||||
" if 'url' in style:\n",
|
||||
" return download_font(style['url'], cache_dir)\n",
|
||||
" return None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "a0843a3e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Alegreya: Alegreya - Everyone has the right to freedom of thought...\n",
|
||||
"Arimo: Arimo - Everyone has the right to freedom of thought...\n",
|
||||
"AtkinsonHyperlegibleNext: AtkinsonHyperlegibleNext - Everyone has the right to freedom of thought...\n",
|
||||
"Bitter: Bitter - Everyone has the right to freedom of thought...\n",
|
||||
"Gelasio: Gelasio - Everyone has the right to freedom of thought...\n",
|
||||
"GentiumBookPlus: GentiumBookPlus - Everyone has the right to freedom of thought...\n",
|
||||
"IBMPlexMono: IBMPlexMono - Everyone has the right to freedom of thought...\n",
|
||||
"IBMPlexSans: IBMPlexSans - Everyone has the right to freedom of thought...\n",
|
||||
"IBMPlexSerif: IBMPlexSerif - Everyone has the right to freedom of thought...\n",
|
||||
"Inter: Inter - Everyone has the right to freedom of thought...\n",
|
||||
"LexicaUltralegible: LexicaUltralegible - Everyone has the right to freedom of thought...\n",
|
||||
"Literata: Literata - Everyone has the right to freedom of thought...\n",
|
||||
"Lora: Lora - Everyone has the right to freedom of thought...\n",
|
||||
"Merriweather: Merriweather - Everyone has the right to freedom of thought...\n",
|
||||
"NotoSansExtended: NotoSansExtended - Everyone has the right to freedom of thought...\n",
|
||||
"NotoSerifExtended: NotoSerifExtended - Everyone has the right to freedom of thought...\n",
|
||||
"OpenDyslexic: OpenDyslexic - Everyone has the right to freedom of thought...\n",
|
||||
"Readerly: Readerly - Everyone has the right to freedom of thought...\n",
|
||||
"SourceCodePro: SourceCodePro - Everyone has the right to freedom of thought...\n",
|
||||
"SourceSans3: SourceSans3 - Everyone has the right to freedom of thought...\n",
|
||||
"SourceSerif4: SourceSerif4 - Everyone has the right to freedom of thought...\n",
|
||||
"Spectral: Spectral - Everyone has the right to freedom of thought...\n",
|
||||
"Vollkorn: Vollkorn - Everyone has the right to freedom of thought...\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"sample_text = 'Everyone has the right to freedom of thought...'\n",
|
||||
"preview_texts = {family: f'{family} - {sample_text}' for family in font_families}\n",
|
||||
"\n",
|
||||
"for family, text in preview_texts.items():\n",
|
||||
" print(f'{family}: {text}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "e23a6728",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Alegreya.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Arimo.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\AtkinsonHyperlegibleNext.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Bitter.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Gelasio.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\GentiumBookPlus.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\IBMPlexMono.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\IBMPlexSans.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\IBMPlexSerif.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Inter.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\LexicaUltralegible.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Literata.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Lora.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Merriweather.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\NotoSansExtended.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\NotoSerifExtended.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\OpenDyslexic.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Readerly.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\SourceCodePro.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\SourceSans3.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\SourceSerif4.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Spectral.png\n",
|
||||
"Saved C:\\_development\\crosspoint-reader\\docs\\images\\sd-font-previews\\Vollkorn.png\n",
|
||||
"All preview images generated.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Render and save preview images\n",
|
||||
"font_size = 28\n",
|
||||
"image_width = 1080\n",
|
||||
"image_height = 220\n",
|
||||
"\n",
|
||||
"for family, text in preview_texts.items():\n",
|
||||
" font_path = resolve_font_path(family)\n",
|
||||
" try:\n",
|
||||
" if font_path is None:\n",
|
||||
" raise FileNotFoundError('No source font path available')\n",
|
||||
" font = ImageFont.truetype(str(font_path), font_size)\n",
|
||||
" except Exception as exc:\n",
|
||||
" print(f'Warning: could not load {family} from {font_path}: {exc}')\n",
|
||||
" font = ImageFont.load_default()\n",
|
||||
"\n",
|
||||
" image = Image.new('RGB', (image_width, image_height), 'white')\n",
|
||||
" draw = ImageDraw.Draw(image)\n",
|
||||
" bbox = draw.textbbox((0, 0), text, font=font)\n",
|
||||
" text_width = bbox[2] - bbox[0]\n",
|
||||
" text_height = bbox[3] - bbox[1]\n",
|
||||
" x = 20\n",
|
||||
" y = (image_height - text_height) // 2\n",
|
||||
" draw.text((x, y), text, fill='black', font=font)\n",
|
||||
" output_path = output_image_dir / f'{family}.png'\n",
|
||||
" image.save(output_path)\n",
|
||||
" print(f'Saved {output_path}')\n",
|
||||
"\n",
|
||||
"print('All preview images generated.')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "7d53f4f2",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Generated markdown page at C:\\_development\\crosspoint-reader\\docs\\sd-fonts-preview.md\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/markdown": [
|
||||
"# SD Font Preview\n",
|
||||
"\n",
|
||||
"This page lists the available SD font families under `assets/sd-fonts` and embeds rendered preview images for each family.\n",
|
||||
"\n",
|
||||
"| Font Family | Preview |\n",
|
||||
"|---|---|\n",
|
||||
"| Alegreya |  |\n",
|
||||
"| Arimo |  |\n",
|
||||
"..."
|
||||
],
|
||||
"text/plain": [
|
||||
"<IPython.core.display.Markdown object>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Generate markdown listing with embedded preview images\n",
|
||||
"lines = [\n",
|
||||
" '# SD Font Preview',\n",
|
||||
" '',\n",
|
||||
" 'This page lists the available SD font families under `assets/sd-fonts` and embeds rendered preview images for each family.',\n",
|
||||
" '',\n",
|
||||
" '| Font Family | Preview |',\n",
|
||||
" '|---|---|',\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"for family in font_families:\n",
|
||||
" image_rel_path = f'images/sd-font-previews/{family}.png'\n",
|
||||
" lines.append(f'| {family} |  |')\n",
|
||||
"\n",
|
||||
"output_markdown_path.write_text('\\n'.join(lines) + '\\n', encoding='utf-8')\n",
|
||||
"print(f'Generated markdown page at {output_markdown_path}')\n",
|
||||
"\n",
|
||||
"# Display a preview of the generated markdown in the notebook\n",
|
||||
"display(Markdown('\\n'.join(lines[:8]) + '\\n...'))"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user