Exemple #1
0
 def __init__(self,
              gradientType=None,
              start=None,
              end=None,
              colors=None,
              positions=None,
              startRadius=None,
              endRadius=None):
     if gradientType is None:
         return
     if gradientType not in ("linear", "radial"):
         raise PageBotError(
             "Gradient type must be either 'linear' or 'radial'")
     if not colors or len(colors) < 2:
         raise PageBotError("Gradient needs at least 2 colors")
     if positions is None:
         positions = [
             i / float(len(colors) - 1) for i in range(len(colors))
         ]
     if len(colors) != len(positions):
         raise PageBotError(
             "Gradient needs a correct position for each color")
     self.gradientType = gradientType
     self.colors = self._colorClass.getColorsFromList(colors)
     self.cmykColors = None
     self.positions = positions
     self.start = start
     self.end = end
     self.startRadius = startRadius
     self.endRadius = endRadius
    def fontVariations(self, *args, **axes):
        """Picks a variation by axes values and return the current font
        variations settings.

        If no arguments are given `fontVariations()` will just return the
        current font variations settings."""
        if args and axes:
            raise PageBotError("Can't combine positional arguments and keyword arguments")

        if args:
            if len(args) != 1:
                raise PageBotError("There can only be one positional argument")
            if args[0] is not None:
                raise PageBotError("First positional argument can only be None")
            logger.warning("fontVariations(None) is deprecated, use fontVariations(resetVariations=True) instead.")
            self._fontVariations.clear()
        else:
            if axes.pop("resetVariations", False):
                self._fontVariations.clear()
            self._fontVariations.update(axes)

        defaultVariations = self.listFontVariations()
        currentVariation = {axis: data["defaultValue"] for axis, data in defaultVariations.items()}
        currentVariation.update(self._fontVariations)
        return currentVariation
Exemple #3
0
 def _fontNameForPath(self, path):
     from fontTools.ttLib import TTFont, TTLibError
     try:
         font = TTFont(path, fontNumber=0)  # in case of .ttc, use the first font
         psName = font["name"].getName(6, 1, 0)
         if psName is None:
             psName = font["name"].getName(6, 3, 1)
         font.close()
     except IOError:
         raise PageBotError("Font '%s' does not exist." % path)
     except TTLibError:
         raise PageBotError("Font '%s' is not a valid font." % path)
     if psName is not None:
         psName = psName.toUnicode()
     return psName
Exemple #4
0
    def getPath(self):
        graphic = self.getGraphic()

        if graphic.path is None:
            raise PageBotError("Create a new path first")

        return graphic.path
Exemple #5
0
 def colorSpace(self, colorSpace):
     if colorSpace is None:
         colorSpace = 'genericRGB'
     if colorSpace not in self._colorSpaceMap:
         raise PageBotError("'%s' is not a valid colorSpace, argument must be '%s'" % (colorSpace, "', '".join(self._colorSpaceMap.keys())))
     colorSpace = self._colorSpaceMap[colorSpace]
     self._state.setColorSpace(colorSpace)
Exemple #6
0
 def getColor(cls, color):
     if isinstance(color, cls.__class__):
         return color
     elif isinstance(color, (tuple, list)):
         return cls(*color)
     elif isinstance(color, AppKit.NSColor):
         return cls(color)
     raise PageBotError("Not a valid color: %s" % color)
