Esempio n. 1
0
    def getBeamStemCounters(self, context, y=None):
        """Calculate the stems and counters by a horizontal beam through the middle of the bounding box.
        This works best with the capital I. The value is uncached and should only be used if
        normal stem detection fails. Or in case of italic."""
        beamStems = {}
        beamCounters = {}
        if y is None:
            y = (self.maxY - self.minY) / 2
        line = ((-sys.maxsize, y), (sys.maxsize, y))
        # Get intersections with this line. We can assume they are sorted set by x value
        intersections = self.intersectWithLine(line, context)
        # If could not make path or flattened path or no intersections or just one, give up.
        if intersections is None or len(intersections) < 2:
            return None
        # Now make Stem instance from these values, as if they we Verticals positions.
        # The difference is that we only have points, not point contexts here,
        # but for limited use that should not make a difference for entry in a Stem
        p0 = ap0 = None
        for n in range(0, len(intersections)):
            # Add this stem or counter to the result. Create point contexts, simulating vertical
            # We cannot just check on odd/even, as a line may pass exactly on the top/bottom of a curve.
            p = intersections[n]
            pUp = p[0], p[1] + 10
            pDown = p[0], p[1] - 10
            ap = APointContext((pUp, pUp, pUp, p, pDown, pDown,
                                pDown))  # Simulate vertical context.

            if p0 is None:
                p0 = p
                ap0 = ap
                continue

            p1 = p0
            ap1 = ap0
            p0 = p
            ap0 = ap

            # If middle of the point is on black, then it is a stem. Otherwise it is a counter.
            mp = (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2
            if self.onBlack(mp):
                stem = self.STEM_CLASS(ap1, ap0, self.glyph.name)
                size = asInt(stem.size)  # Make sure not to get floats as key
                if not size in beamStems:
                    beamStems[size] = []
                beamStems[size].append(stem)
            else:  # Otherwise, middle point between intersections is on white, it must be a counter
                counter = self.COUNTER_CLASS(ap1, ap0, self.glyph.name)
                size = asInt(counter.size)  # Make sure to get floats as key
                if not size in beamCounters:
                    beamCounters[size] = []
                beamCounters[size].append(counter)
        return beamStems, beamCounters
Esempio n. 2
0
def commaString2IntegerList(s):
    l = []
    for word in commaString2List(s):
        number = asInt(word)
        if number is not None:
            l.append(number)
    return l
Esempio n. 3
0
def idCommaString2IdSet(s):
    """Transform a string with comma separated items into a set of id integers."""
    t = set()
    if s is not None:
        for value in s.split(','):
            value = asInt(value)
            if value is not None:
                t.add(value)
    return t
Esempio n. 4
0
def filterValue2Int(s):
    """Filter all numeric characters from the string and answer the resulting integer.
    Answer 0 if no digits are found. If s is already a number, then answer it as rounded int."""
    if isinstance(s, (int, float)):
        return int(round(s))
    digits = '0'
    for c in s:
        if c in '0123456789':
            digits += c
    return asInt(digits)
Esempio n. 5
0
    def findBars(self):
        """The @findBars@ method finds the bars in the current glyph and
        assigns them as dictionary to @self._bars@. Since we cannot use the CVT
        of the glyph (the analyzer is user to find these values, not to use
        them), we'll make an assumption about the pattern of vertices found. It
        is up to the caller to make sure that the current glyph is relevant in
        the kind of vertices that we are looking for."""
        horizontals = self.horizontals
        self._bars = bars = {}
        # BlueBars by separate property call
        self._roundBars = roundBars = {}
        self._straightRoundBars = straightRoundBars = {}
        self._verticalCounters = verticalCounters = {}
        self._verticalRoundCounters = verticalRoundCounters = {}
        self._verticalMixedCounters = verticalMixedCounters = {}
        self._allVerticalCounters = allVerticalCounters = {
        }  # Space between all neighboring stems, running over white only.

        checked = set()  # Store what we checked, to avoid doubles in the loops
        dimensions = self.dimensions
        if dimensions:
            for dimension in dimensions:  # UFO only, needs to be written.
                if self.FLOQMEME_BAR in dimensions[
                        'types']:  # Is this this dimension defining a stem?
                    bar = self.BAR_CLASS(dimensions['pc0'], dimensions['pc1'],
                                         self.glyph.name)
                    size = bar.size
                    if not size in bars:
                        bars[size] = []
                    bars[size].append(bar)
        if not bars:  # No "manual" hints defined, try to analyze from the found Vertical instances.
            for _, horizontal1 in sorted(
                    horizontals.items()):  # y1, horizontal1
                for _, horizontal2 in sorted(
                        horizontals.items()):  # y2, horizontal2
                    if horizontal1 is horizontal2:
                        continue
                    # We need to loop through the points of the horizontal
                    # separate, to find e.g. the vertical separate round bars
                    # of the points of a ellipsis. Otherwise they will seen as one horizontal.
                    for pc0 in horizontal1:
                        for pc1 in horizontal2:
                            # Skip if identical, they cannot be a stem.
                            if pc0 is pc1:
                                continue
                            # Skip if we already examined this one.
                            if (pc0.index, pc1.index) in checked:
                                continue
                            checked.add((pc0.index, pc1.index))
                            checked.add((pc1.index, pc0.index))
                            # Test if the y values are in range so this can be seen as stem pair
                            # and test if this pair is spanning a black space and not covered in black.
                            if self.isBar(pc0, pc1):
                                # Add this bar to the result.
                                bar = self.BAR_CLASS(pc0, pc1, self.glyph.name)
                                size = asInt(
                                    bar.size
                                )  # Make sure not to get floats as keys
                                if not size in bars:
                                    bars[size] = []
                                bars[size].append(bar)

                            elif self.isRoundBar(pc0, pc1):
                                # If either of the point context is a curve extreme
                                # then count this bar as round bar
                                bar = self.BAR_CLASS(pc0, pc1, self.glyph.name)
                                size = asInt(
                                    bar.size
                                )  # Make sure not to get floats as keys
                                if not size in roundBars:
                                    roundBars[size] = []
                                roundBars[size].append(bar)

                            elif self.isStraightRoundBar(pc0, pc1):
                                # If one side is straight and the other side is round extreme
                                # then count this stem as straight round bar.
                                bar = self.BAR_CLASS(pc0, pc1, self.glyph.name)
                                size = asInt(
                                    bar.size
                                )  # Make sure not to get floats as key
                                if not size in straightRoundBars:
                                    straightRoundBars[size] = []
                                straightRoundBars[size].append(bar)

                            elif self.isVerticalCounter(pc0, pc1):
                                # If there is just white space between the points and they are some kind of extreme,
                                # then assume this is a counter.
                                counter = self.VERTICAL_COUNTER_CLASS(
                                    pc0, pc1, self.glyph.name)
                                size = asInt(counter.size)

                                if pc0.isHorizontalExtreme(
                                ) and pc1.isHorizontalExtreme():
                                    if not size in verticalCounters:
                                        verticalCounters[size] = []
                                    verticalCounters[size].append(counter)
                                elif pc0.isHorizontalRoundExtreme(
                                ) and pc1.isHorizontalRoundExtreme():
                                    if not size in verticalRoundCounters:
                                        verticalRoundCounters[size] = []
                                    verticalRoundCounters[size].append(counter)
                                else:
                                    if not size in verticalMixedCounters:
                                        verticalMixedCounters[size] = []
                                    verticalMixedCounters[size].append(counter)

                                if not size in allVerticalCounters:
                                    allVerticalCounters[size] = []
                                allVerticalCounters[size].append(counter)

        return self._bars
Esempio n. 6
0
    def findStems(self):
        """The @findStems@ method finds the stems in the current glyph and
        assigns them as dictionary to @self._stems@. Since we cannot use the
        CVT of the glyph (the analyzer is used to find these values, not to use
        them), we'll make an assumption about the pattern of vertices found. It
        is up to the caller to make sure that the current glyph is relevant in
        the kind of vertices that we are looking for.

        NOTE: An alternative approach could be to make a Fourier analysis of all
        stem distances of the font, and so find out which are likely to have a
        stem distance.

        Additionally the stems are found by manual hints in the glyph, as
        generated by the Hint Editor. Since these stem definitions not
        necessarily run from point to point (instead an interpolated location
        on a curve or straight line can be used), a special kind of
        PointContext is added there.
        """
        self._stems = stems = {}
        self._roundStems = roundStems = {}
        self._straightRoundStems = straightRoundStems = {}
        self._allHorizontalCounters = horizontalCounters = {
        }  # Space between all neighboring stems, running over white only.

        verticals = self.verticals
        checked = set()  # Store what we checked, to avoid doubles in the loops

        for _, vertical1 in sorted(verticals.items()):  # x1, vertical1
            for _, vertical2 in sorted(verticals.items()):  # x2, vertical2
                if vertical1 is vertical2:
                    continue
                # We need to loop through the points of the vertical
                # separate, to find e.g. the horizontal separate round stems
                # of the points of a column. Otherwise they will be seen as one vertical.
                for pc0 in vertical1:
                    for pc1 in vertical2:
                        # Skip if identical, they cannot be a stem.
                        if pc0 is pc1:
                            continue
                        # Skip if we already examined this one.
                        if (pc0.index, pc1.index) in checked:
                            continue
                        checked.add((pc0.index, pc1.index))
                        checked.add((pc1.index, pc0.index))
                        # Test if the y values are in range so this can be seen as stem pair
                        # and test if this pair is spanning a black space and the lines are
                        # not entirely covered in black.
                        if self.isStem(pc0, pc1):
                            # Add this stem to the result.
                            stem = self.STEM_CLASS(pc0, pc1, self.glyph.name)
                            size = asInt(
                                stem.size
                            )  # Make sure not to get floats as key
                            if not size in stems:
                                stems[size] = []
                            stems[size].append(stem)

                        elif self.isRoundStem(pc0, pc1):
                            # If either of the point context is a curve extreme
                            # then count this stem as round stem
                            stem = self.STEM_CLASS(pc0, pc1, self.glyph.name)
                            size = asInt(
                                stem.size
                            )  # Make sure not to get floats as key
                            if not size in roundStems:
                                roundStems[size] = []
                            roundStems[size].append(stem)

                        elif self.isStraightRoundStem(pc0, pc1):
                            # If one side is straight and the other side is round extreme
                            # then count this stem as straight round stem.
                            stem = self.STEM_CLASS(pc0, pc1, self.glyph.name)
                            size = asInt(
                                stem.size
                            )  # Make sure not to get floats as key
                            if not size in straightRoundStems:
                                straightRoundStems[size] = []
                            straightRoundStems[size].append(stem)

                        elif self.isHorizontalCounter(pc0, pc1):
                            # If there is just whitspace between the points and they are some kind of extreme,
                            # then assume this is a counter.
                            counter = self.COUNTER_CLASS(
                                pc0, pc1, self.glyph.name)
                            size = asInt(counter.size)
                            if not size in horizontalCounters:
                                horizontalCounters[size] = []
                            horizontalCounters[size].append(counter)

        return self._stems