コード例 #1
0
ファイル: theme.py プロジェクト: PageBot/PageBotNano
    def textColor(self, base, shade):
        """Answer the shade of base color that words best as text foreground
        on the `shade` color.

        >>> from pagebotnano.themes import BackToTheCity
        >>> theme = BackToTheCity()
        >>> theme.textColor(3, 0).name
        'black'
        """
        c = self.colors[base][shade]
        if c.averageRgb < 0.4:
            return color(1)
        return color(0)
コード例 #2
0
    def __init__(self,
                 glyphName,
                 font,
                 lineStroke=True,
                 lineWidth=None,
                 textFill=None,
                 textStroke=None,
                 textStrokeWidth=0,
                 pointStroke=None,
                 pointStrokeWidth=0,
                 pointMarkerSize=None,
                 **kwargs):
        Element.__init__(self, **kwargs)
        assert isinstance(font, Font)
        self.font = font  # This is a real Font instance
        self.glyphName = glyphName
        # As start assume the full height of the element as fontSize
        self.fontSize = self.h

        assert textFill is None or isinstance(textFill, Color)
        assert textStroke is None or isinstance(textStroke, Color)
        if textFill is None:
            textFill = self.GLYPH_FILL
        self.textFill = textFill
        self.textStroke = textStroke
        self.textStrokeWidth = textStrokeWidth or 0

        # Flag to show horizontal metrics lines. Can be one of (None, True, False, Color)
        # Default is self.LINE_STROKE color(0, 0, 1)
        if lineStroke and not isinstance(lineStroke,
                                         Color):  # In case it is "True"
            lineStroke = self.LINE_STROKE
        self.lineStroke = lineStroke
        self.lineWidth = lineWidth or 0  # Thickness of metrics lines

        # Create a style for it, so we can draw the glyph(s) as Text.
        style = dict(font=self.font.path,
                     fontSize=self.fontSize,
                     textFill=textFill or color(0),
                     align=CENTER)
        self.bs = BabelString(self.glyphName, style=style)
        tw, th = self.bs.textSize  # Get the size of the glyph(s) string to see if it fits.

        if self.w and tw > self.w:  # If width of self is defined and string is wider
            # Interpolate the fontSize from the measured width to smaller scaled fontSize.
            self.fontSize *= self.w / tw  # Multiply original fontsize by ratio
            # Make a new string with the fitting fontSize
            style['fontSize'] = self.fontSize  # Adjust the existing style
            style['fill'] = textFill or color(0)
            self.bs = BabelString(self.glyphName, style=style)
コード例 #3
0
class HappyHolidays(BaseTheme):
    NAME = 'Happy Holidays'
    BASE_COLORS = dict(
        base0=color(1, 0, 0.2),
        base1=color(0.7, 0.1, 0.2),
        base2=color(0.9, 0, 0.3),
        base3=color(0.5, 0.96, 0.2),
        base4=color(0, 1, 0),
        base5=color(0.55, 0.5, 0.5),
    )
コード例 #4
0
ファイル: drawbotcontext.py プロジェクト: PageBot/PageBotNano
    def fill(self, c):
        """Set the fill mode of the context. `c` can be None, a number,
        a name or a Color instance. 

        >>> context = DrawBotContext()
        >>> context.fill(None)
        >>> context.fill('red')
        >>> context.fill((1, 0, 0))
        >>> context.fill(Color(1, 0, 0))
        >>> context.fill(0.5)
        """
        if c is None:
            drawBot.fill(None)
        else:
            if not isinstance(c, Color):  # Make sure is it a Color instance.
                c = color(c)
            r, g, b, a = c.rgba
            drawBot.fill(r, g, b, a)
