Skip to content

Commit fc4f0cd

Browse files
committed
fix: renderTxt2ImgBitmap width/height maybe incorrect when custom fontFamily
1 parent 697fc57 commit fc4f0cd

File tree

4 files changed

+49
-9
lines changed

4 files changed

+49
-9
lines changed

.changeset/loud-taxes-obey.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@webav/av-cliper': patch
3+
---
4+
5+
fix: renderTxt2ImgBitmap width/height maybe incorrect when custom fontFamily
44.9 KB
Binary file not shown.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { expect, it } from 'vitest';
2+
import { renderTxt2ImgBitmap } from '../dom-utils';
3+
4+
it('renderTxt2ImgBitmap with custon font', async () => {
5+
const cssText =
6+
'font-size: 32px; font-family: Sedan SC; opacity: 1; line-height: 1; padding: 0; margin: 0;max-width: 100px; word-break: break-all; white-space: break-spaces;';
7+
const opts = {
8+
font: {
9+
name: 'Sedan SC',
10+
url: '/fonts/SedanSC-Regular.woff2',
11+
},
12+
};
13+
const img = await renderTxt2ImgBitmap('Hello World', cssText, opts);
14+
// 固定宽度 + 折行
15+
expect(img.width).toBe(100);
16+
expect(img.height).toBe(96);
17+
img.close();
18+
});

packages/av-cliper/src/dom-utils.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,32 @@ export async function renderTxt2Img(
3333
onCreated?: (el: HTMLElement) => void;
3434
} = {},
3535
): Promise<HTMLImageElement> {
36-
const div = createEl('pre');
37-
div.style.cssText = `margin: 0; ${cssText}; position: fixed;`;
38-
div.textContent = txt;
39-
document.body.appendChild(div);
40-
opts.onCreated?.(div);
36+
const preEl = createEl('pre');
37+
preEl.style.cssText = `margin: 0; ${cssText}; position: fixed;`;
38+
preEl.textContent = txt;
39+
document.body.appendChild(preEl);
40+
opts.onCreated?.(preEl);
4141

42-
const { width, height } = div.getBoundingClientRect();
42+
// 避免重复覆盖其他字体他
43+
const tmpFontName = 'TMP_FONT_NAME_' + crypto.randomUUID();
44+
let fontFace: FontFace | null = null;
45+
// 等待字体加载完成后再计算尺寸
46+
if (opts.font != null) {
47+
preEl.style.fontFamily = tmpFontName;
48+
fontFace = new FontFace(tmpFontName, `url(${opts.font.url})`);
49+
await fontFace.load();
50+
// @ts-expect-error https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/add
51+
document.fonts.add(fontFace);
52+
await document.fonts.ready;
53+
}
54+
55+
const { width, height } = preEl.getBoundingClientRect();
4356
// 计算出 rect,立即从dom移除
44-
div.remove();
57+
preEl.remove();
58+
if (fontFace != null) {
59+
// @ts-expect-error https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/delete
60+
document.fonts.delete(fontFace);
61+
}
4562

4663
const img = new Image();
4764
img.width = width;
@@ -51,7 +68,7 @@ export async function renderTxt2Img(
5168
? ''
5269
: `
5370
@font-face {
54-
font-family: '${opts.font.name}';
71+
font-family: '${tmpFontName}';
5572
src: url('data:font/woff2;base64,${arrayBufferToBase64(await (await fetch(opts.font.url)).arrayBuffer())}') format('woff2');
5673
}
5774
`;
@@ -61,7 +78,7 @@ export async function renderTxt2Img(
6178
${fontFaceStr}
6279
</style>
6380
<foreignObject width="100%" height="100%">
64-
<div xmlns="http://www.w3.org/1999/xhtml">${div.outerHTML}</div>
81+
<div xmlns="http://www.w3.org/1999/xhtml">${preEl.outerHTML}</div>
6582
</foreignObject>
6683
</svg>
6784
`

0 commit comments

Comments
 (0)