Beispiel #1
0
    def __init__(self,
                 glyphName,
                 font,
                 lineColor=None,
                 lineWidth=None,
                 **kwargs):
        Element.__init__(self, **kwargs)
        self.font = font
        self.glyphName = glyphName
        self.lineColor = lineColor or (0, 0, 1)  # Color of metrics lines
        self.lineWidth = lineWidth or 0.5  # Thickness of metrics lines
        self.fontSize = self.h  # As start assume the full height of the element as fontSize

        # Create a style for it, so we can draw the glyph(s) as Text.
        style = dict(font=self.font,
                     fontSize=self.fontSize,
                     textFill=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
            # Make a new string with the fitting fontSize
            style['fontSize'] = self.fontSize  # Adjust the existing style
            self.bs = BabelString(self.glyphName, style=style)
Beispiel #2
0
    def compose(self, doc, page, parent=None):
        """Compose the cell as background color, with recipes text block on top.

        """
        label = self._getLabel()
        bs = BabelString(label, self.style)
        tw, th = bs.textSize

        if self.layout == SPOTSAMPLE:
            # Mark abbreviated color recipes by parenthesis.
            # They are not an exact match, but closest known value for this color.

            # Used padding-bottom (self.pb) also as gutter between color rectangle and labels
            e = Rect(x=0, y=th+self.pb, w=self.w, h=self.h-th-self.pb, fill=self.c)
            self.addElement(e)

            e = Text(bs, x=self.w/2, y=th-self.style.get('lineHeight', 0) + self.pb, w=self.w, h=self.h)
            self.addElement(e)

        else: # Default layout is OVERLAY
            e = Rect(x=0, y=0, w=self.w, h=self.h, fill=self.c)
            self.addElement(e)

            e = Text(bs, x=self.w/2, y=th-self.style.get('lineHeight', 0) + self.pb, w=self.w, h=self.h)
            self.addElement(e)
Beispiel #3
0
    def oneColumnPage(cls, theme, doc, page=None, parent=None, pageNumbers=None, **kwargs):
        """
        >>> from pagebotnano.document import Document
        >>> from pagebotnano.themes import BackToTheCity
        >>> template = OneColumnTemplate()
        >>> theme = BackToTheCity()
        >>> doc = Document()
        >>> page = template.oneColumnPage(theme, doc, pageNumbers=NONE)
        >>> page.compose(doc)
        >>> page.find(MAIN)
        <TextBox name=mainText w=535 h=782>
        >>> page = doc.newPage(template=oneColumnPage)
        """
        page = cls._initialize(theme, doc, page, parent)
        # Add text element with the main text column of this page
        e = TextBox('', name=MAIN, x=page.pl, y=page.pb, w=page.pw, h=page.ph)
        page.addElement(e)

        if pageNumbers is None:
            pageNumbers = [LEFT, RIGHT]
        if LEFT in pageNumbers and page.pn % 2 == 0: # Even page number?:
            bs = BabelString(str(page.pn), style)
            e = Text(bs, name=PN_LEFT, x=page.pl, y=page.pb/2)
            page.addElement(e)
        if CENTER in pageNumbers:
            e = Text('', name=PN_CENTER, x=page.pl+page.pw, y=page.pb/2)
            page.addElement(e)
        if RIGHT in pageNumbers:
            e = Text('', name=PN_RIGHT, x=page.pl+page.pw, y=page.pb/2)
            page.addElement(e)
        return page
Beispiel #4
0
    def page(self, doc):
        """
        >>> from pagebotnano.document import Document
        >>> from pagebotnano.themes import BackToTheCity
        >>> templates = OneColumnTemplates()
        >>> templates
        <OneColumnTemplates>
        >>> theme = BackToTheCity()
        >>> doc = Document(theme=theme, templates=templates)
        >>> page = templates.cover(doc) # The "page" template always must be there.
        >>> page.compose(doc)
        """
        page = self._initialize(doc, True)
        # Add text element with the main text column of this page
        e = TextBox('', name=MAIN, x=page.pl, y=page.pb, w=page.pw, h=page.ph)
        page.addElement(e)

        leftPageNumberStyle = doc.theme.getStyle('leftPageNumber')
        centerPageNumberStyle = doc.theme.getStyle('centerPageNumber')
        rightPageNumberStyle = doc.theme.getStyle('rightPageNumber')

        if leftPageNumberStyle is not None and page.pn % 2 == 0:  # Even page number?:
            bs = BabelString(str(page.pn), style)
            e = Text(bs, name=PN_LEFT, x=page.pl, y=page.pb / 2)
            page.addElement(e)
        if centerPageNumberStyle is not None:
            e = Text('', name=PN_CENTER, x=page.pl + page.pw, y=page.pb / 2)
            page.addElement(e)
        if rightPageNumberStyle is not None and page.pn % 2 != 0:  # Odd page number?:
            e = Text('', name=PN_RIGHT, x=page.pl + page.pw, y=page.pb / 2)
            page.addElement(e)
        return page
Beispiel #5
0
 def __init__(self, bs, x, y, w=None, h=None, name=None, 
     fill=None, stroke=None, strokeWidth=None):
     # Call the base element with all standard attributes.
     Element.__init__(self, x=x, y=y, w=w, h=h, name=name, 
         fill=fill, stroke=stroke, strokeWidth=strokeWidth)
     if not isinstance(bs, BabelString):
         bs = BabelString(bs)
     self.bs = bs # Store the BabelString in self.
Beispiel #6
0
    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.
        """
        labelStyle = dict(font=self.font,
                          fontSize=7,
                          textFill=0,
                          lineHeight=8,
                          aligh=LEFT)
        style = dict(font=self.font,
                     fontSize=self.fontSizes[0],
                     textFill=0,
                     align=LEFT)
        bs = BabelString('', style)
        tw, th = bs.textSize
        for fontSize in self.fontSizes:
            labelLine = BabelString(' %d pt' % fontSize, labelStyle)
            ltw, lth = labelLine.textSize

            style['fontSize'] = fontSize
            style['lineHeight'] = fontSize * self.leading
            sample = self.sample
            textLine = BabelString(sample, style)
            stw, sth = textLine.textSize

            while sample and self.w and stw + ltw > self.w:
                # If not fitting, shorten the string until it does
                sample = sample[:-1]
                textLine = BabelString(sample, style)
                stw, sth = textLine.textSize
            if self.h and th + sth > self.h:
                break  # No vertical space left, skip the rest of the fontSizes.

            bs += BabelString(
                '\n' + sample, style
            ) + labelLine  # There still is vertical space, add the textLine
            tw, th = bs.textSize

        e = Text(bs, x=ox, y=oy + self.h)
        page.h = page.pb + page.pt + th
        page.addElement(e)
Beispiel #7
0
    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.
        TODO: For large sizes, compensate for the side beatings of straight stems.
        """
        y = self.h
        for word in self.words:
            if self.fontChoice:
                fontName = choice(self.fontChoice)
            else:
                fontName = self.font
            if self.theme is None:
                textColor = Color(0)
            else:
                textColor = self.theme.randomTextColor
            style = dict(font=fontName, textFill=textColor, align=LEFT)
            if self.capsOnly:
                word = word.upper()
            style[
                'fontSize'] = fontSize = 100  # Start with large guess of fontSize
            textLine = BabelString(word, style)
            tlw, tlh = textLine.textSize

            style['fontSize'] = fontSize = fontSize * self.w / tlw
            textLine = BabelString(word, style)  # Get a new scaled version
            tlw, tlh = textLine.textSize
            if tlh > y:  # Not fitting this word vertical anymore, try other.
                continue

            if self.capsOnly:
                y -= doc.context.fontCapHeight(self.font, fontSize)
            else:
                y -= doc.context.fontAscender(self.font, fontSize)
            e = Text(textLine, x=ox, y=oy + y)
            page.addElement(e)

            if not self.capsOnly:
                y += doc.context.fontDescender(self.font, fontSize)
            y -= fontSize * (self.leading - 1) + self.gh
Beispiel #8
0
 def addPageNumberXXX(self, page, pad, leftStyle, rightStyle):
     # Add text element with page number
     if page.pn % 2 == 0:  # Even page number?
         style = leftStyle
         x = pad
     else:  # Odd page number
         style = rightStyle
         x = page.w - pad
     pn = BabelString(str(page.pn), style)
     # Center the page number.
     #e = Text(pn, page.w/2, pad/2)
     e = Text(pn, x=x, y=pad * 3 / 4, w=page.w - 2 * pad, fill=0.9)
     page.addElement(e)
Beispiel #9
0
    def compose(self, doc, parent=None):
        """Compose the cell as background color, with recipes text block on top.

        """
        label = self._getLabel()

        if self.layout == SPOTSAMPLE:
            # Mark approximated color recipes by parenthesis.
            # They are not an exact match, but closest known value for this color.

            bs = BabelString(label, self.style)
            tw, th = bs.textSize

            # Used padding-bottom (self.pb) also as gutter between color rectangle and labels
            e = Rect(x=self.pl, y=th+self.pb, w=self.pw, h=self.h-th-self.pb, fill=self.c)
            self.addElement(e)

            e = Text(bs, x=self.w/2, y=th-self.style.get('fontSize') + self.pb, w=self.w, h=self.h)
            self.addElement(e)

        else: # Default layout is OVERLAY. 
            # Check the text color to be enough contrast with the background.
            # Otherwise flip between black and white.
            style = copy(self.style) # Copy as we are going to alter it
            if self.c.gray < 0.33: # Dark color?
                labelText = color(1) # White label text
            else:
                labelText = color(0) # Black label text
            style['fill'] = labelText
            bs = BabelString(label, style)
            tw, th = bs.textSize

            e = Rect(x=self.pl, y=self.pb, w=self.pw, h=self.ph, fill=self.c)
            self.addElement(e)

            e = Text(bs, x=self.w/2, y=th-self.style.get('fontSize')*2/3 + self.pb, w=self.w, h=self.h)
            self.addElement(e)
Beispiel #10
0
    def compose(self, doc, page, parent=None):
        """Compose the cell as background color, with recipes text block on top.

        """
        e = Rect(x=0, y=0, w=self.w, h=self.h, fill=self.c)
        self.addElement(e)

        # Mark approximated color recipes by parenthesis.
        # They are not an exact match, but closest known value for this color.
        Cmyk, cMyk, cmYk, cmyK = self.c.cmyk 
        s = '#%s\n(%s)\n(cmyk %d %d %d %d)\n(Spot %s)\n(RAL %s)' % \
            (self.c.hex, self.c.name.capitalize(), Cmyk*100, cMyk*100, cmYk*100, cmyK*100, 
                self.c.spot, self.c.ral)
        if self.themePosition is not None:
            s += '\nColor[%d][%d]' % (base, shade)
        bs = BabelString(s, self.style)
        tw, th = bs.textSize
        e = Text(bs, x=self.w/2, y=th-self.style.get('lineHeight', 0)/2, w=self.w, h=self.h)
        self.addElement(e)
Beispiel #11
0
    def cover(self, doc):
        page = self._initialize(doc, True)
        # Fill the cover page with a theme background color
        e = Rect(0, 0, page.w, page.h,
                 fill=doc.theme.getColor(1, 4))  # Dark cover color
        page.addElement(e)

        # Add title and author, centered on top-half of the cover.
        try:
            title = doc.cd.elements[0].bs
        except (IndexError, AttributeError):
            title = BabelString('Untitled')
        e = TextBox(title,
                    name='Title',
                    x=page.pl / 2,
                    y=page.h / 2,
                    w=page.pw,
                    h=page.ph / 2)
        page.addElement(e)

        e = Image(x=page.pl, y=page.pb, w=page.pw)
        page.addElement(e)
        return page
Beispiel #12
0
                font=fontName2,
                x=page.pl + cw + GUTTER_X,
                y=page.pt,
                w=cw,
                h=page.ph,
                gh=GUTTER_Y,
                capsOnly=capsOnly,
                fill=0.9)
    page.addElement(e)

    footNoteStyle = dict(font=labelFontName,
                         tracking=0.5,
                         fontSize=labelSize,
                         fill=labelColor,
                         align=LEFT)
    bs = BabelString('TYPETR ' + fontName1, footNoteStyle)
    e = Text(bs, x=page.pl, y=page.pb / 2, w=page.pw)
    page.addElement(e)

    footNoteStyle = dict(font=labelFontName,
                         tracking=0.5,
                         fontSize=labelSize,
                         fill=labelColor,
                         align=LEFT)
    bs = BabelString('TYPETR ' + fontName1, footNoteStyle)
    e = Text(bs, x=page.pl, y=page.pb / 2, w=page.pw)
    page.addElement(e)

    footNoteStyle['align'] = RIGHT
    bs = BabelString('Generated by PageBotNano', footNoteStyle)
    e = Text(bs, x=page.pl + page.pw, y=page.pb / 2, w=page.pw)
