示例#1
0
def main(font_path_a, font_path_b, specimen_path):
    generator = hb_input.HbInputGenerator(ttLib.TTFont(font_path_a))
    inputs_a = generator.all_inputs(warn=True)
    generator = hb_input.HbInputGenerator(ttLib.TTFont(font_path_b))
    inputs_b = set(generator.all_inputs(warn=True))

    to_ignore = ('\00', '\02')
    to_replace = (('&', '&amp;'), ('<', '&lt;'), ('>', '&gt;'))
    out_lines = ['<html>']
    for features, text in [i for i in inputs_a if i in inputs_b]:
        if any(char in text for char in to_ignore):
            continue
        for old, new in to_replace:
            text = text.replace(old, new)
        style = ''
        if features:
            style = (' style="font-feature-settings: %s;"' %
                     ', '.join("'%s'" % f for f in features))
        out_lines.append('<p%s>%s</p>' % (style, text))
    out_lines.append('</html>')
    out_text = '\n'.join(out_lines)

    with open(specimen_path, 'w') as out_file:
        out_file.write(out_text.encode('utf-8'))
示例#2
0
    def find_rendered_diffs(self, font_size=128, render_path=None):
        """Find diffs of glyphs as rendered by harfbuzz."""

        hb_input_generator_a = hb_input.HbInputGenerator(self.font_a)
        hb_input_generator_b = hb_input.HbInputGenerator(self.font_b)

        if render_path:
            font_name, _ = os.path.splitext(self.basepath)
            render_path = os.path.join(render_path, font_name)
            if not os.path.exists(render_path):
                os.makedirs(render_path)

        self.build_names()
        diffs = []
        for name in self.names:
            class_a = self.gdef_a.get(name, GDEF_UNDEF)
            class_b = self.gdef_b.get(name, GDEF_UNDEF)
            if GDEF_MARK in (class_a, class_b) and class_a != class_b:
                self.stats['gdef_mark_mismatch'].append(
                    (self.basepath, name, GDEF_LABELS[class_a],
                     GDEF_LABELS[class_b]))
                continue

            width_a = self.glyph_set_a[name].width
            width_b = self.glyph_set_b[name].width
            zwidth_a = width_a == 0
            zwidth_b = width_b == 0
            if zwidth_a != zwidth_b:
                self.stats['zero_width_mismatch'].append(
                    (self.basepath, name, width_a, width_b))
                continue

            hb_args_a = hb_input_generator_a.input_from_name(name,
                                                             pad=zwidth_a)
            hb_args_b = hb_input_generator_b.input_from_name(name,
                                                             pad=zwidth_b)
            if hb_args_a != hb_args_b:
                self.stats['input_mismatch'].append(
                    (self.basepath, name, hb_args_a, hb_args_b))
                continue

            # ignore unreachable characters
            if not hb_args_a:
                self.stats['untested'].append((self.basepath, name))
                continue

            features, text = hb_args_a

            # ignore null character
            if unichr(0) in text:
                continue

            img_file_a = StringIO.StringIO(
                subprocess.check_output([
                    'hb-view',
                    '--font-size=%d' % font_size,
                    '--features=%s' % ','.join(features), self.path_a, text
                ]))
            img_file_b = StringIO.StringIO(
                subprocess.check_output([
                    'hb-view',
                    '--font-size=%d' % font_size,
                    '--features=%s' % ','.join(features), self.path_b, text
                ]))
            img_a = Image.open(img_file_a)
            img_b = Image.open(img_file_b)
            width_a, height_a = img_a.size
            width_b, height_b = img_b.size
            data_a = img_a.getdata()
            data_b = img_b.getdata()
            img_file_a.close()
            img_file_b.close()

            width, height = max(width_a, width_b), max(height_a, height_b)
            offset_ax = (width - width_a) // 2
            offset_ay = (height - height_a) // 2
            offset_bx = (width - width_b) // 2
            offset_by = (height - height_b) // 2

            diff = 0
            for y in range(height):
                for x in range(width):
                    ax, ay = x - offset_ax, y - offset_ay
                    bx, by = x - offset_bx, y - offset_by
                    if (ax < 0 or bx < 0 or ax >= width_a or bx >= width_b
                            or ay < 0 or by < 0 or ay >= height_a
                            or by >= height_b):
                        diff += 1
                    else:
                        diff += abs(data_a[ax + ay * width_a] -
                                    data_b[bx + by * width_b]) / 255

            if self.ratio_diffs:
                diff /= (width * height)

            if render_path and diff > self.diff_threshold:
                img_cmp = Image.new('RGB', (width, height))
                data_cmp = list(img_cmp.getdata())
                self._project(data_a, width_a, height_a, data_cmp, width,
                              height, 1)
                self._project(data_b, width_b, height_b, data_cmp, width,
                              height, 0)
                for y in range(height):
                    for x in range(width):
                        i = x + y * width
                        r, g, b = data_cmp[i]
                        assert b == 0
                        data_cmp[i] = r, g, min(r, g)
                img_cmp.putdata(data_cmp)
                img_cmp.save(self._rendered_png(render_path, name))

            diffs.append((name, diff))

        mismatched = {}
        for name, diff in diffs:
            if diff > self.diff_threshold:
                mismatched[name] = diff

        stats = self.stats['compared']
        for name, diff in mismatched.items():
            stats.append((diff, name, self.basepath))
