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)
|
getFontInfo(styleName)
|
||||||
.then((info) => {
|
.then((info) => {
|
||||||
if (cancelled) return;
|
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) {
|
if (canvas && canvasRef.current) {
|
||||||
canvasRef.current.width = canvas.width;
|
canvasRef.current.width = canvas.width;
|
||||||
canvasRef.current.height = canvas.height;
|
canvasRef.current.height = canvas.height;
|
||||||
@@ -108,7 +108,7 @@ export default function LogoGenerator() {
|
|||||||
for (const font of allFonts) {
|
for (const font of allFonts) {
|
||||||
try {
|
try {
|
||||||
const info = await getFontInfo(font.styleName);
|
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; }
|
if (!canvas) { fail++; continue; }
|
||||||
const blob = await new Promise<Blob | null>((r) => canvas.toBlob((b) => r(b), "image/png"));
|
const blob = await new Promise<Blob | null>((r) => canvas.toBlob((b) => r(b), "image/png"));
|
||||||
if (blob) folder.file(`${font.styleName}.png`, blob);
|
if (blob) folder.file(`${font.styleName}.png`, blob);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ interface CharInfo {
|
|||||||
w: number;
|
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 {
|
function hexPixel(data: Uint8ClampedArray, x: number, y: number, w: number): number {
|
||||||
const i = (y * w + x) * 4;
|
const i = (y * w + x) * 4;
|
||||||
@@ -49,7 +49,7 @@ function scanCharWidths(data: Uint8ClampedArray, sw: number, sh: number): CharIn
|
|||||||
return chars;
|
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);
|
const cached = fontCache.get(font);
|
||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
|
|
||||||
@@ -83,20 +83,22 @@ export async function getFontInfo(font: string): Promise<{ chars: CharInfo[]; h:
|
|||||||
}
|
}
|
||||||
const h = bottom - top + 1;
|
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);
|
fontCache.set(font, result);
|
||||||
return 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]));
|
const map = new Map(chars.map((c) => [c.char, c]));
|
||||||
let totalW = 0;
|
let totalW = 0;
|
||||||
for (const ch of text.toLowerCase()) {
|
for (const ch of text.toLowerCase()) {
|
||||||
if (ch === " ") {
|
if (ch === " ") {
|
||||||
totalW += spaceW;
|
totalW += avgW;
|
||||||
} else {
|
} else {
|
||||||
const info = map.get(ch);
|
const info = map.get(ch);
|
||||||
totalW += info?.w ?? spaceW;
|
totalW += info?.w ?? avgW;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { totalW };
|
return { totalW };
|
||||||
@@ -105,9 +107,10 @@ export function measureText(chars: CharInfo[], h: number, text: string, spaceW:
|
|||||||
export function renderToCanvas(
|
export function renderToCanvas(
|
||||||
chars: CharInfo[],
|
chars: CharInfo[],
|
||||||
h: number,
|
h: number,
|
||||||
|
top: number,
|
||||||
sheet: HTMLImageElement,
|
sheet: HTMLImageElement,
|
||||||
text: string,
|
text: string,
|
||||||
spaceW: number,
|
avgW: number,
|
||||||
dpr = 1,
|
dpr = 1,
|
||||||
): HTMLCanvasElement | null {
|
): HTMLCanvasElement | null {
|
||||||
const map = new Map(chars.map((c) => [c.char, c]));
|
const map = new Map(chars.map((c) => [c.char, c]));
|
||||||
@@ -115,7 +118,7 @@ export function renderToCanvas(
|
|||||||
|
|
||||||
let totalW = 0;
|
let totalW = 0;
|
||||||
for (const ch of safeText) {
|
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;
|
if (totalW === 0) return null;
|
||||||
@@ -130,14 +133,14 @@ export function renderToCanvas(
|
|||||||
let x = 0;
|
let x = 0;
|
||||||
for (const ch of safeText) {
|
for (const ch of safeText) {
|
||||||
if (ch === " ") {
|
if (ch === " ") {
|
||||||
x += spaceW;
|
x += avgW;
|
||||||
} else {
|
} else {
|
||||||
const info = map.get(ch);
|
const info = map.get(ch);
|
||||||
if (info) {
|
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;
|
x += info.w;
|
||||||
} else {
|
} else {
|
||||||
x += spaceW;
|
x += avgW;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user