コード例 #5
0
ファイル: drawbotcontext.py プロジェクト: PageBot/PageBotNano
    def stroke(self, c, strokeWidth=None):
        """Set the stroke mode of the context. `c` can be None, a number,
        a name or a Color instance. 

        >>> context = DrawBotContext()
        >>> context.stroke(None)
        >>> context.stroke('red')
        >>> context.stroke((1, 0, 0))
        >>> context.stroke(Color(1, 0, 0))
        >>> context.stroke(0.5, 1)
        """
        if strokeWidth is not None:
            self.strokeWidth(strokeWidth)
        if c is None:
            drawBot.stroke(None)
        else:  # Make sure it is a Color instance.
            if not isinstance(c, Color):
                c = color(c)
            r, g, b, a = c.rgba
            drawBot.stroke(r, g, b, a)
コード例 #6
0
# Create a new document for the given size
doc = Document(w=w, h=h)

# Create the first page in the document, taking over the document size and padding.
page = doc.newPage()
# Show a single glyph, as large as it fits (in height or width) on the page,
# white on color background.
# The GlyphView element has a number of attributes (guided by attributes),
# to define the details that should be shown with the glyph outline.
gv = GlyphPathView('G',
                   font=f,
                   x=page.pl,
                   y=page.pb,
                   w=page.pw,
                   h=page.ph,
                   fill=color(0.9),
                   textFill=color(0.7),
                   textStroke=color(1, 0, 0),
                   textStrokeWidth=2,
                   pointStroke=color('darkblue'),
                   pointStrokeWidth=2,
                   pointMarkerSize=12,
                   pointFill=color(0.9),
                   pointLine=True)
page.addElement(gv)

# Create the first page in the document, taking over the document size and padding.
page = doc.newPage()
# Show a single glyph, as large as it fits (in height or width) on the page,
# white on color background.
# The GlyphView element has a number of attributes (guided by attributes),
コード例 #7
0
class GlyphView(Element):
    """The GlyphView show single glyphs with metrics lines, using a 
    FormattedString to show the text in a specified font. This is
    faster and more direct than drawing with a GlyphPath (which is
    demonstrated in the Element class GlyphPathView).

    >>> from pagebotnano_030.document import Document
    >>> from pagebotnano_030.fonttoolbox.objects.font import findFont
    >>> f = Font('../../resources/fonts/typetr/PageBot-Light.ttf')
    >>> #f = findFont('PageBot-Light.ttf')
    >>> doc = Document(w=200, h=200)
    >>> page = doc.newPage()
    >>> pad = 10
    >>> page.padding = pad
    >>> e = GlyphView('Hhj', f, x=pad, y=pad, w=page.pw, h=page.ph, fill=color(0.96))
    >>> page.addElement(e)
    >>> doc.export('_export/GlyphView.pdf')
    """
    LINE_STROKE = color(0, 0,
                        1)  # Defaultl color of the metrics lines (if defined)
    GLYPH_FILL = color(0)  # Default color of the glyph

    def __init__(self,
                 glyphName,
                 font,
                 lineStroke=True,
                 lineWidth=None,
                 textFill=None,
                 textStroke=None,
                 textStrokeWidth=0,
                 pointStroke=None,
                 pointStrokeWidth=0,
                 pointMarkerSize=None,
                 **kwargs):
        Element.__init__(self, **kwargs)
        assert isinstance(font, Font)
        self.font = font  # This is a real Font instance
        self.glyphName = glyphName
        # As start assume the full height of the element as fontSize
        self.fontSize = self.h

        assert textFill is None or isinstance(textFill, Color)
        assert textStroke is None or isinstance(textStroke, Color)
        if textFill is None:
            textFill = self.GLYPH_FILL
        self.textFill = textFill
        self.textStroke = textStroke
        self.textStrokeWidth = textStrokeWidth or 0

        # Flag to show horizontal metrics lines. Can be one of (None, True, False, Color)
        # Default is self.LINE_STROKE color(0, 0, 1)
        if lineStroke and not isinstance(lineStroke,
                                         Color):  # In case it is "True"
            lineStroke = self.LINE_STROKE
        self.lineStroke = lineStroke
        self.lineWidth = lineWidth or 0  # Thickness of metrics lines

        # Create a style for it, so we can draw the glyph(s) as Text.
        style = dict(font=self.font.path,
                     fontSize=self.fontSize,
                     textFill=textFill or color(0),
                     align=CENTER)
        self.bs = BabelString(self.glyphName, style=style)
        tw, th = self.bs.textSize  # Get the size of the glyph(s) string to see if it fits.

        if self.w and tw > self.w:  # If width of self is defined and string is wider
            # Interpolate the fontSize from the measured width to smaller scaled fontSize.
            self.fontSize *= self.w / tw  # Multiply original fontsize by ratio
            # Make a new string with the fitting fontSize
            style['fontSize'] = self.fontSize  # Adjust the existing style
            style['fill'] = textFill or color(0)
            self.bs = BabelString(self.glyphName, style=style)

    def drawContent(self, ox, oy, doc, page, parent):
        """Draw the content of this single glyph/string fitting, with line indicators
        of vertical metrics.

        TODO: Show more font metrics and glyph metrics here. Add labels of values and names.
        """

        # Set the context to font and fontSize, so we get the right descender back.
        doc.context.font(
            self.font.path,
            self.fontSize)  # Set to new fontSize, so metrics do fit
        descender = doc.context.fontDescender(
        )  # Scaled descender of current font/fontSize
        # If the fontSize is down scaled to match the string width, then evenely
        # distribute the extra vertical space above and below that scaled fontSize.
        baseline = (self.h - self.fontSize
                    ) / 2 - descender  # Distance from baseline to bottom y

        y = oy + baseline  # Calculate the position of the baseline.
        doc.context.text(
            self.bs,
            (ox + self.w / 2, y))  # Draw the glyphs on centered position.

        # If line color and line width are defined.
        if self.lineStroke and self.lineWidth:
            doc.context.stroke(self.lineStroke, self.lineWidth)
            doc.context.line((ox, y), (ox + self.w, y))  # Draw baseline

            xHeight = doc.context.fontXHeight()
            y = oy + baseline + xHeight
            doc.context.line((ox, y), (ox + self.w, y))

            capHeight = doc.context.fontCapHeight()
            y = oy + baseline + capHeight
            doc.context.line((ox, y), (ox + self.w, y))

            y = oy + baseline + descender
            doc.context.line((ox, y), (ox + self.w, y))  # Descender

            y = oy + baseline + self.fontSize + descender
            doc.context.line((ox, y), (ox + self.w, y))  # Descender