示例#3
0
    def find_rendered_diffs(self, font_size=256, render_path=None):
        """Find diffs of glyphs as rendered by harfbuzz + image magick."""

        hb_input_generator_a = hb_input.HbInputGenerator(self.font_a)
        hb_input_generator_b = hb_input.HbInputGenerator(self.font_b)

        a_png_file = tempfile.NamedTemporaryFile()
        a_png = a_png_file.name
        b_png_file = tempfile.NamedTemporaryFile()
        b_png = b_png_file.name
        cmp_png_file = tempfile.NamedTemporaryFile()
        cmp_png = cmp_png_file.name
        diffs_file = tempfile.NamedTemporaryFile()
        diffs_filename = diffs_file.name

        self.build_names()
        for name in self.names:
            class_a = self.gdef_a.get(name, GDEF_UNDEF)
            class_b = self.gdef_b.get(name, GDEF_UNDEF)
            if GDEF_MARK in (class_a, class_b) and class_a != class_b:
                self.stats['gdef_mark_mismatch'].append(
                    (self.basepath, name, GDEF_LABELS[class_a],
                     GDEF_LABELS[class_b]))
                continue

            width_a = self.glyph_set_a[name].width
            width_b = self.glyph_set_b[name].width
            zwidth_a = width_a == 0
            zwidth_b = width_b == 0
            if zwidth_a != zwidth_b:
                self.stats['zero_width_mismatch'].append(
                    (self.basepath, name, width_a, width_b))
                continue

            hb_args_a = hb_input_generator_a.input_from_name(name,
                                                             pad=zwidth_a)
            hb_args_b = hb_input_generator_b.input_from_name(name,
                                                             pad=zwidth_b)
            if hb_args_a != hb_args_b:
                self.stats['input_mismatch'].append(
                    (self.basepath, name, hb_args_a, hb_args_b))
                continue

            # ignore unreachable characters
            if not hb_args_a:
                self.stats['untested'].append((self.basepath, name))
                continue

            features, text = hb_args_a

            # ignore null character
            if unichr(0) in text:
                continue

            with open(diffs_filename, 'a') as ofile:
                ofile.write('%s\n' % name)

            subprocess.call([
                'hb-view',
                '--font-size=%d' % font_size,
                '--output-file=%s' % a_png,
                '--features=%s' % ','.join(features), self.path_a, text
            ])
            subprocess.call([
                'hb-view',
                '--font-size=%d' % font_size,
                '--output-file=%s' % b_png,
                '--features=%s' % ','.join(features), self.path_b, text
            ])

            img_info = subprocess.check_output(['identify', a_png]).split()
            assert img_info[0] == a_png and img_info[1] == 'PNG'
            subprocess.call([
                'convert', '-gravity', 'center', '-background', 'black',
                '-extent', img_info[2], b_png, b_png
            ])

            if render_path:
                glyph_filename = re.sub(r'([A-Z_])', r'\1_', name) + '.png'
                output_png = os.path.join(render_path, glyph_filename)
                # see for a discussion of this rendering technique:
                # https://github.com/googlei18n/nototools/issues/162#issuecomment-175885431
                subprocess.call([
                    'convert', '(', a_png, '-colorspace', 'gray', ')', '(',
                    b_png, '-colorspace', 'gray', ')', '(', '-clone', '0-1',
                    '-compose', 'darken', '-composite', ')', '-channel', 'RGB',
                    '-combine', output_png
                ])

            with open(diffs_filename, 'a') as ofile:
                subprocess.call(
                    ['compare', '-metric', 'AE', a_png, b_png, cmp_png],
                    stderr=ofile)
                ofile.write('\n')

        with open(diffs_filename) as ifile:
            lines = [l.strip() for l in ifile.readlines() if l.strip()]
        diffs = [(lines[i], lines[i + 1]) for i in range(0, len(lines), 2)]

        mismatched = {}
        for name, diff in diffs:
            if int(diff) != 0:
                mismatched[name] = int(diff)

        stats = self.stats['compared']
        for name, diff in mismatched.items():
            stats.append((diff, name, self.basepath))
