Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize downloading webfonts #37

Open
vinaynb opened this issue Jun 3, 2016 · 19 comments · May be fixed by #92
Open

Optimize downloading webfonts #37

vinaynb opened this issue Jun 3, 2016 · 19 comments · May be fixed by #92

Comments

@vinaynb
Copy link

vinaynb commented Jun 3, 2016

Hello ,

I am having lots of fonts in my app and while generating png image there are many ajax calls for getting these font files from the server. As i need to support many browsers hence there are font's in different formats and right now for a single image to be generated from DOM, the count for fetching fonts goes above 100.

Due to browser trying to fetch so many fonts, it freezes for a while when generating image. Is there any way by which i can reduce these downloads or supply those fonts in some way so that we need not tell browser to fetch it exclusively again as they are already fetched ?

@tsayen tsayen added the question label Jun 5, 2016
@tsayen
Copy link
Owner

tsayen commented Jun 5, 2016

Hi. Well, there is currently no setting that would limit external resources downloading. The library by itself is not so intelligent - it does not check whether the font declared via @font-face is really used in the node you're going to render, it just gets all the fonts. It also doesn't currently "prefer" any concrete font format (like WOFF or sth) - since it doesn't really know which of those fromats are supported by current browser.

I can imagine adding a setting like "do not embed fonts", or also "embed only woff format for fonts" (that also might change the appearance of the result) - but that is currently not the case.

@vinaynb
Copy link
Author

vinaynb commented Jun 6, 2016

So maybe we can try making the library intelligent to check if the fonts declared via @font-face are already loaded in the node we wish to render. I'd be happy to work on a pull request. A bit of direction as to where should i start would be helpful.

@tsayen
Copy link
Owner

tsayen commented Jun 6, 2016

One more thought: I would suppose that browser itself caches the fonts - so
what you see as an XHR to get the font file may be just a browser cache
hit, and no actual download happens. Did you maybe check for that?

On Mon, Jun 6, 2016 at 6:57 AM, Vinay Bhinde notifications@github.com
wrote:

So maybe we can try making the library intelligent to check if the fonts
declared via @font-face https://github.com/font-face are already loaded
in the node we wish to render. I'd be happy to work on a pull request. A
bit of direction as to where should i start would be helpful.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#37 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/ABpydLOyxMKvY34-x68qSid0o5lNbp-4ks5qI6iogaJpZM4IteGw
.

@tsayen
Copy link
Owner

tsayen commented Jun 6, 2016

You might be bypassing the cache, if you have font URLs like described here
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache

Solution that would not require changes to the lib would just be using font
URLs that cause cache hits.

On Mon, Jun 6, 2016 at 7:26 AM, Anatoly Sayenko anatoly.sayenko@gmail.com
wrote:

One more thought: I would suppose that browser itself caches the fonts -
so what you see as an XHR to get the font file may be just a browser cache
hit, and no actual download happens. Did you maybe check for that?

On Mon, Jun 6, 2016 at 6:57 AM, Vinay Bhinde notifications@github.com
wrote:

So maybe we can try making the library intelligent to check if the fonts
declared via @font-face https://github.com/font-face are already
loaded in the node we wish to render. I'd be happy to work on a pull
request. A bit of direction as to where should i start would be helpful.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#37 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/ABpydLOyxMKvY34-x68qSid0o5lNbp-4ks5qI6iogaJpZM4IteGw
.

@vinaynb
Copy link
Author

vinaynb commented Jun 7, 2016

Yes i am hitting the cache and the font is not actually downloaded from the server so we are fine on that front. But i found another issue while checking this. What's happening is that each font file format is loaded 9 times !

This is not normal so there something wrong with this. How does the lib go about loading fonts it finds @font-face definition for ? If i can fix this i can reduce a lot of requests.

@tsayen
Copy link
Owner

tsayen commented Aug 25, 2016

I'll check whether adding a font cache would fix anything (each file will be downloaded still, but once)

@tsayen tsayen self-assigned this Aug 25, 2016
@swampthang
Copy link

Hi, I am working on a desktop application where I'll never need the fonts because all the data that needs to be rendered comes from inline SVGs. Is there an easy way to completely bypass the embedFonts calls?

@tsayen
Copy link
Owner

tsayen commented Sep 9, 2016

Hi. If you don't have web fonts in your CSS, then there will be no network
calls made to fetch them. Same with images: if all of them are data URLs,
then you're fine too.

On Fri, Sep 9, 2016 at 2:25 PM, Carvel Avis notifications@github.com
wrote:

Hi, I am working on a desktop application where I'll never need the fonts
because all the data that needs to be rendered comes from inline SVGs. Is
there an easy way to completely bypass the embedFonts calls?


You are receiving this because you were assigned.
Reply to this email directly, view it on GitHub
#37 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABpydJrn3EfRlJT2bgEbqpL4ghtiiK80ks5qoVAqgaJpZM4IteGw
.

@swampthang
Copy link

swampthang commented Sep 9, 2016

Oh, I should have been more specific. And by the way, yours is the only script I've found that will do what I need. Thanks so much for making it available!

This is an Electron app so it's all html, js and css. I do have one .woff file but it's local and doesn't apply to anything in the dom (div) element I'm trying to render.

All that will ever be in that dom are multiple SVGs. It's capturing some rather heavy SVG animations at anywhere from 30-60 FPS (set by the user), converting to PNG sequence, then using FFMPEG to export them out to various formats - MP4, GIF or MOV file.