Beispiel #13
0
 def textBox(self, bs, r):
     # Set the cache from the overflow, we don't have the source anymore
     overFlow = BabelString(hyphenation=bs.hyphenation)
     overFlow.fs = drawBot.textBox(bs.fs, r)
     return overFlow  # Return this “incomplete” BabelString.
Beispiel #14
0
    def compose(self, doc, parent=None):
        """Compose the self.elements with ColorCell instances, as now we 
        know the actual size of self.
        Draw the cells of the theme in the given element size.
        """
        if self.theme is None:
            self.theme = doc.theme or DefaultTheme()
        if self.labelStyle is None:
            self.labelStyle = dict(font=FONT_NAME, fontSize=self.FONT_SIZE, align=CENTER,
                lineHeight=self.FONT_SIZE*self.LEADING) 
        if self.labels is None:
            self.labels = (HEX,)

        fontName = self.labelStyle.get('fontName', self.FONT_NAME)
        fontSize = self.labelStyle.get('fontSize', self.FONT_SIZE)
        textFill = self.theme.colors[0][4]
        backgroundFill = self.theme.getColor(0,2)

        if self.titleStyle and not isinstance(self.titleStyle, dict):
            self.titleStyle = dict(font=fontName, fontSize=fontSize*2, 
                fill=textFill, lineHeight=fontSize*2*self.LEADING) 
        if self.captionStyle and not isinstance(self.captionStyle, dict):
            self.captionStyle = dict(font=fontName, fontSize=fontSize, 
                fill=textFill, lineHeight=self.LEADING) 

        cols = len(self.theme.colors[0])
        rows = len(self.theme.colors)
        cw = self.pw/cols # Column width
        ch = self.ph/rows # Column height
        for shade in range(cols):
            for base in range(rows):
                # Get the color from the theme color matrix and add as rectangle
                # This is the extended example, instead of using the ColorCell element.
                c = self.theme.colors[base][shade]
                # If textColor not defined, then get it from the theme, based on the
                # darkness of the current color.
                tc = self.theme.textColor(base, shade)

                # The ColorCell element takes care of showing the color as rectangle
                # and the lines of various recipes on top.
                e = ColorCell(c, x=self.pl+shade*cw, y=self.pb+base*ch, w=cw, h=ch, 
                    themePosition=(shade, base), layout=self.layout, labels=self.labels, 
                    style=self.labelStyle, padding=self.cellPadding)
                e.pb = self.labelStyle['lineHeight']
                self.addElement(e)
                e.compose(doc, parent=self) # Do recursive compose.

        if self.titleStyle:        
            # Add background rectangle on top with theme name and mood. getColor(shade, base)
            bs = BabelString('%s – %s' % (self.theme.name, self.theme.mood), self.titleStyle)
            tw, th = bs.textSize
            e = Text(bs, x=self.pl+fontSize/2, y=self.h-self.pt*2/3, w=self.w)
            self.addElement(e)

        if self.captionStyle:
            bs = BabelString('Colors with (parenthesis) are approximated to the closest recipe.', 
                self.captionStyle)
            tw, th = bs.textSize
            e = Text(bs, x=self.pl, y=self.pb-th, w=self.pw)
            self.addElement(e)

            captionStyle2 = copy(self.captionStyle)
            captionStyle2['align'] = RIGHT
            bs = BabelString('Generated by PageBotNano', captionStyle2)
            tw, th = bs.textSize
            e = Text(bs, x=self.pl+self.pw, y=self.pb-th, w=self.pw)
            self.addElement(e)
