bubkoo / html-to-image

✂️ Generates an image from a DOM node using HTML5 canvas and SVG.
MIT License
5.4k stars 505 forks source link

Load specified fonts only instead of loading hundreds of fonts #405

Open myszkin81 opened 1 year ago

myszkin81 commented 1 year ago

Current state

html-to-image now calls for about 150 fonts on the first call, ten some more for ther second call. I only need 2 fonts to be downloaded.

Expected Behavior

I would like to specify the fonts I need and not to download any more fonts.

Possible Solution

Defining needed fonts in font.config file

vivcat[bot] commented 1 year ago

👋 @myszkin81

Thanks for opening your first issue here! If you're reporting a 🐞 bug, please make sure you include steps to reproduce it. To help make it easier for us to investigate your issue, please follow the contributing guidelines.

We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can.

mahmonirbkh commented 1 year ago

I have the same problem, it loads a lot of font assets and makes project very slow and laggy.

aadi-paypay commented 10 months ago

Same problem here as well.

Parth909 commented 5 months ago

@aadi-paypay , @mahmonirbkh , @myszkin81 How are you loading the fonts? Can you show us the code snippet that you are using to load the fonts

mahmonirbkh commented 5 months ago

@aadi-paypay , @mahmonirbkh , @myszkin81 How are you loading the fonts? Can you show us the code snippet that you are using to load the fonts

I use sass, so for loading fonts a mixin's been defined like below:

$fontpath2: '../assets/fonts';
$fontFolder2: 'inter';
$fontFamily2: 'Inter';
$fontWeights2: 100, 200, 300, 400, 500, 600, 700, 800, 900;
$fontExtension2: 'woff2';

@mixin fontface($folder2, $ffamily2, $fweight2, $fname2) {
    @font-face {
        @if $ffamily2 {
            font-family: $ffamily2;
        }

        @if $fweight2 {
            font-weight: $fweight2;
        }

        font-display: swap;
        font-style: normal;

        @if $folder2 {
            src: url('#{$fontpath2}/#{$folder2}/#{$fname2}.#{$fontExtension2}') format($fontExtension2);
        } @else {
            src: url('#{$fontpath2}/#{$fname2}.#{$fontExtension2}') format($fontExtension2);
        }
    }
}
Howlcn1997 commented 3 months ago

maybe you can use fontEmbedCSS to customize the fonts you want to load. first you need to find all font families in the target DOM yourself.

function findAllFontFamily(root: HTMLElement) {
  const familyList = new Set<string>()
  const queue: HTMLElement[] = [root]
  while (queue.length) {
    const node = queue.shift()
    if (!node) continue
    const styleValue = node?.attributes?.getNamedItem('style')?.value
    const fontFamilyMatch = styleValue?.match(/font-family:([^;]*)/)
    if (fontFamilyMatch && fontFamilyMatch[1]) {
      familyList .add(fontFamilyMatch[1].trim())
    }
    // const { fontFamily } = window.getComputedStyle(node)
    if (node.children) {
      queue.push(...node.children as any)
    }
  }
  return [ ...familyList ]
}

next

import { fetchAsDataURL } from 'html-to-image/src/dataurl'
import { toJpeg  } from 'html-to-image'

(async () => {
    const config: ExportImageConfig = {
      quality: 1,
      width: 1600
      }
      const embedFamilyList = findAllFontFamily(rootDom)
      const dataUrls = []
      for (const family of embedFamilyList) {
        const dataUrl:string = await fetchAsDataURL(`https://host.com/path/to/${family}.woff2`, {}, ({result}) => {
          return `
          @font-face {
            font-display: swap;
            font-family: ${family};
            src: url('${result}') format('woff2');
          }
          `
        })
        dataUrls.push(dataUrl)
      }
      config.fontEmbedCSS = dataUrls.join('')
      await toJpeg(rootDom, config)
})()

Here is an idea, not the complete code