Group Details Private

administrators

  • RE: QRCodeGenerator(size, message)

    maybe the callback should convert incoming str to bytes, or the docs must change. Im make an issue --> https://github.com/typemytype/drawbot/issues/411

    posted in General Discussion
  • RE: QRCodeGenerator(size, message)

    hello @eduairet,

    when working with QRCodeGenerator:

    • data must be in bytes
    • size must be a tuple

    this works:

    path = bytes('http://www.drawbot.com/', 'utf-8')
    
    w, h = 31, 31
    
    img = ImageObject()
    img.QRCodeGenerator((w, h), path, 'Q')
    
    size(w, h)
    image(img, (0, 0))
    

    the third parameter (L, M, Q or H) determines the correction level, see the Core Image docs for more info.

    hope this helps! cheers

    ps. the resulting image is tiny (1 pixel per bit). you can scale it by reading the pixel values and redrawing it with shapes:

    path = bytes('http://www.drawbot.com/', 'utf-8')
    
    w, h = 31, 31
    s = 10
    
    img = ImageObject()
    img.QRCodeGenerator((w, h), path, 'Q')
    
    size(w*s, h*s)
    for x in range(w):
        for y in range(h):
            c = imagePixelColor(img, (x, y))
            fill(*c)
            rect(x*s, y*s, s, s)
    
    posted in General Discussion
  • RE: Markdown syntax for FormattedString?

    hello @djrrb,

    I think this error was introduced in markdown 3.3 (new htmlparser).

    I don’t know how to fix it, but you can install an earlier version of markdown which still works:

    pip install markdown==3.2.2
    

    cheers

    posted in Feature Requests
  • RE: Boustrophedonic typesetting

    @imik glad to hear that. cheers!!

    posted in Code snippets
  • RE: Reading pixel values (rgb or brightness) on coordinations

    hello @snaders,

    yes, you can read image pixel values with imagePixelColor(). it’s a bit slow though, use it with caution… good luck!

    posted in General Discussion
  • Boustrophedonic typesetting

    boustrophedonic.png

    txt = "Boustrophedon is a type of bi-directional text, mostly seen in ancient manuscripts and other inscriptions. Alternate lines of writing are flipped, or reversed, with reversed letters. Rather than going left-to-right as in modern European languages, or right-to-left as in Arabic and Hebrew, alternate lines in boustrophedon must be read in opposite directions. Also, the individual characters are reversed, or mirrored. It was a common way of writing in stone in ancient Greece.".upper()
    
    
    def boustrophedonicTextBox(txt, box, drawFrame=False):
    
        x, y, w, h = box
        L = fontLineHeight()
    
        save()
        translate(x, y-L)
    
        T = ''
        lineLength = 0
        backward = False
        words = txt.split()
        lineCount = 0
        overflow = ''
    
        for i, word in enumerate(words):
    
            # add word to current line
            if lineLength + textSize(word)[0] <= w:
                T += word + ' '
                lineLength += textSize(word + ' ')[0]
    
            # break to next line
            else:
                # no more space for new line
                if not (lineCount+1) * L < h:
                    overflow = T + ' '.join(words[i:])
                    break
    
                # draw current line
                with savedState():
                    # flip direction
                    if backward:
                        scale(-1, 1)
                    text(T, (0, 0), align='center')
    
                # begin new line
                translate(0, -L)
                backward = not backward
                lineCount += 1
                T = word + ' '
                lineLength = textSize(word + ' ')[0]
    
            # draw last line
            if i == len(words)-1:
                lineCount += 1
                with savedState():
                    if backward:
                        scale(-1, 1)
                    text(T, (0, 0), align='center')
    
        restore()
    
        if drawFrame:
            with savedState():
                fill(None)
                stroke(1, 0, 0)
                rect(x - w/2, y, w, -h)
    
        return overflow
    
    
    font('Skia')
    fontSize(36)
    lineHeight(66)
    txt = boustrophedonicTextBox(txt, (width()/2, height()-100, width()-80, 800), drawFrame=False)
    
    print(txt)
    
    posted in Code snippets
  • RE: Different fonts in a text box

    hello @mït,

    I think I understand what you mean – it’s not so easy because, once a piece of text is drawn into the page, you can’t really ‘search’ for it anymore.

    it can be done if you lay out the text yourself: word by word, line by line, page by page. the example script below is based on this one.

    Screen Shot 2020-09-21 at 12.51.01.png

    TXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
    FONT = 'Menlo-Bold'
    FONTSIZE = 36
    LINEHEIGHT = 120
    WIDTH = 570
    X, Y = 150, 900
    HIGHLIGHT = 'voluptate'
    PAGEHIGHLIGHT = None
    
    # start with an empty string, add words one by one
    T = FormattedString(font=FONT, fontSize=FONTSIZE, lineHeight=FONTSIZE*1.2)
    
    # set text properties globally - needed for correct measurements with `textSize`
    font(FONT)
    fontSize(FONTSIZE)
    
    # variables to keep track of the current line
    lineLength = 0
    lineNumber = 1
    lineY = Y
    
    # iterate over words in text
    for word in TXT.split():
    
        # if word fits in the current line, add word to line
        if lineLength + textSize(word)[0] <= WIDTH:
            T += word + ' '
            lineLength += textSize(word + ' ')[0]
    
        # word does not fit in current line, make a new line
        else:        
    
            # if next line does not fit in current page, start a new page
            if lineY - LINEHEIGHT < 0:
                newPage()
                font(FONT)
                fontSize(FONTSIZE)
                lineY = Y
                
            # draw the current line
            text(T, (X, lineY))
    
            # check if highlight word was in this line and page
            if HIGHLIGHT in str(T):
                PAGEHIGHLIGHT = pageCount()
                color = (1, 0, 0)
            else: 
                color = (0.7,)
            fill(*color)
            text(str(lineNumber), (X-50, lineY), align='right')
    
            # make a fresh new line, add word to line
            T = FormattedString(font=FONT, fontSize=FONTSIZE, lineHeight=FONTSIZE*1.2)
            T += word + ' '
    
            # update variables for new line
            lineLength = textSize(word + ' ')[0]
            lineNumber += 1
            lineY -= LINEHEIGHT
    
    # draw page numbers, check if highlight word in page
    for i, page in enumerate(pages()):
        with page:
            color = (1, 0, 0) if (i+1) == PAGEHIGHLIGHT else (0.7,)
            fill(*color)
            text(str(i+1), (width()-50, Y), align='right')
    

    hope this makes sense!

    posted in General Discussion
  • RE: Different fonts in a text box

    pageCount() returning the current page count -->https://www.drawbot.com/content/canvas/pages.html#drawBot.pageCount

    textBoxCharacterBounds (I see its not added to the docs yet..) returning a list of typesetted bounding boxes with characters and a subsetted formattedString

    help(textBoxCharacterBounds)  # :)
    

    hope this helps with your puzzle!

    posted in General Discussion
  • RE: Different fonts in a text box

    hello @mït,

    not sure if we can call it clean 🙂 but here’s a way to apply formatting to a FormattedString a posteriori using a simple find & replace:

    txt = '''Some title here
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempus justo in finibus condimentum. Proin vitae mauris ac nibh elementum consectetur. Aenean justo mi, cursus vel placerat vitae, gravida in mi.
    '''
    
    def applyFormatting(formattedString, findText, styleDict):
    
        start = str(formattedString).find(findText)
        end = start + len(findText)
        
        before = formattedString[:start]
        after  = formattedString[end:]
    
        replaceText = formattedString.copy()
        replaceText.clear()
        replaceText.append(findText, **styleDict)
    
        return before + replaceText + after
    
    T = FormattedString(txt, fontSize=36, font="Arial")
    
    T = applyFormatting(T, 'Some title here', dict(fontSize=72, font='Times New Roman', paragraphBottomSpacing=20))
    T = applyFormatting(T, 'sit amet', dict(font='Arial Bold', fill=(1, 0, 0),))
    T = applyFormatting(T, 'condimentum', dict(font='Arial Italic', fill=(0, 1, 0),))
    
    while len(T):
        newPage('A4')
        T = textBox(T, (20, 20, width() - 40, height() - 40))
    

    adding support for markdown or html markup to FormattedString would be super useful!

    hope this helps

    posted in General Discussion
  • RE: Different fonts in a text box

    hello @mït,

    you can change text properties in the FormattedString, before passing it to textBox.

    like this:

    T = FormattedString(fontSize=42)
    T.font("Arial")
    T.append('Lorem ipsum dolor ')
    
    T.font("Arial Bold")
    T.append('sit amet, ')
    
    T.font("Arial")
    T.append('consectetur adipiscing elit. Nulla tempus justo in finibus ')
    
    T.font("Arial Italic")
    T.append('condimentum. ')
    
    T.font("Arial")
    T.append('Proin vitae mauris ac nibh elementum consectetur. Aenean justo mi, cursus vel placerat vitae, gravida in mi.')
    
    while len(T):
        newPage('A4')
        T = textBox(T, (10, 10, width() - 20, height() - 20))
    

    hope this helps! cheers

    posted in General Discussion