示例#4
0
    def find_rendered_diffs(self, font_size=256, render_path=None):
        """Find diffs of glyphs as rendered by harfbuzz + image magick."""

        self.build_names()
        self.build_reverse_cmap()

        hb_input_generators = [
            hb_input.HbInputGenerator(p, self.reverse_cmap) for p in self.paths
        ]
        path_a, path_b = self.paths
        ordered_names = list(self.names)

        a_png = self._make_tmp_path()
        b_png = self._make_tmp_path()
        cmp_png = self._make_tmp_path()
        diffs_filename = self._make_tmp_path()

        for name in ordered_names:
            hb_args, hb_args_b = [
                input_generator.input_from_name(name)
                for input_generator in hb_input_generators
            ]
            assert hb_args == hb_args_b

            # ignore unreachable characters
            if not hb_args:
                self.stats['untested'].append(name)
                continue

            features, text = hb_args

            # ignore null character
            if text == unichr(0):
                continue

            with open(diffs_filename, 'a') as ofile:
                ofile.write('%s\n' % name)

            subprocess.call([
                'hb-view',
                '--font-size=%d' % font_size,
                '--output-file=%s' % a_png,
                '--features=%s' % ','.join(features), path_a, text
            ])
            subprocess.call([
                'hb-view',
                '--font-size=%d' % font_size,
                '--output-file=%s' % b_png,
                '--features=%s' % ','.join(features), path_b, text
            ])

            img_info = subprocess.check_output(['identify', a_png]).split()
            assert img_info[0] == a_png and img_info[1] == 'PNG'
            subprocess.call([
                'convert', '-gravity', 'center', '-background', 'black',
                '-extent', img_info[2], b_png, b_png
            ])

            if render_path:
                output_png = os.path.join(render_path, name + '.png')
                # see for a discussion of this rendering technique:
                # https://github.com/googlei18n/nototools/issues/162#issuecomment-175885431
                subprocess.call([
                    'convert', '(', a_png, '-colorspace', 'gray', ')', '(',
                    b_png, '-colorspace', 'gray', ')', '(', '-clone', '0-1',
                    '-compose', 'darken', '-composite', ')', '-channel', 'RGB',
                    '-combine', output_png
                ])

            with open(diffs_filename, 'a') as ofile:
                subprocess.call(
                    ['compare', '-metric', 'AE', a_png, b_png, cmp_png],
                    stderr=ofile)

        with open(diffs_filename) as ifile:
            lines = ifile.readlines()
        diffs = [(lines[i].strip(), lines[i + 1].strip())
                 for i in range(0, len(lines), 2)]

        os.remove(a_png)
        os.remove(b_png)
        os.remove(cmp_png)
        os.remove(diffs_filename)

        mismatched = {}
        for name, diff in diffs:
            if int(diff) != 0:
                mismatched[name] = int(diff)

        stats = self.stats['compared']
        for name, diff in mismatched.items():
            stats.append((diff, name, self.basepath))