Exemple #1
0
def run(argv: List[str]) -> None:
    # ===========================================================
    # argparse command line argument definitions
    # ===========================================================
    parser = argparse.ArgumentParser(
        description=
        "A tool for the removal of TrueType instruction sets (hints) in fonts")
    parser.add_argument("--version",
                        action="version",
                        version="dehinter v{}".format(__version__))
    parser.add_argument("-o", "--out", help="out file path (dehinted font)")
    parser.add_argument("--keep-cvar",
                        help="keep cvar table",
                        action="store_true")
    parser.add_argument("--keep-cvt",
                        help="keep cvt table",
                        action="store_true")
    parser.add_argument("--keep-fpgm",
                        help="keep fpgm table",
                        action="store_true")
    parser.add_argument("--keep-hdmx",
                        help="keep hdmx table",
                        action="store_true")
    parser.add_argument("--keep-ltsh",
                        help="keep LTSH table",
                        action="store_true")
    parser.add_argument("--keep-prep",
                        help="keep prep table",
                        action="store_true")
    parser.add_argument("--keep-ttfa",
                        help="keep TTFA table",
                        action="store_true")
    parser.add_argument("--keep-vdmx",
                        help="keep VDMX table",
                        action="store_true")
    parser.add_argument("--keep-glyf",
                        help="do not modify glyf table",
                        action="store_true")
    parser.add_argument("--keep-gasp",
                        help="do not modify gasp table",
                        action="store_true")
    parser.add_argument("--keep-maxp",
                        help="do not modify maxp table",
                        action="store_true")
    parser.add_argument("--keep-head",
                        help="do not modify head table",
                        action="store_true")
    parser.add_argument("--quiet",
                        help="silence standard output",
                        action="store_true")
    parser.add_argument("INFILE", help="in file path (hinted font)")

    args = parser.parse_args(argv)

    # ===========================================================
    # Command line logic
    # ===========================================================
    #
    # Validations
    # -----------
    #  (1) file path request is a file
    if not filepath_exists(args.INFILE):
        sys.stderr.write(
            f"[!] Error: '{args.INFILE}' is not a valid file path.{os.linesep}"
        )
        sys.stderr.write(f"[!] Request canceled.{os.linesep}")
        sys.exit(1)
    #  (2) the file is a ttf font file (based on the 4 byte file signature
    if not is_truetype_font(args.INFILE):
        sys.stderr.write(
            f"[!] Error: '{args.INFILE}' does not appear to be a TrueType font "
            f"file.{os.linesep}")
        sys.stderr.write(f"[!] Request canceled.{os.linesep}")
        sys.exit(1)
    #   (3) confirm that out path is not the same as in path
    #    This tool does not support writing dehinted files in place over hinted version
    if args.INFILE == args.out:
        sys.stderr.write(
            f"[!] Error: You are attempting to overwrite the hinted file with the "
            f"dehinted file.  This is not supported. Please choose a different file "
            f"path for the dehinted file.{os.linesep}")
        sys.exit(1)
    # Execution
    # ---------
    #  (1) OpenType table removal
    try:
        tt = TTFont(args.INFILE)
    except Exception as e:
        sys.stderr.write(
            f"[!] Error: Unable to create font object with '{args.INFILE}' -> {str(e)}"
        )
        sys.exit(1)

    use_verbose_output = not args.quiet

    dehint(
        tt,
        keep_cvar=args.keep_cvar,
        keep_cvt=args.keep_cvt,
        keep_fpgm=args.keep_fpgm,
        keep_gasp=args.keep_gasp,
        keep_glyf=args.keep_glyf,
        keep_hdmx=args.keep_hdmx,
        keep_head=args.keep_head,
        keep_ltsh=args.keep_ltsh,
        keep_maxp=args.keep_maxp,
        keep_prep=args.keep_prep,
        keep_ttfa=args.keep_ttfa,
        keep_vdmx=args.keep_vdmx,
        verbose=use_verbose_output,
    )

    # File write
    # ----------
    if args.out:
        # validation performed above to prevent this file path definition from
        # being the same as the in file path.  Write in place over a hinted
        # file is not supported
        outpath = args.out
    else:
        outpath = get_default_out_path(args.INFILE)

    try:
        tt.save(outpath)
        if use_verbose_output:
            print(f"{os.linesep}[+] Saved dehinted font as '{outpath}'")
    except Exception as e:  # pragma: no cover
        sys.stderr.write(
            f"[!] Error: Unable to save dehinted font file: {str(e)}{os.linesep}"
        )

    # File size comparison
    # --------------------
    if use_verbose_output:
        infile_size_tuple = get_filesize(args.INFILE)
        outfile_size_tuple = get_filesize(
            outpath)  # depends on outpath definition defined during file write
        print(f"{os.linesep}[*] File sizes:")
        print(f"    {infile_size_tuple[0]}{infile_size_tuple[1]} (hinted)")
        print(f"    {outfile_size_tuple[0]}{outfile_size_tuple[1]} (dehinted)")