コード例 #8
0
class GlyphPathView(GlyphView):
    """The GlyphPathView show single glyphs with metrics lines, using 
    the Glyph.getGlyphPath as contour drawing. This is more flexible
    than drawing text as FormattedString. 
    GlyphPathView inherits from GlyphView, because it only is different
    in the GlyphPathView.drawContent method.

    >>> from pagebotnano_030.document import Document
    >>> from pagebotnano_030.fonttoolbox.objects.font import findFont
    >>> f = findFont('PageBot-Bold.ttf')
    >>> doc = Document(w=595, h=842)
    >>> page = doc.newPage()
    >>> pad = 10
    >>> page.padding = pad
    >>> e = GlyphPathView('Oi', f, x=pad, y=pad, w=page.pw, h=page.ph, fill=color(0.96), textFill=color(0.6), textStroke=color(0), textStrokeWidth=1)
    >>> page.addElement(e)
    >>> doc.export('_export/GlyphPathView.pdf')
    """
    POINT_STROKE = color('darkblue')
    POINT_FILL = color(0.9)

    def __init__(self,
                 glyphName,
                 font,
                 pointStroke=None,
                 pointStrokeWidth=0,
                 pointFill=None,
                 pointSize=None,
                 pointLine=None,
                 **kwargs):
        GlyphView.__init__(self, glyphName, font, **kwargs)

        # Flag to show point markers. Can be one of (None, True, False, Color)
        # Default is self.POINT_STROKE color(1, 0, 0)
        if pointFill and not isinstance(pointFill,
                                        Color):  # In case it is "True"
            pointFill = self.POINT_FILL
        self.pointFill = pointFill
        if pointStroke and not isinstance(pointStroke,
                                          Color):  # In case it is "True"
            pointStroke = self.POINT_STROKE
        self.pointStroke = pointStroke
        self.pointStrokeWidth = pointStrokeWidth or 0  # Thickness of metrics lines
        self.pointSize = pointSize or 0  # Size of point markers
        if pointLine and not isinstance(pointLine,
                                        Color):  # In case it is "True"
            pointLine = self.POINT_STROKE
        self.pointLine = pointLine  # Flag or color of lines between the point markers

    def drawContent(self, ox, oy, doc, page, parent):
        """Draw the content of this single glyph/string fitting, with line indicators
        of vertical metrics.

        TODO: Show more font metrics and glyph metrics here. Add labels of values and names.
        """
        scale = self.fontSize / self.font.info.unitsPerEm
        descender = scale * self.font.info.descender
        # Scaled descender of current font/fontSize
        # If the fontSize is down scaled to match the string width, then evenely
        # distribute the extra vertical space above and below that scaled fontSize.
        baseline = (self.h - self.fontSize
                    ) / 2 - descender  # Distance from baseline to bottom y

        y = oy + baseline  # Calculate the position of the baseline.
        for char in self.glyphName:
            # Just the first glyph of the string for now.
            glyph = self.font[char]
            glyphPath = glyph.getGlyphPath(doc.context)
            #print(glyphPath._path) # Showing the points in a BezierPath

            # Draw stroke and fill separate, to overwrite the inline
            # side of a thick stroke.
            doc.context.save()
            doc.context.scale(scale)
            doc.context.translate(ox / scale, y / scale)
            doc.context.stroke(self.textStroke, self.textStrokeWidth)
            doc.context.fill(None)
            doc.context.drawPath(glyphPath)
            # Something else could draw here, between stroke-fill
            doc.context.fill(self.textFill)
            doc.context.stroke(None)
            doc.context.drawPath(glyphPath)
            doc.context.restore()

            # If line color and line width are defined.
            if self.lineStroke and self.lineWidth:
                doc.context.stroke(self.lineStroke, self.lineWidth)
                doc.context.line((ox, y), (ox + self.w, y))  # Draw baseline

                xHeight = scale * self.font.info.xHeight
                ly = oy + baseline + xHeight
                doc.context.line((ox, ly), (ox + self.w, ly))

                capHeight = scale * self.font.info.capHeight
                ly = oy + baseline + capHeight
                doc.context.line((ox, ly), (ox + self.w, ly))

                ly = oy + baseline + descender
                doc.context.line((ox, ly), (ox + self.w, ly))  # Descender

                ly = oy + baseline + self.fontSize + descender
                doc.context.line((ox, ly), (ox + self.w, ly))  # Descender

            if self.pointFill or (self.pointStroke and self.pointStrokeWidth):
                radius = (self.pointSize or 16) / 2
                doc.context.save()
                doc.context.scale(scale)
                doc.context.translate(ox / scale, y / scale)

                # First draw the connecting lines between the points
                # Instead of using glyph.points we iterate through a list of
                # PointContext instances, that hold a sequence of 7 points.
                lineWidth = self.pointStrokeWidth or 1
                doc.context.stroke(self.pointLine or self.pointStroke,
                                   lineWidth / 2)
                # Point context naming
                # O   O   O   O     O   O   O   O   O   O   O   O
                #                   p_3 p_2 p_1 p   p1  p2  p3
                for pc in glyph.pointContexts:
                    # Calculate the positions of marker + line + marker,
                    # so the line does not overlap to the middle of the marker.
                    doc.context.fill(None)
                    if pc.p_1.offCurve and pc.p.onCurve:
                        doc.context.line(pc.p_1.p, pc.p.p)
                    if pc.p.onCurve and pc.p1.offCurve:
                        doc.context.line(pc.p.p, pc.p1.p)
                for p in glyph.points:
                    # Now draw all markers, only for the middle point
                    doc.context.fill(self.pointFill)
                    if p.offCurve:  # Off-curves radius 60% point size
                        doc.context.oval(p.x - radius * 0.6,
                                         p.y - radius * 0.6, radius * 2 * 0.6)
                    else:
                        doc.context.oval(p.x - radius, p.y - radius,
                                         2 * radius)
                doc.context.restore()