Exemple #7
0
 def _contoursForBooleanOperations(self):
     # contours are temporary objects
     # redirect drawToPointPen to drawPoints
     contours = self.contours
     for contour in contours:
         contour.drawPoints = contour.drawToPointPen
         if contour.open:
             raise PageBotError("open contours are not supported during boolean operations")
     return contours
    def textBox(self,
                txt,
                box,
                font=_FALLBACKFONT,
                fontSize=10,
                align=None,
                hyphenation=None):
        """Draws a `txt` with a `font` and `fontSize` in a `box` in the Bézier
        path. If a font path is given the font will be installed and used
        directly.

        - Optionally an alignment can be set.
        - Possible `align` values are: `"left"`, `"center"` and `"right"`.
        - The default alignment is `left`.
        - Optionally `hyphenation` can be provided.
        - Optionally `txt` can be a `FormattedString`.
        - Optionally `box` can be a `BezierPath`.
        """
        if align and align not in self._textAlignMap.keys():
            raise PageBotError("align must be %s" %
                               (", ".join(self._textAlignMap.keys())))

        context = BaseContext()
        context.font(font, fontSize)
        context.hyphenation(hyphenation)
        path, (x, y) = context._getPathForFrameSetter(box)
        attributedString = context.attributedString(txt, align)

        setter = CoreText.CTFramesetterCreateWithAttributedString(
            attributedString)
        frame = CoreText.CTFramesetterCreateFrame(setter, (0, 0), path, None)
        ctLines = CoreText.CTFrameGetLines(frame)
        origins = CoreText.CTFrameGetLineOrigins(frame, (0, len(ctLines)),
                                                 None)

        for i, (originX, originY) in enumerate(origins):
            ctLine = ctLines[i]
            ctRuns = CoreText.CTLineGetGlyphRuns(ctLine)
            for ctRun in ctRuns:
                attributes = CoreText.CTRunGetAttributes(ctRun)
                font = attributes.get(AppKit.NSFontAttributeName)
                baselineShift = attributes.get(
                    AppKit.NSBaselineOffsetAttributeName, 0)
                glyphCount = CoreText.CTRunGetGlyphCount(ctRun)
                for i in range(glyphCount):
                    glyph = CoreText.CTRunGetGlyphs(ctRun, (i, 1), None)[0]
                    ax, ay = CoreText.CTRunGetPositions(ctRun, (i, 1), None)[0]
                    if glyph:
                        self._path.moveToPoint_(
                            (x + originX + ax,
                             y + originY + ay + baselineShift))
                        self._path.appendBezierPathWithGlyph_inFont_(
                            glyph, font)
        self.optimizePath()
        return context.clippedText(txt, box, align)
Exemple #9
0
    def newPage(self, width=None, height=None):
        if self.width is None:
            if width is None:
                raise PageBotError("A page must have a width")
            self.width = width

        if self.height is None:
            if height is None:
                raise PageBotError("A page must have a height")
            self.height = height

        self.hasPage = True

        self.page = Canvas((0, 0, -0, -0), delegate=self,
            canvasSize=(self.width, self.height), acceptsMouseMoved=True,
            hasHorizontalScroller=True, hasVerticalScroller=True,
            autohidesScrollers=False, backgroundColor=None,
            drawsBackground=True, flipped=True)
        self._newPage(width, height)
        return self.page
    def openTypeFeatures(self, *args, **features):
        """Enables OpenType features and return the current openType features
        settings.

        If no arguments are given `openTypeFeatures()` will just return the
        current openType features settings.

        .. downloadcode:: openTypeFeaturesFormattedString.py

            size(1000, 200)
            # create an empty formatted string object
            t = FormattedString()
            # set a font
            t.font("ACaslonPro-Regular")
            # set a font size
            t.fontSize(60)
            # add some text
            t += "0123456789 Hello"
            # enable some open type features
            t.openTypeFeatures(smcp=True, lnum=True)
            # add some text
            t += " 0123456789 Hello"
            # draw the formatted string
            text(t, (10, 80))
        """
        if args and features:
            raise PageBotError("Can't combine positional arguments and keyword arguments")
        if args:
            if len(args) != 1:
                raise PageBotError("There can only be one positional argument")
            if args[0] is not None:
                raise PageBotError("First positional argument can only be None")
            logger.warning("openTypeFeatures(None) is deprecated, use openTypeFeatures(resetFeatures=True) instead.")
            self._openTypeFeatures.clear()
        else:
            if features.pop("resetFeatures", False):
                self._openTypeFeatures.clear()
            self._openTypeFeatures.update(features)
        currentFeatures = self.listOpenTypeFeatures()
        currentFeatures.update(self._openTypeFeatures)
        return currentFeatures
 def fallbackFont(self, font):
     """Sets a fallback font, used whenever a glyph is not available in the
     normal font. If a font path is given the font will be installed and
     used directly."""
     if font:
         font = _tryInstallFontFromFontName(font)
         font = str(font)
         testFont = AppKit.NSFont.fontWithName_size_(font, self._fontSize)
         if testFont is None:
             raise PageBotError("Fallback font '%s' is not available" % font)
     self._fallbackFont = font
     return font
    def text(self,
             txt,
             offset=None,
             font=_FALLBACKFONT,
             fontSize=10,
             align=None):
        """Draws a `txt` with a `font` and `fontSize` at an `offset` in the
        Bézier path. If a font path is given the font will be installed and
        used directly.

        - Optionally an alignment can be set.
        - Possible `align` values are: `"left"`, `"center"` and `"right"`.
        - The default alignment is `left`.
        - Optionally `txt` can be a `FormattedString`.
        """
        context = BaseContext()

        if align and align not in self._textAlignMap.keys():
            raise PageBotError("align must be %s" %
                               (", ".join(self._textAlignMap.keys())))

        context.font(font, fontSize)
        attributedString = context.attributedString(txt, align)
        w, h = attributedString.size()
        w *= 2

        if offset:
            x, y = offset
        else:
            x = y = 0
        if align == "right":
            x -= w
        elif align == "center":
            x -= w * .5

        setter = CoreText.CTFramesetterCreateWithAttributedString(
            attributedString)
        path = Quartz.CGPathCreateMutable()
        Quartz.CGPathAddRect(path, None, Quartz.CGRectMake(x, y, w, h * 2))
        frame = CoreText.CTFramesetterCreateFrame(setter, (0, 0), path, None)
        ctLines = CoreText.CTFrameGetLines(frame)
        origins = CoreText.CTFrameGetLineOrigins(frame, (0, len(ctLines)),
                                                 None)

        if origins:
            y -= origins[0][1]

        self.textBox(txt,
                     box=(x, y, w, h * 2),
                     font=font,
                     fontSize=fontSize,
                     align=align)