Exemple #2
0
def test_filepath_exists_good_filepath():
    good_path = os.path.join("tests", "test_files", "fonts",
                             "Roboto-Regular.ttf")
    assert filepath_exists(good_path) is True
Exemple #3
0
def run(argv: List[str]) -> None:
    # instantiate pretty printer
    pp = pprint.PrettyPrinter(indent=4)

    # ===========================================================
    # argparse command line argument definitions
    # ===========================================================
    parser = argparse.ArgumentParser(
        description="A tool for the removal of TrueType instruction sets (hints) in fonts"
    )
    parser.add_argument(
        "--version", action="version", version="dehinter v{}".format(__version__)
    )
    parser.add_argument("-o", "--out", help="out file path (dehinted font)")
    parser.add_argument("--keep-cvar", help="keep cvar table", action="store_true")
    parser.add_argument("--keep-cvt", help="keep cvt table", action="store_true")
    parser.add_argument("--keep-fpgm", help="keep fpgm table", action="store_true")
    parser.add_argument("--keep-hdmx", help="keep hdmx table", action="store_true")
    parser.add_argument("--keep-ltsh", help="keep LTSH table", action="store_true")
    parser.add_argument("--keep-prep", help="keep prep table", action="store_true")
    parser.add_argument("--keep-ttfa", help="keep TTFA table", action="store_true")
    parser.add_argument("--keep-vdmx", help="keep VDMX table", action="store_true")
    parser.add_argument(
        "--keep-glyf", help="do not modify glyf table", action="store_true"
    )
    parser.add_argument(
        "--keep-gasp", help="do not modify gasp table", action="store_true"
    )
    parser.add_argument(
        "--keep-maxp", help="do not modify maxp table", action="store_true"
    )
    parser.add_argument(
        "--keep-head", help="do not modify head table", action="store_true"
    )
    parser.add_argument("INFILE", help="in file path (hinted font)")

    args = parser.parse_args(argv)

    # ===========================================================
    # Command line logic
    # ===========================================================
    #
    # Validations
    # -----------
    #  (1) file path request is a file
    if not filepath_exists(args.INFILE):
        sys.stderr.write(
            f"[!] Error: '{args.INFILE}' is not a valid file path.{os.linesep}"
        )
        sys.stderr.write(f"[!] Request canceled.{os.linesep}")
        sys.exit(1)
    #  (2) the file is a ttf font file (based on the 4 byte file signature
    if not is_truetype_font(args.INFILE):
        sys.stderr.write(
            f"[!] Error: '{args.INFILE}' does not appear to be a TrueType font "
            f"file.{os.linesep}"
        )
        sys.stderr.write(f"[!] Request canceled.{os.linesep}")
        sys.exit(1)
    #   (3) confirm that out path is not the same as in path
    #    This tool does not support writing dehinted files in place over hinted version
    if args.INFILE == args.out:
        sys.stderr.write(
            f"[!] Error: You are attempting to overwrite the hinted file with the "
            f"dehinted file.  This is not supported. Please choose a different file "
            f"path for the dehinted file.{os.linesep}"
        )
        sys.exit(1)
    # Execution
    # ---------
    #  (1) OpenType table removal
    try:
        tt = TTFont(args.INFILE)
    except Exception as e:
        sys.stderr.write(
            f"[!] Error: Unable to create font object with '{args.INFILE}' -> {str(e)}"
        )
        sys.exit(1)

    if is_variable_font(tt) and not args.keep_cvar:
        if has_cvar_table(tt):
            remove_cvar_table(tt)
            if not has_cvar_table(tt):
                print("[-] Removed cvar table")
            else:  # pragma: no cover
                sys.stderr.write(
                    f"[!] Error: failed to remove cvar table from font{os.linesep}"
                )

    if not args.keep_cvt:
        if has_cvt_table(tt):
            remove_cvt_table(tt)
            if not has_cvt_table(tt):
                print("[-] Removed cvt table")
            else:  # pragma: no cover
                sys.stderr.write(
                    f"[!] Error: failed to remove cvt table from font{os.linesep}"
                )

    if not args.keep_fpgm:
        if has_fpgm_table(tt):
            remove_fpgm_table(tt)
            if not has_fpgm_table(tt):
                print("[-] Removed fpgm table")
            else:  # pragma: no cover
                sys.stderr.write(
                    f"[!] Error: failed to remove fpgm table from font{os.linesep}"
                )

    if not args.keep_hdmx:
        if has_hdmx_table(tt):
            remove_hdmx_table(tt)
            if not has_hdmx_table(tt):
                print("[-] Removed hdmx table")
            else:  # pragma: no cover
                sys.stderr.write(
                    f"[!] Error: failed to remove hdmx table from font{os.linesep}"
                )

    if not args.keep_ltsh:
        if has_ltsh_table(tt):
            remove_ltsh_table(tt)
            if not has_ltsh_table(tt):
                print("[-] Removed LTSH table")
            else:  # pragma: no cover
                sys.stderr.write(
                    f"[!] Error: failed to remove LTSH table from font{os.linesep}"
                )

    if not args.keep_prep:
        if has_prep_table(tt):
            remove_prep_table(tt)
            if not has_prep_table(tt):
                print("[-] Removed prep table")
            else:  # pragma: no cover
                sys.stderr.write(
                    f"[!] Error: failed to remove prep table from font{os.linesep}"
                )

    if not args.keep_ttfa:
        if has_ttfa_table(tt):
            remove_ttfa_table(tt)
            if not has_ttfa_table(tt):
                print("[-] Removed TTFA table")
            else:  # pragma: no cover
                sys.stderr.write(
                    f"[!] Error: failed to remove TTFA table from font{os.linesep}"
                )

    if not args.keep_vdmx:
        if has_vdmx_table(tt):
            remove_vdmx_table(tt)
            if not has_vdmx_table(tt):
                print("[-] Removed VDMX table")
            else:  # pragma: no cover
                sys.stderr.write(
                    f"[!] Error: failed to remove VDMX table from font{os.linesep}"
                )

    #  (2) Remove glyf table instruction set bytecode
    if not args.keep_glyf:
        number_glyfs_edited = remove_glyf_instructions(tt)
        if number_glyfs_edited > 0:
            print(
                f"[-] Removed glyf table instruction bytecode from "
                f"{number_glyfs_edited} glyphs"
            )

    #  (3) Edit gasp table
    if not args.keep_gasp:
        if update_gasp_table(tt):
            gasp_string = pp.pformat(tt["gasp"].__dict__)
            print(f"[Δ] New gasp table values:{os.linesep}    {gasp_string}")

    #  (4) Edit maxp table
    if not args.keep_maxp:
        if update_maxp_table(tt):
            maxp_string = pp.pformat(tt["maxp"].__dict__)
            print(f"[Δ] New maxp table values:{os.linesep}    {maxp_string}")

    #  (5) Edit head table flags to clear bit 4
    if not args.keep_head:
        if update_head_table_flags(tt):
            print("[Δ] Cleared bit 4 in head table flags")

    # File write
    # ----------
    if args.out:
        # validation performed above to prevent this file path definition from
        # being the same as the in file path.  Write in place over a hinted
        # file is not supported
        outpath = args.out
    else:
        outpath = get_default_out_path(args.INFILE)

    try:
        tt.save(outpath)
        print(f"{os.linesep}[+] Saved dehinted font as '{outpath}'")
    except Exception as e:  # pragma: no cover
        sys.stderr.write(
            f"[!] Error: Unable to save dehinted font file: {str(e)}{os.linesep}"
        )

    # File size comparison
    # --------------------
    infile_size_tuple = get_filesize(args.INFILE)
    outfile_size_tuple = get_filesize(
        outpath
    )  # depends on outpath definition defined during file write
    print(f"{os.linesep}[*] File sizes:")
    print(f"    {infile_size_tuple[0]}{infile_size_tuple[1]} (hinted)")
    print(f"    {outfile_size_tuple[0]}{outfile_size_tuple[1]} (dehinted)")
Exemple #4
0
def test_filepath_exists_bad_filepath():
    bad_path = "bogus_file.txt"
    assert filepath_exists(bad_path) is False