Animations can be as long as a couple of minutes or more so I need to do anything possible to reduce the time it takes to parse through the animations. I notice that your script (in order to preserve transparency) has to parse through every node of every SVG in the DOM. I'd be willing to pay for some help with this.

@swampthang
Copy link

For now I've commented out the call to that function and it seems to be working ok.

function toSvg(node, options) {
    options = options || {};
    return Promise.resolve(node)
        .then(function (node) {
            return cloneNode(node, options.filter, true);
        })
        // .then(embedFonts)
        .then(inlineImages)
        .then(applyOptions)

@tsayen
Copy link
Owner

tsayen commented Sep 9, 2016

OK, I see. The thing is that this lib might not be the right tool for the job. It is more for "make a page screenshot once in a while" kind of stuff. You might be much better off with directly rendering your SVG on canvas and grabbing image data from it, like described here and here.

This lib has to get all the web fonts it sees on the page, cause it cannot predict whether particular font is used in the node you're trying to render (OK, it theoretically could, but it's not implemented).

@tsayen
Copy link
Owner

tsayen commented Sep 9, 2016

I can imagine some kind of option like embedFonts that toggles this piece of code you've commented out (and it even makes some kind of sense), but still, you might want to consider rendering your SVGs directly, because in your case using this lib might add almost no value (at least it looks to me like that).

@swampthang
Copy link

Yea, I see what you mean. The only thing is, there are multiple SVGs in the dom element wrapped by a div. I wonder if it would be a good idea to create a master SVG and embed all the others in it.

@ragamufin
Copy link

+1 on an option to only load fonts being used in the node being made into an image

@tsayen tsayen changed the title How can i reduce or maybe stop network calls for loading fonts ? Optimize downloading webfonts Sep 25, 2016
@kumarsai
Copy link

kumarsai commented Jan 3, 2017

I got the same issue, every time its calling same Font URL.
so I did below changes, it may help you.

`var URLWithResponce = [];// copy this line near global variables 
        function getAndEncode(url) { // replace getAndEncode with this function
            var TIMEOUT = 30000;
            var _url = url.split('?')[0];
            var _obj;
            _obj = $.grep(URLWithResponce, function (e) { return e.url == _url; });
            if (_obj.length == 0) {
                console.log(_url);
                var prom = new Promise(function (resolve) {
                    var request = new XMLHttpRequest();
                    request.onreadystatechange = done;
                    request.ontimeout = timeout;
                    request.responseType = 'blob';
                    request.timeout = TIMEOUT;
                    request.open('GET', url, true);
                    request.send();
                    function done() {
                        if (request.readyState !== 4) return;
                        if (request.status !== 200) {
                            fail('cannot fetch resource: ' + url + ', status: ' + request.status);
                            return;
                        }
                        var encoder = new FileReader();
                        encoder.onloadend = function () {
                            var content = encoder.result.split(/,/)[1];
                            resolve(content);
                        };
                        encoder.readAsDataURL(request.response);
                    }
                    function timeout() {
                        fail('timeout of ' + TIMEOUT + 'ms occured while fetching resource: ' + url);
                    }
                    function fail(message) {
                        console.error(message);
                        resolve('');
                    }
                });
                _obj = {
                    url: _url,
                    prom: prom
                };
                URLWithResponce.push(_obj);
                _obj.prom;
            }
            else
            return _obj[0].prom;
            // }
        }
`

jdforsythe added a commit to jdforsythe/dom-to-image that referenced this issue Jan 12, 2017
@jdforsythe jdforsythe linked a pull request Jan 12, 2017 that will close this issue
@tctimmeh
Copy link

tctimmeh commented Jan 4, 2018

Any plans to fix this issue? I've got an app that is trying to generate several hundred images and it takes a very long time due to repeatedly loading fonts.

I'll check whether adding a font cache would fix anything (each file will be downloaded still, but once)

A font cache would work great for my case. Redownloading all the fonts once isn't a huge deal and would cut my total task time down to almost nothing I think.

@kachkaev
Copy link

kachkaev commented Mar 12, 2019

@tsayen would you be happy to accept a PR that calls .then(embedFonts) conditionally based on an new option? It could be called skipEmbedFonts. Meanwhile, we have to rely on a temporary fork of your awesome library.


UPD: Seems the PR is out there already: #92

@svigelj
Copy link

svigelj commented Apr 7, 2020

Hi. I have added a small check that tracks which resources were already downloaded and simply skips if a resources wants to be downloaded again. It worked for my use case but didn't do any extensive testing.

See the small code changes here. svigelj@487c431

@chihiro888
Copy link

chihiro888 commented Oct 12, 2020

we don't have to request for unnecessary fonts

   function getAndEncode(url) {
        var TIMEOUT = 30000;
        if(domtoimage.impl.options.cacheBust) {
            // Cache bypass so we dont have CORS issues with cached images
            // Source: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache
            url += ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime();
        }

        console.log('url = ', url)

        // font bug fix
        let lock = 1;

        if (url.search('YES24GothicR.woff') != -1) {
            lock = 0;
        }
        if (url.search('YES24.woff') != -1) {
            lock = 0;
        }
        if (url.search('YES24MyoungjoR.woff') != -1) {
            lock = 0;
        }
        if (url.search('image') != -1) {
            lock = 0;
        }

        if (lock == 1) {
            return ;
        }

        return new Promise(function (resolve) {
            var request = new XMLHttpRequest();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
dom-to-image
In Progress
Development

Successfully merging a pull request may close this issue.

9 participants