Exemple #13
0
 def addPoint(self, point, segmentType=None, smooth=False, name=None,
         identifier=None, **kwargs):
     """Use the path as a point pen and add a point to the current subpath.
     `beginPath` must have been called prior to adding points with
     `addPoint` calls."""
     if not hasattr(self, "_pointToSegmentPen"):
         msg = "path.beginPath() must be called before the path can be used as a point pen."
         raise PageBotError(msg)
     self._pointToSegmentPen.addPoint(
         point,
         segmentType=segmentType,
         smooth=smooth,
         name=name,
         identifier=identifier,
         **kwargs
     )
Exemple #14
0
    def endPath(self):
        """Ends the current subpath. Calling this method has two distinct
        meanings depending on the context:

        When the Bézier path is used as a segment pen (using `moveTo`,
        `lineTo`, etc.), the current subpath will be finished as an open
        contour.

        When the Bézier path is used as a point pen (using `beginPath`,
        `addPoint` and `endPath`), the path will process all the points added
        with `addPoint`, finishing the current subpath."""
        if hasattr(self, "_pointToSegmentPen"):
            pointToSegmentPen = self._pointToSegmentPen
            del self._pointToSegmentPen
            pointToSegmentPen.endPath()
        else:
            msg = "path.beginPath() must be called before the path can be used as a point pen."
            raise PageBotError(msg)
Exemple #15
0
 def restore(self):
     if not self._stack:
         raise PageBotError("can't restore graphics state: no matching save()")
     self._state = self._stack.pop()
     #self._state.update(self)
     self._restore()
Exemple #16
0
 def saveImage(self, path, options):
     if not self.hasPage:
         raise PageBotError("can't save image when no page is set")
     self._saveImage(path, options)
Exemple #17
0
 def lineCap(self, cap):
     if cap is None:
         self._state.lineCap = None
     if cap not in self._lineCapStylesMap:
         raise PageBotError("lineCap() argument must be 'butt', 'square' or 'round'")
     self._state.lineCap = self._lineCapStylesMap[cap]
Exemple #18
0
 def lineJoin(self, join):
     if join is None:
         self._state.lineJoin = None
     if join not in self._lineJoinStylesMap:
         raise PageBotError("lineJoin() argument must be 'bevel', 'miter' or 'round'")
     self._state.lineJoin = self._lineJoinStylesMap[join]