Navigation

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Users
    • Groups
    • Solved
    • Unsolved
    • Search
    1. Home
    2. gferreira
    3. Best
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    Best posts made by gferreira

    • RE: Variable Font Animation Jiggle

      hello @paul,

      I’ve adapted your script to use the Skia font, and was able to reproduce the issue. I think it‘s related to hinting and text rasterization on low resolutions.

      you can reduce the jiggle effect by converting the text to curves – that is, setting it with BezierPath instead of text().

      the script below generates two movies for comparison, one with each approach.

      w = 1080
      h = 1080
      customFont = 'Skia'
      nframes = 500
      fps = 30
      
      var = listFontVariations(customFont)
      varMin = var['wght']['minValue']
      varMax = var['wght']['maxValue']
      
      for mode in range(2):
          for i in range(nframes):
              newPage(w, h)
              frameDuration(1.0/fps)
              fill(1)
              rect(0, 0, w, h)
              fill(0)    
              wt = varMin + i * ((varMax - varMin) / nframes)
      
              # mode 0: text as text
              if mode == 0:
                  font(customFont, 200)
                  fontVariations(wght=wt)
                  text("Hamburg", (w/2, h/2-100), align="center")
              
              # mode 1: text as bezierPath
              else:
                  txt = FormattedString()
                  txt.append("Hamburg", font=customFont, fontSize=200, fontVariations=dict(wght=wt))
                  B = BezierPath()
                  B.text(txt, (w/2, h/2-100), align="center")
                  drawPath(B)
          
          saveImage(f"animation-{mode}.mp4")
          newDrawing()
      

      hope this helps! cheers

      posted in Bugs
      gferreira
      gferreira
    • RE: Add fontVariation to text drawn in bezierPath?

      hi. you can use a FormattedString:

      txt = FormattedString()
      txt.append("hello world", font='Skia', fontSize=150, fontVariations=dict(wdth=0.8, wght=1.3))
      
      B = BezierPath()
      B.text(txt, (100, 100))
      
      drawPath(B)
      
      posted in General Discussion
      gferreira
      gferreira
    • RE: access a specific frame from a gif

      hello @eduairet,

      you can use the pageNumber argument in image or imageSize to get a given frame in a multipage image (gif or pdf). important: page numbering starts at 1.

      see Inserting a PDF

      path = '~/Desktop/image.gif'
      pageCount = numberOfPages(path)
      
      for pageNumber in range(1, pageCount+1):
          w, h = imageSize(path, pageNumber=pageNumber)
          newPage(w, h)
          image(path, (0, 0), pageNumber=pageNumber)
      

      cheers!

      posted in General Discussion
      gferreira
      gferreira
    • RE: Stroke alignment in shape

      hello @guidoferreyra,

      ovals and rects are also available as methods of BezierPath, so you can use that same solution to draw the stroke inwards.

      to draw the stroke outwards, you can draw the shape with a doubled stroke first, and then draw it again on top using only the fill (so the internal half of the stroke is covered).

      here’s an updated example showing all 3 “stroke modes”:

      stroke-modes.png

      STROKEWIDTH = 20
      
      B = BezierPath()
      B.text('a', (0, 0), fontSize=1200)
      # B.rect(0, 0, 500, 500)
      # B.oval(0, 0, 500, 500)
      
      size(2200, 1000)
      translate(50, 100)
      fontSize(72)
      
      for option in ['inside', 'center', 'outside']:
      
          text(option, (100, 780))
          save()        
          stroke(1, 0, 0)
      
          if option == 'inside':
              strokeWidth(STROKEWIDTH * 2)
              with savedState():
                  clipPath(B)
                  drawPath(B)
      
          elif option == 'outside':
              strokeWidth(STROKEWIDTH * 2)
              drawPath(B)
              stroke(None)
              drawPath(B)
      
          else:
              strokeWidth(STROKEWIDTH)
              drawPath(B)
      
          restore()
          translate(700, 0)
      

      hope this helps! cheers

      posted in General Discussion
      gferreira
      gferreira
    • RE: Oval() point placement

      hello @ryan,

      I dont’t know why the extremes are angled…

      here’s a way to get the desired result by modifying oval:

      def twist(func, angle):
          def wrapper(x, y, w, h):
              with savedState():
                  translate(x + w/2, y + h/2)
                  rotate(angle)
                  func(-w/2, -h/2, w, h)
          return wrapper
      
      oval = twist(oval, 45)
      

      when working with BezierPath, it’s possible to rotate the shape:

      B = BezierPath()
      B.oval(x, y, w, h)
      B.rotate(45, (x + w/2, y + h/2))
      

      hope this helps!

      posted in General Discussion
      gferreira
      gferreira
    • RE: Manipulating points

      @michelangelo you can use DrawBot inside RoboFont with the DrawBot extension

      posted in General Discussion
      gferreira
      gferreira
    • RE: RFont subclass not generating "otf"

      hello @RicardGarcia,

      for a simple interpolation between two masters you can use font.interpolate(factor, font1, font2) – see this example script.

      hope this helps!

      posted in General Discussion
      gferreira
      gferreira
    • RE: Changing a list derived from a reference list also changes the reference list?

      hello @MauriceMeilleur,

      assigning a list to a new variable does not create a new list, just a new reference to the same list. (this also applies to dictionaries; both are mutable object types.)

      there are different ways to create a copy of a list:

      A = [1, 2, 3]
      B = A.copy() # or list(A) # or A[:]
      B.append(4)
      print(A)
      print(B)
      

      cheers!

      posted in General Discussion
      gferreira
      gferreira
    • RE: Delete previously made pages

      hello @ryan,

      I think newDrawing() is what you’re looking for.

      cheers!

      posted in General Discussion
      gferreira
      gferreira
    • RE: Problems with cv2? Alternative for resizing saved images on the fly?

      hello @MauriceMeilleur,

      you can set a different resolution when saving images in DrawBot. this can produce a different size in pixels than the document size (in points):

      size(100, 100)
      rect(10, 10, 80, 80)
      imgPath = '~/Desktop/malevich.png'
      saveImage(imgPath, imageResolution=144) # 200% = 72dpi * 2
      print(imageSize(imgPath))
      # (200, 200)
      

      you can also try using PIL/Pillow.

      cheers!

      posted in General Discussion
      gferreira
      gferreira
    • RE: OTF file: accessing contours & segments

      hello @RicardGarcia,

      a BezierPath is similar to a glyph. here’s how you can access the contours, segments and points:

      B = BezierPath()
      B.text('a', font='Menlo-Bold', fontSize=1000)
      
      for contour in B.contours:
          print(contour)
          for segment in contour:
              print(segment) # a segment is a list of points
          print()
      

      there’s also points, onCurvePoints and offCurvePoints.

      I hope this is what you’re looking for… cheers!

      posted in General Discussion
      gferreira
      gferreira
    • RE: Load font from filepath

      hi @lnp,

      the font() command can take a font name OR a path to a font file as argument:

      font('myFolder/myFont.ttf')
      

      cheers!

      posted in General Discussion
      gferreira
      gferreira
    • RE: Import python file.

      @snaders right, I forgot to mention: to update the contents of a module, you need to reload it:

      from importlib import reload
      import settings
      reload(settings)
      
      from settings import *
      print(aVariable)
      print(anotherVariable)
      

      cheers!

      posted in General Discussion
      gferreira
      gferreira
    • RE: Import python file.

      @MauriceMeilleur this can be a start. but creating and using a library involves a bit more:

      relative imports installed module
      imported files must be in the same folder as the main script imported files can be elsewhere
      module is imported directly with a relative import module must be installed in Python (for example appending to sys.path or using a .pth file)
      module is available only for scripts in the same folder module is available for all Python scripts

      see How To Write Modules in Python 3 for a step-by-step guide about creating your own modules.

      good luck!

      posted in General Discussion
      gferreira
      gferreira
    • RE: PDF adding pages to existing file

      ps. see also this character set proof example using the DrawBot extension in RoboFont.

      posted in General Discussion
      gferreira
      gferreira
    • RE: Sorting glyphs by "density"

      hello @RicardGarcia,

      there are probably different ways to define the ‘density’ of a glyph. in this example, it is defined as the ratio between the glyph area and the total glyph box area:

      from fontTools.pens.areaPen import AreaPen
      
      CHARS = 'abcdefghijklmnopqrstuvwxyz$%&@'
      FONTNAME = 'Menlo-Bold'
      FONTSIZE = 1000
      
      # set font properties
      fontSize(FONTSIZE)
      font(FONTNAME)
      lineHeight(FONTSIZE)
      
      # measure glyph densities and collect values in a dict
      densities = {}
      
      for char in CHARS:
      
          # get total area for glyph
          w, h = textSize(char)
      
          # get area of 'black' surface
          B = BezierPath()
          B.text(char, (0, 0), font=FONTNAME, fontSize=FONTSIZE)
          pen = AreaPen()
          B.drawToPen(pen)
          area = abs(pen.value)
      
          # calculate density as percentage of black
          density = area / (w * h)
      
          # store density value in dict
          densities[char] = density
      

      you could also calculate density by rasterizing the glyph and counting the black pixels…

      hope this helps!

      posted in General Discussion
      gferreira
      gferreira
    • RE: How do I size an image with the ImageObject (or without)?

      hi @ThunderNixon,

      placing images is a job for image(); imageObject() is for creating or modifying raster images inside DrawBot.

      to draw an image at a given size:

      1. get the width and height of the image
      2. define the intended width and height
      3. calculate the X and Y scaling factors
      4. apply the scaling factors & draw the image

      in code:

      imgPath = 'someFolder/myImage.png'
      
      # 1
      srcWidth, srcHeight = imageSize(imgPath)
      
      # 2
      dstWidth, dstHeight = 500, 800
      
      # 3
      factorWidth  = dstWidth  / srcWidth
      factorHeight = dstHeight / srcHeight
      
      # 4
      with savedState():
          scale(factorWidth, factorHeight)
          image(imgPath, (0, 0))
      

      cheers!

      posted in General Discussion
      gferreira
      gferreira
    • RE: Vector/BezierPath distortion methods?

      the bump distortion filter might be useful for sketching and experimenting:

      bumpDistortion.png

      size(400, 400)
      
      steps = 9
      gridX = width()  / steps
      gridY = height() / steps
      
      im = ImageObject()
      black = False
      with im:
          for x in range(steps):
              for y in range(steps):
                  if black:
                      fill(0,)
                      rect(x * gridX, y * gridY, gridX, gridY)
                  black = not black
              if not steps % 2:
                  black = not black
      
      im.bumpDistortion(center=(width()/2, height()/2), radius=200, scale=0.8)
      image(im, im.offset())
      
      saveImage('bumpDistortion.png')
      
      posted in General Discussion
      gferreira
      gferreira
    • RE: Overlapping paths

      @MauriceMeilleur thanks for the points. remove overlap also works as expected with a lineTo-only version of the shape:

      pts = [(-125.0, 275.0), (-125.0, -100.0), (-125.0, -99.99999999999999), (-125.0, -113.80711874576983), (-113.80711874576983, -124.99999999999999), (-100.0, -124.99999999999999), (125.0, -125.0), (125.0, 100.0), (125.0, 100.0), (125.0, 113.80711874576983), (113.80711874576983, 125.0), (100.0, 125.0), (-275.0, 125.0), (-275.0, 275.0), (100.0, 275.0), (99.99999999999999, 275.0), (196.64983122038882, 275.0), (275.0, 196.64983122038882), (275.0, 100.0), (275.0, -275.0), (-100.0, -275.0), (-100.00000000000003, -275.0), (-196.64983122038888, -275.0), (-275.0, -196.64983122038882), (-275.0, -99.99999999999997), (-275.0, 275.0), (-125.0, 275.0)]
      
      B = BezierPath()
      for i, pt in enumerate(pts):
          if i == 0:
              B.moveTo(pt)
          else:
              B.lineTo(pt)
      B.closePath()
      
      # (un)comment this line to test
      # B.removeOverlap()
      
      newPage(800, 800)
      translate(400, 400)
      fill(None)
      stroke(1, 0, 0)
      strokeWidth(8)
      drawPath(B)
      

      I don’t think the lack of curveTos plays a role in the result (but you never know).

      let’s try it the other way around: can you provide a simple example in code of a shape where the whole path is erased when removing overlap? thanks!

      posted in General Discussion
      gferreira
      gferreira
    • RE: Overlapping paths

      hello @MauriceMeilleur,

      I’ve created a simplified version of your shape for testing (see below). remove overlap works as expected, the inner shape is preserved:

      removeOverlapTest.gif

      B = BezierPath()
      B.moveTo((10, 90))
      B.lineTo((90, 90))
      B.lineTo((90, 10))
      B.lineTo((10, 10))
      B.lineTo((10, 90))
      B.lineTo((40, 90))
      B.lineTo((40, 40))
      B.lineTo((60, 40))
      B.lineTo((60, 60))
      B.lineTo((10, 60))
      B.closePath()
      
      newPage(100, 100)
      frameDuration(3)
      fill(None)
      stroke(1, 0, 0)
      drawPath(B)
      
      B.removeOverlap()
      
      newPage(100, 100)
      frameDuration(3)
      fill(None)
      stroke(1, 0, 0)
      drawPath(B)
      
      # saveImage('removeOverlapTest.gif')
      

      it would help if you could post your actual bezier points, so we can see if it’s a problem in the data.

      ps. the color scheme is a nice reminder to add an illustration to the arcTo docs 🙂

      posted in General Discussion
      gferreira
      gferreira