Beispiel #15
0
    def compose(self):
        """This is the core of a publication, composing the specific
        content of the document. The compose method gets called
        before building and exporting the self.doc document.
        """
        fontSize = 11
        headSize = fontSize*1.5
        titleSize = 36
        subTitleSize = titleSize * 0.5
        pad = 48

        self.theme.styles['h1'] = dict(font='Georgia-Bold', 
            lineHeight=titleSize*1.1, 
            fontSize=titleSize,
            align=CENTER,
            fill=1, # White title on dark cover background
            language=EN, hyphenation=False,
        )
        self.theme.styles['h2'] = dict(font='Georgia-Italic',
            paragraphTopSpacing=subTitleSize/2,
            lineHeight=subTitleSize*1.2, 
            fontSize=subTitleSize,
            align=CENTER,
            fill=1, # White title on dark cover background
            language=EN, hyphenation=False,
        )
        headStyle = dict(font='Georgia', 
            lineHeight=headSize*1.3, 
            fontSize=headSize,
            fill=0, # Black text
            language=EN, hyphenation=False,
        )
        subHeadStyle = dict(font='Georgia-Italic', 
            lineHeight=headSize*0.8*1.4, 
            fontSize=headSize*0.8,
            fill=0, # Black text
            language=EN, hyphenation=False,
        )
        bodyStyle = dict(font='Georgia', 
            lineHeight=fontSize*1.4, 
            fontSize=fontSize,
            fill=0, # Black text
            language=EN, hyphenation=True,
        )
        pageNumberLeftStyle = dict(
            font='Georgia', 
            fontSize=9,
            fill=0, # Black text
            align=LEFT, 
        )
        pageNumberRightStyle = copy(pageNumberLeftStyle)
        pageNumberRightStyle['align'] = RIGHT


        # Make the cover page.
        page = coverPage(self.theme, self.doc)

        # Make “French” “Voordehandse” page.
        page = self.doc.newPage() # No page number here.

        # CENTER text alignment overwrites the value in headStyle.
        # fontSize overwrites the value in headStyle
        bs = BabelString('AAAA'+'\n', headStyle, fontSize=fontSize, align=CENTER)
        e = Text(bs, x=page.w/2, y=page.h*4/5)
        page.addElement(e)

        # Make Title page.
        page = titlePage(self.theme, self.doc)
        page.compose(self.doc, page)
        bs = BabelString('VVVVV'+'\n', headStyle, align=CENTER)
        bs.append(BabelString('AUTHOR', subHeadStyle, align=CENTER))
        page.find(MAIN).bs = bs

        # For all the elements that are collected in the galley, assume that
        # the TextBoxes are chapters, creating a new page for them.
        # If the TextBox does not fit on the page, keep adding new pages 
        # until all of the BabelString overfill is processed.

        for ge in self.galley.elements:

            if isinstance(ge, TextBox):

                bs = ge.bs # Get the BabelString from the galley box.

                for n in range(self.MAX_PAGES):
                    page = self.doc.newPage()

                    # Add text element with page number
                    self.addPageNumber(page, pad, pageNumberLeftStyle, pageNumberRightStyle)

                    # Add text element with the main text column of this page
                    e = TextBox(bs, x=pad, y=pad, w=page.w-2*pad, h=page.h-2*pad)
                    page.addElement(e)

                    # If there is overflow on this page, continue looping creating
                    # as many pages as needed to fill all the text in self.content.
                    # Otherwise break the loop, as we are done placing content.
                    bs = e.getOverflow(bs, doc=self.doc)
                    # Test on this “incomplete” BabelString, as it only has a cached FS
                    if not bs.fs:
                        break

            elif isinstance(ge, Image): # Images not supported yet
                page = self.doc.newPage()

                self.addPageNumber(page, pad, pageNumberLeftStyle, pageNumberRightStyle)
                page.addElement(ge)
                ge.w = page.w - pad
                iw, ih = ge.getSize(self.doc)
                ge.x = pad/2
                ge.y = page.h - pad - ih