From d1d92930f8554c9ff9a6aa199cc2b429fd171958 Mon Sep 17 00:00:00 2001 From: "B. Stack" Date: Sun, 4 Apr 2021 22:29:18 -0400 Subject: add support for fonts inline in css as url data: The handler parses the first data value and has support for only one exact entry, but it can be adapted for more. --- savewebfonts_lib.py | 111 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 39 deletions(-) (limited to 'savewebfonts_lib.py') diff --git a/savewebfonts_lib.py b/savewebfonts_lib.py index 53615c1..b0a6f30 100755 --- a/savewebfonts_lib.py +++ b/savewebfonts_lib.py @@ -17,7 +17,7 @@ # req-devuan: python3-bs4, python3-tinycss2 # rec-devuan: python3-fonttools, eot2ttf -import requests, os, json, tempfile, subprocess +import requests, os, json, tempfile, subprocess, base64 from sys import stderr from bs4 import BeautifulSoup as bs # python3-beautifulsoup4 from urllib.parse import urljoin, urlparse @@ -138,61 +138,88 @@ def save_font(url,destdir,config): filename="" filename=os.path.basename(urlparse(url).path) ext = os.path.splitext(filename)[-1] + tf = None # Do not try to convert .svg if config.convert and not filename.endswith(".ttf") and ext not in [".svg"]: need_convert = True orig_filename = filename # in case we cannot load library later filename = ttfify_filename(filename) + + if url.startswith("data:"): + if url.startswith("data:application/x-font-woff;charset=utf-8;base64,"): + need_convert = True + ext = ".woff" + tf = tempfile.NamedTemporaryFile() + contents = url[len("data:application/x-font-woff;charset=utf-8;base64,"):] # no worries about dryrun; we have already downloaded the font contents which are inline in the css file itself. + tf.write(base64.b64decode(contents)) + filename = ttfify_filename(contents[:20]) + filepath = os.path.join(destdir, filename) if not os.path.exists(filepath): if url.startswith("data:"): - # not supported! - # WORKHERE: support saving to a tempfile this datastream, probably a base64encoded woff file. Then just convert. - eprint(f"Warning: Url {url[:config.MAX_STRING_PRINT_LENGTH]} is unsupported.") - else: - if not config.dryrun: - # Download content - response = config.session.get(url) + # Yes, some repetition here. + if url.startswith("data:application/x-font-woff;charset=utf-8;base64,"): + pass + else: + # not supported yet! + eprint(f"Warning: Url {url[:config.MAX_STRING_PRINT_LENGTH]} is unsupported.") + return -1 + if not config.dryrun: + if tf: + with open(tf.name,'rb') as otf: + file_contents = otf.read() + else: + # Download content + response = config.session.get(url) if 'Content-Disposition' in response.headers: filename=response.headers['Content-Disposition'] eprint(f"Using content-disposition value of {response.headers['Content-Disposition']}") if need_convert and not filename.endswith(".ttf"): orig_filename = filename # in case we cannot load library later filename = ttfify_filename(filename) - filepath = os.path.join(destdir, filename) - - try: - if config.debuglevel >= 1: - sstring = "Saving" if not config.dryrun else "Save" - eprint(f"{sstring} {url} to file {filepath}") - if not config.dryrun: - if not need_convert: - with open(filepath,'wb') as thisfile: - thisfile.write(response.content) + file_contents = response.content + + filepath = os.path.join(destdir, filename) + #try: + if True: + if config.debuglevel >= 1: + sstring = "Saving" if not config.dryrun else "Save" + eprint(f"{sstring} {url[:config.MAX_STRING_PRINT_LENGTH]} to file {filepath}") + if not config.dryrun: + if not need_convert: + with open(filepath,'wb') as thisfile: + thisfile.write(file_contents) + else: + # need_convert is true, and not dryrun, so call function + if ext in [".woff",".woff2"]: + try: + from fontTools import ttLib + except Exception as e: + raise e + convert_in = url + if tf: + convert_in = tf.name + convert_woffwoff2_ttf(convert_in,filepath,config=config) + elif ext in [".eot"]: + convert_eot_ttf(url,filepath,config=config) else: - # need_convert is true, and not dryrun, so call function - if ext in [".woff",".woff2"]: - try: - from fontTools import ttLib - except Exception as e: - raise e - convert_woffwoff2_ttf(url,filepath,config=config) - elif ext in [".eot"]: - convert_eot_ttf(url,filepath,config=config) - else: - # no plan for conversion! - eprint(f"Warning: no conversion plan for ext {ext} of {url}. Saving as-is.") - with open(filepath,'wb') as thisfile: - thisfile.write(response.content) - return 0 - except Exception as E: - eprint(f"Error when downloading {url}, {E}") - return -1 + # no plan for conversion! + eprint(f"Warning: no conversion plan for ext {ext} of {url[:config.MAX_STRING_PRINT_LENGTH]}. Saving as-is.") + with open(filepath,'wb') as thisfile: + thisfile.write(file_contents) + if tf: tf.close() + return 0 + #except Exception as E: + # eprint(f"Error when downloading {url}, {E}") + # if tf: tf.close() + # return -1 + if tf: tf.close() else: # filepath does exist if config.debuglevel >= 2: - eprint(f"File {filepath} exists for {url}. Skipping.") + eprint(f"File {filepath} exists for {url[:config.MAX_STRING_PRINT_LENGTH]}. Skipping.") + if tf: tf.close() return 0 def get_all_fonts_from_csslist(all_css, config): @@ -294,7 +321,13 @@ def convert_woffwoff2_ttf(url, filename, config): Save the given url to filename, with filetype ttf """ # This will only be called from save_font when dryrun=False, so the dryrun flag here is useful only if called from some other usage. - response = config.session.get(url) + if (url.startswith("http://") or url.startswith("https://") or url.startswith("ftp://")): + response = config.session.get(url) + file_contents = response.content + else: + # assume local file + with open(url,'rb') as o: + file_contents = o.read() try: from fontTools import ttLib except ModuleNotFoundError: @@ -304,7 +337,7 @@ def convert_woffwoff2_ttf(url, filename, config): raise e with tempfile.TemporaryFile() as tf: - tf.write(response.content) + tf.write(file_contents) font = ttLib.TTFont(tf) if config.debuglevel >= 3: eprint(f"Converting {url[:config.MAX_STRING_PRINT_LENGTH]} from {font.flavor} to ttf as file {filename}") -- cgit