fix: correct sprite font vertical offset and use avg char width fallback
This commit is contained in:
1 parent
77ae4838c0
commit
a1950e5b65
5 files changed
+16
-13
No files matched your search
BIN
Binary file not shown.
|
After Width: | Height: | Size: 156 B |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 191 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
@@ -47,7 +47,7 @@ export default function LogoGenerator() {
|
||||
getFontInfo(styleName)
|
||||
.then((info) => {
|
||||
if (cancelled) return;
|
||||
const canvas = renderToCanvas(info.chars, info.h, info.sheet, safeText, 12);
|
||||
const canvas = renderToCanvas(info.chars, info.h, info.top, info.sheet, safeText, info.avgW);
|
||||
if (canvas && canvasRef.current) {
|
||||
canvasRef.current.width = canvas.width;
|
||||
canvasRef.current.height = canvas.height;
|
||||
@@ -108,7 +108,7 @@ export default function LogoGenerator() {
|
||||
for (const font of allFonts) {
|
||||
try {
|
||||
const info = await getFontInfo(font.styleName);
|
||||
const canvas = renderToCanvas(info.chars, info.h, info.sheet, safeText, 12);
|
||||
const canvas = renderToCanvas(info.chars, info.h, info.top, info.sheet, safeText, info.avgW);
|
||||
if (!canvas) { fail++; continue; }
|
||||
const blob = await new Promise<Blob | null>((r) => canvas.toBlob((b) => r(b), "image/png"));
|
||||
if (blob) folder.file(`${font.styleName}.png`, blob);
|
||||
|
||||
@@ -6,7 +6,7 @@ interface CharInfo {
|
||||
w: number;
|
||||
}
|
||||
|
||||
const fontCache = new Map<string, { chars: CharInfo[]; h: number; sheet: HTMLImageElement }>();
|
||||
const fontCache = new Map<string, { chars: CharInfo[]; h: number; top: number; sheet: HTMLImageElement; avgW: number }>();
|
||||
|
||||
function hexPixel(data: Uint8ClampedArray, x: number, y: number, w: number): number {
|
||||
const i = (y * w + x) * 4;
|
||||
@@ -49,7 +49,7 @@ function scanCharWidths(data: Uint8ClampedArray, sw: number, sh: number): CharIn
|
||||
return chars;
|
||||
}
|
||||
|
||||
export async function getFontInfo(font: string): Promise<{ chars: CharInfo[]; h: number; sheet: HTMLImageElement }> {
|
||||
export async function getFontInfo(font: string): Promise<{ chars: CharInfo[]; h: number; top: number; sheet: HTMLImageElement; avgW: number }> {
|
||||
const cached = fontCache.get(font);
|
||||
if (cached) return cached;
|
||||
|
||||
@@ -83,20 +83,22 @@ export async function getFontInfo(font: string): Promise<{ chars: CharInfo[]; h:
|
||||
}
|
||||
const h = bottom - top + 1;
|
||||
|
||||
const result = { chars, h, sheet: img };
|
||||
const avgW = chars.length > 0 ? Math.round(chars.reduce((s, c) => s + c.w, 0) / chars.length) : 12;
|
||||
|
||||
const result = { chars, h, top, sheet: img, avgW };
|
||||
fontCache.set(font, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function measureText(chars: CharInfo[], h: number, text: string, spaceW: number): { totalW: number } {
|
||||
export function measureText(chars: CharInfo[], text: string, avgW: number): { totalW: number } {
|
||||
const map = new Map(chars.map((c) => [c.char, c]));
|
||||
let totalW = 0;
|
||||
for (const ch of text.toLowerCase()) {
|
||||
if (ch === " ") {
|
||||
totalW += spaceW;
|
||||
totalW += avgW;
|
||||
} else {
|
||||
const info = map.get(ch);
|
||||
totalW += info?.w ?? spaceW;
|
||||
totalW += info?.w ?? avgW;
|
||||
}
|
||||
}
|
||||
return { totalW };
|
||||
@@ -105,9 +107,10 @@ export function measureText(chars: CharInfo[], h: number, text: string, spaceW:
|
||||
export function renderToCanvas(
|
||||
chars: CharInfo[],
|
||||
h: number,
|
||||
top: number,
|
||||
sheet: HTMLImageElement,
|
||||
text: string,
|
||||
spaceW: number,
|
||||
avgW: number,
|
||||
dpr = 1,
|
||||
): HTMLCanvasElement | null {
|
||||
const map = new Map(chars.map((c) => [c.char, c]));
|
||||
@@ -115,7 +118,7 @@ export function renderToCanvas(
|
||||
|
||||
let totalW = 0;
|
||||
for (const ch of safeText) {
|
||||
totalW += ch === " " ? spaceW : (map.get(ch)?.w ?? spaceW);
|
||||
totalW += ch === " " ? avgW : (map.get(ch)?.w ?? avgW);
|
||||
}
|
||||
|
||||
if (totalW === 0) return null;
|
||||
@@ -130,14 +133,14 @@ export function renderToCanvas(
|
||||
let x = 0;
|
||||
for (const ch of safeText) {
|
||||
if (ch === " ") {
|
||||
x += spaceW;
|
||||
x += avgW;
|
||||
} else {
|
||||
const info = map.get(ch);
|
||||
if (info) {
|
||||
ctx.drawImage(sheet, info.x, 0, info.w, sheet.naturalHeight, x, 0, info.w, h);
|
||||
ctx.drawImage(sheet, info.x, top, info.w, h, x, 0, info.w, h);
|
||||
x += info.w;
|
||||
} else {
|
||||
x += spaceW;
|
||||
x += avgW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user