def browser_previews(self, **kwargs): """Use GFR and diffbrowsers to take screenshots of how the fonts will look on different browsers. A Browserstack account is required.""" logger.info("Running browser previews") if not self._bstack_auth: logger.info("Skipping. No Browserstack credentials. " "See https://github.com/googlefonts/" "diffbrowsers#installation on how to add them.") return out = os.path.join(self.out, "browser_previews") mkdir(out) browsers_to_test = test_browsers["vf_browsers"] font_groups = self.chunkify( list([i['filename'] for i in self.instances.values()]), 4) name_groups = self.chunkify(list(self.instances.keys()), 4) for name_group, font_group in zip(name_groups, font_groups): name = "_".join(sorted(name_group)) diff_browsers = DiffBrowsers( auth=self._bstack_auth, gfr_instance_url=FontQA.GFR_URL, dst_dir=os.path.join(out, name), browsers=browsers_to_test, gfr_is_local=False, ) diff_browsers.new_session(font_group, font_group) diff_browsers.diff_view("waterfall", styles=name_group) diff_browsers.diff_view("glyphs_all", styles=name_group, pt=15)
def diffbrowsers(self, **kwargs): """Test fonts on GFR regression and take screenshots using diffbrowsers. A browserstack account is required.""" logger.info("Running Diffbrowsers") if not self._bstack_auth: logger.info("Skipping. No Browserstack credentials. " "See https://github.com/googlefonts/" "diffbrowsers#installation on how to add them.") return dst = os.path.join(self.out, "Diffbrowsers") mkdir(dst) browsers_to_test = test_browsers["vf_browsers"] fonts = [(k, self.instances_before[k]['filename'], self.instances[k]['filename']) for k in self.matching_instances] font_groups = self.chunkify(sorted(fonts), 4) for group in font_groups: styles = [i[0] for i in group] dir_name = "_".join(styles) fonts_before = [i[1] for i in group] fonts_after = [i[2] for i in group] out = os.path.join(dst, dir_name) diff_browsers = DiffBrowsers( auth=self._bstack_auth, gfr_instance_url=self.GFR_URL, dst_dir=out, browsers=browsers_to_test, ) diff_browsers.new_session(set(fonts_before), set(fonts_after)) diff_browsers.diff_view("waterfall", styles=styles) info = os.path.join(out, "info.json") json.dump(diff_browsers.stats, open(info, "w")) diff_browsers.diff_view("glyphs_all", pt=16, styles=styles)
def diffenator(self, **kwargs): logger.info("Running Diffenator") dst = os.path.join(self._out, "Diffenator") mkdir(dst) for style in self._shared_instances: font_before = DFont(self._instances_before[style]) font_after = DFont(self._instances[style]) out = os.path.join(dst, style) if font_after.is_variable and not font_before.is_variable: font_after.set_variations_from_static(font_before) elif not font_after.is_variable and font_before.is_variable: font_before.set_variations_from_static(font_after) elif font_after.is_variable and font_before.is_variable: # TODO get wdth and slnt axis vals variations = {"wght": font_before.ttfont["OS/2"].usWeightClass} font_after.set_variations(variations) font_before.set_variations(variations) # TODO add settings diff = DiffFonts(font_before, font_after, {"render_diffs": True}) diff.to_gifs(dst=out) diff.to_txt(20, os.path.join(out, "report.txt")) diff.to_md(20, os.path.join(out, "report.md")) diff.to_html(20, os.path.join(out, "report.html"), image_dir=".")
def diffenator(self, **kwargs): logger.info("Running Diffenator") dst = os.path.join(self.out, "Diffenator") mkdir(dst) for style in self.matching_instances: font_before = DFont(self.instances_before[style]['filename']) font_after = DFont(self.instances[style]['filename']) out = os.path.join(dst, style) if font_after.is_variable and not font_before.is_variable: font_after.set_variations_from_static(font_before) elif not font_after.is_variable and font_before.is_variable: font_before.set_variations_from_static(font_after) elif font_after.is_variable and font_before.is_variable: coordinates = self.instances_before[style]['coordinates'] font_after.set_variations(coordinates) font_before.set_variations(coordinates) # TODO add settings diff = DiffFonts(font_before, font_after, {"render_diffs": True}) diff.to_gifs(dst=out) diff.to_txt(20, os.path.join(out, "report.txt")) diff.to_md(20, os.path.join(out, "report.md")) diff.to_html(20, os.path.join(out, "report.html"), image_dir=".")
def fontbakery(self): logger.info("Running Fontbakery") out = os.path.join(self.out, "Fontbakery") mkdir(out) cmd = (["fontbakery", "check-googlefonts", "-l", "WARN"] + [f.reader.file.name for f in self.fonts] + ["-C"] + ["--ghmarkdown", os.path.join(out, "report.md")]) subprocess.call(cmd)
def __init__(self, fonts, fonts_before=None, out="out"): self._fonts = fonts self._instances = self.font_instances(self._fonts) self._fonts_before = fonts_before self._instances_before = self.font_instances(self._fonts_before) self._shared_instances = self._get_shared_instances() self._bstack_auth = load_browserstack_credentials() self._out = out mkdir(self._out)
def browser_previews(self, **kwargs): """Use GFR and diffbrowsers to take screenshots of how the fonts will look on different browsers. A Browserstack account is required.""" logger.info("Running browser previews") if not self._bstack_auth: logger.info("Skipping. No Browserstack credentials. " "See https://github.com/googlefonts/" "diffbrowsers#installation on how to add them.") return out = os.path.join(self.out, "browser_previews") mkdir(out) html = HtmlProof(out=out, fonts=[f.reader.file.name for f in self.fonts]) html.build_pages(["waterfall.html", "text.html"]) html.build_pages(["glyphs.html"], pt_size=16) html.save_imgs()
def plot_glyphs(self): logger.info("Running plot glyphs") out = os.path.join(self.out, "plot_glyphs") mkdir(out) fonts = [f.reader.file.name for f in self.fonts] for font in fonts: font_filename = os.path.basename(font)[:-4] dfont = DFont(font) if dfont.is_variable: for _, coords in dfont.instances_coordinates.items(): dfont.set_variations(coords) img_out = os.path.join( out, "%s_%s.png" % (font_filename, self._instance_coords_to_filename(coords)), ) dfont.glyphs.to_png(img_out, limit=100000) else: img_out = os.path.join(out, font_filename + ".png") dfont.glyphs.to_png(dst=img_out)
def diffbrowsers(self, **kwargs): """Test fonts on GFR regression and take screenshots using diffbrowsers. A browserstack account is required.""" logger.info("Running Diffbrowsers") if not self._bstack_auth: logger.info("Skipping. No Browserstack credentials. " "See https://github.com/googlefonts/" "diffbrowsers#installation on how to add them.") return dst = os.path.join(self.out, "Diffbrowsers") mkdir(dst) html = HtmlDiff( out=dst, fonts_before=[f.reader.file.name for f in self.fonts_before], fonts_after=[f.reader.file.name for f in self.fonts], ) html.build_pages(["waterfall.html", "text.html"]) html.build_pages(["glyphs.html"], pt_size=16) html.save_imgs()
def diffbrowsers(self, **kwargs): """Test fonts on GFR regression and take screenshots using diffbrowsers. A browserstack account is required.""" logger.info("Running Diffbrowsers") if not self._bstack_auth: logger.info("Skipping. No Browserstack credentials. " "See https://github.com/googlefonts/" "diffbrowsers#installation on how to add them.") return dst = os.path.join(self._out, "Diffbrowsers") mkdir(dst) browsers_to_test = test_browsers["vf_browsers"] fonts = sorted( [v for k, v in self._instances.items() if k in self._shared_instances] ) fonts_before = sorted( [ v for k, v in self._instances_before.items() if k in self._shared_instances ] ) fonts_before_groups = self.chunkify(fonts_before, 4) fonts_groups = self.chunkify(fonts, 4) name_groups = self.chunkify(sorted([k for k in self._shared_instances]), 4) for name_group, before, after in zip(name_groups, fonts_before_groups, fonts_groups): name = "_".join(name_group) out = os.path.join(dst, name) diff_browsers = DiffBrowsers( auth=self._bstack_auth, gfr_instance_url=self.GFR_URL, dst_dir=out, browsers=browsers_to_test, ) diff_browsers.new_session(set(before), set(after)) diff_browsers.diff_view("waterfall") info = os.path.join(out, "info.json") json.dump(diff_browsers.stats, open(info, "w")) diff_browsers.diff_view("glyphs_all", pt=16)
def main(): parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) font_group = parser.add_argument_group(title="Fonts to qa") font_input_group = font_group.add_mutually_exclusive_group(required=True) font_input_group.add_argument("-f", "--fonts", nargs="+", help="Paths to fonts") font_input_group.add_argument("-pr", "--pull-request", help="Get fonts from a Github pull request") font_input_group.add_argument("-gh", "--github-dir", help="Get fonts from a Github directory") font_input_group.add_argument("-gf", "--googlefonts", help="Get fonts from Google Fonts") font_before_group = parser.add_argument_group(title="Fonts before input") font_before_input_group = font_before_group.add_mutually_exclusive_group( required=False) font_before_input_group.add_argument("-fb", "--fonts-before", nargs="+", help="Paths to previous fonts") font_before_input_group.add_argument( "-prb", "--pull-request-before", help="Get previous fonts from a Github pull request") font_before_input_group.add_argument( "-ghb", "--github-dir-before", help="Get previous fonts from a Github dir") font_before_input_group.add_argument( "-gfb", "--googlefonts-before", action="store_true", help="Get previous fonts from Google Fonts", ) check_group = parser.add_argument_group(title="QA checks") check_group.add_argument( "-a", "--auto-qa", action="store_true", help= "Check fonts against against the same fonts hosted on Google Fonts", ) check_group.add_argument("--diffenator", action="store_true", help="Run Fontdiffenator") check_group.add_argument("--diffbrowsers", action="store_true", help="Run Diffbrowsers") check_group.add_argument("--fontbakery", action="store_true", help="Run FontBakery") check_group.add_argument( "--plot-glyphs", action="store_true", help="Gen images of full charset, useful for new familes", ) check_group.add_argument( "--browser-previews", action="store_true", help="Gen images on diff browsers, useful for new families", ) check_group.add_argument("-dm", "--diff-mode", choices=("weak", "normal", "strict"), default="normal") parser.add_argument("-re", "--filter-fonts", help="Filter fonts by regex") parser.add_argument("-o", "--out", default="out", help="Output path for check results") parser.add_argument( "-ogh", "--out-github", action="store_true", help=("Post report data to either the pull request as a comment " "open a new issue. This can only be used if fonts have been " "fetched from either a pull request or github dir."), ) parser.add_argument( "--out-url", help=( "Post report data to a github pr. This can be used with any font " "fetching method.")) parser.add_argument("--version", action="version", version=__version__) args = parser.parse_args() if args.out_github and not any([args.pull_request, args.github_dir]): raise Exception( "Cannot upload results to a github issue or pr. " "Font input must either a github dir or a pull request") if not any([ args.auto_qa, args.fontbakery, args.plot_glyphs, args.diffbrowsers, args.diffenator, args.browser_previews ]): raise Exception("Terminating. No checks selected. Run gftools qa " "--help to see all possible commands.") # Retrieve fonts and store in out dir mkdir(args.out) fonts_dir = os.path.join(args.out, "fonts") mkdir(fonts_dir) if args.fonts: [shutil.copy(f, fonts_dir) for f in args.fonts] fonts = args.fonts elif args.pull_request: fonts = download_files_in_github_pr( args.pull_request, fonts_dir, ignore_static_dir=False, ) if not fonts: logger.info("No fonts found in pull request. Skipping") return elif args.github_dir: fonts = download_files_in_github_dir(args.github_dir, fonts_dir) if not fonts: logger.info("No fonts found in github dir. Skipping") return elif args.googlefonts: fonts = download_family_from_Google_Fonts(args.googlefonts, fonts_dir) if args.filter_fonts: re_filter = re.compile(args.filter_fonts) fonts = [f for f in fonts if re_filter.search(f)] ttfonts = [ TTFont(f) for f in fonts if f.endswith((".ttf", ".otf")) and "static" not in f ] family_name = family_name_from_fonts(ttfonts) family_on_gf = Google_Fonts_has_family(family_name) # Retrieve fonts_before and store in out dir fonts_before = None if any([args.fonts_before, args.pull_request_before, args.github_dir_before]) or \ (args.googlefonts_before and family_on_gf): fonts_before_dir = os.path.join(args.out, "fonts_before") mkdir(fonts_before_dir, overwrite=False) if args.fonts_before: [shutil.copy(f, fonts_before_dir) for f in args.fonts_before] fonts_before = args.fonts_before elif args.pull_request_before: fonts_before = download_files_in_github_pr(args.pull_request_before, fonts_before_dir, ignore_static_dir=False) elif args.github_dir_before: fonts_before = download_files_in_github_dir(args.github_dir_before, fonts_before_dir) elif args.googlefonts_before and family_on_gf: fonts_before = download_family_from_Google_Fonts( family_name, fonts_before_dir) if fonts_before: ttfonts_before = [ TTFont(f) for f in fonts_before if f.endswith((".ttf", ".otf")) and "static" not in f ] qa = FontQA(ttfonts, ttfonts_before, args.out) else: qa = FontQA(ttfonts, out=args.out) if args.auto_qa and family_on_gf: qa.googlefonts_upgrade() elif args.auto_qa and not family_on_gf: qa.googlefonts_new() if args.plot_glyphs: qa.plot_glyphs() if args.browser_previews: qa.browser_previews() if args.fontbakery: qa.fontbakery() if args.diffenator: qa.diffenator() if args.diffbrowsers: qa.diffbrowsers() if args.out_url: qa.post_to_github(args.out_url) elif args.out_github and args.pull_request: qa.post_to_github(args.pull_request) elif args.out_github and args.github_dir: qa.post_to_github(args.github_dir)