Example #1
0
    def draw(self):
        rotation = self.rotation
        center = self.surface_width / 2.0
        r = self.radius + 1
        for i in range(0, len(self.colors)):
            brush = Brush(rgb_to_rgba(self.colors[i]))
            vertices = [center, center]
            for i in range(0, 4):
                r_shift = -0.25 if i < 2 else 1.25
                r_shift -= rotation
                func = cos if i % 2 else sin
                vertices.append(r + r * func(radians(r_shift + 180)))
            self.surface.polygon(vertices, brush)
            rotation += 360.0 / len(self.colors)
        self.surface.flush()

        # Create annulus mask and apply it to colour disc
        mask = Image.new('L', (self.surface_width, self.surface_height), 0)
        d = Draw(mask)
        xy_1 = center - (self.radius - self.thickness / 2.0)
        xy_2 = center + (self.radius - self.thickness / 2.0)
        path_pen = Pen(255, self.thickness)
        d.ellipse([xy_1, xy_1, xy_2, xy_2], path_pen, self.transparent_brush)
        d.flush()
        self.canvas.putalpha(mask)

        return self.canvas
    def getProgressItems(self, curStepIndex, steps):
        total = len(steps)
        marginTop = 4
        dia = 9
        space = 12

        image = Image.new("RGB", (self.width, dia + int(marginTop * 1.5)))
        draw = Draw(image)

        w = ((dia + space) * total) - space
        marginLeft = (self.width - w) / 2

        for s in range(total):
            left = marginLeft + ((dia + space) * s)
            draw.ellipse((left, marginTop, left + dia, marginTop + dia),
                         Pen(self.colors[steps[s]]),
                         Brush(self.colors[steps[s]]))
            if curStepIndex < s:
                draw.ellipse(
                    (left + (dia * 0.25), marginTop + (dia * 0.25), left +
                     (dia * 0.75), marginTop + (dia * 0.75)), Pen("#000"),
                    Brush("#000"))
        draw.flush()

        return image
Example #3
0
 def get_image(self, im_width, im_length):
     im = Image.new("RGBA", (im_width, im_length),
                    (0, 0, 0, MAX_COLOR))  # Black image
     draw = Draw(im)
     for shape in self.shapes_list:
         shape.draw(draw)
     draw.flush()
     return im
Example #4
0
def test_graphics2():
    """See issue #14."""
    from aggdraw import Draw, Symbol, Pen
    from PIL import Image
    import numpy as np
    symbol = Symbol("M400 200 L400 400")
    pen = Pen("red")
    image = Image.fromarray(np.zeros((800, 600, 3)), mode="RGB")
    canvas = Draw(image)
    canvas.symbol((0, 0), symbol, pen)
    canvas.flush()
    assert np.asarray(image).sum() == 50800
    async def loading(self):
        image = Image.new("RGB", (self.width, self.height))

        draw = Draw(image)

        colors = list(self.colors.values())
        draw.ellipse((50, 59, 60, 69), Pen(colors[0]), Brush(colors[0]))
        draw.ellipse((75, 59, 85, 69), Pen(colors[1]), Brush(colors[1]))
        draw.ellipse((100, 59, 110, 69), Pen(colors[2]), Brush(colors[2]))

        draw.flush()

        self.display(image)
    def circleProgressLeft(self, percent, color):
        dia = 44

        image = Image.new("RGB", (dia + 6, dia + 6))

        draw = Draw(image)
        pen = Pen(self.colors[color], 6)

        radian = percent * 360
        draw.arc((3, 3, dia + 3, dia + 3), 450 - radian, 90, pen)

        draw.flush()

        return image
Example #7
0
def draw_text(frame, x, y, text, size=16, color='white'):

    im = Image.fromarray(frame)
    draw = Draw(im)
    _, fh = draw.size

    font = Font(color, os.path.join(os.path.dirname(__file__), './Reith.ttf'),
                DRAW_SCALE_FACTOR)

    text_w, text_h = draw.textsize(text, font)
    y -= text_h
    draw.text((x + 2, y + 4), text, font)
    draw.flush()

    return np.array(im)
Example #8
0
def make_marker(radius, fill_color, stroke_color, stroke_width, opacity=1.0):
    """
    Creates a map marker and returns a PIL image.

    radius
        In pixels

    fill_color
        Any PIL-acceptable color representation, but standard hex
        string is best

    stroke_color
        See fill_color

    stroke_width
        In pixels

    opacity
        Float between 0.0 and 1.0
    """
    # Double all dimensions for drawing. We'll resize back to the original
    # radius for final output -- it makes for a higher-quality image, especially
    # around the edges
    radius, stroke_width = radius * 2, stroke_width * 2
    diameter = radius * 2
    im = Image.new('RGBA', (diameter, diameter))
    draw = Draw(im)
    
    
    
    # Move in from edges half the stroke width, so that the stroke is not
    # clipped.
    half_stroke_w = (stroke_width / 2 * 1.0) + 1
    min_x, min_y = half_stroke_w, half_stroke_w
    max_x = diameter - half_stroke_w
    max_y = max_x
    bbox = (min_x, min_y, max_x, max_y)
    # Translate opacity into aggdraw's reference (0-255)
    opacity = int(opacity * 255)
    draw.ellipse(bbox,
                 Pen(stroke_color, stroke_width, opacity),
                 Brush(fill_color, opacity))
    draw.flush()
    # The key here is to resize using the ANTIALIAS filter, which is very
    # high-quality
    im = im.resize((diameter / 2, diameter / 2), Image.ANTIALIAS)
    return im
Example #9
0
def make_marker(radius, fill_color, stroke_color, stroke_width, opacity=1.0):
    """
    Creates a map marker and returns a PIL image.

    radius
        In pixels

    fill_color
        Any PIL-acceptable color representation, but standard hex
        string is best

    stroke_color
        See fill_color

    stroke_width
        In pixels

    opacity
        Float between 0.0 and 1.0
    """
    # Double all dimensions for drawing. We'll resize back to the original
    # radius for final output -- it makes for a higher-quality image, especially
    # around the edges
    radius, stroke_width = radius * 2, stroke_width * 2
    diameter = radius * 2
    im = Image.new('RGBA', (diameter, diameter))
    draw = Draw(im)
    # Move in from edges half the stroke width, so that the stroke is not
    # clipped.
    half_stroke_w = (stroke_width / 2 * 1.0) + 1
    min_x, min_y = half_stroke_w, half_stroke_w
    max_x = diameter - half_stroke_w
    max_y = max_x
    bbox = (min_x, min_y, max_x, max_y)
    # Translate opacity into aggdraw's reference (0-255)
    opacity = int(opacity * 255)
    draw.ellipse(bbox,
                 Pen(stroke_color, stroke_width, opacity),
                 Brush(fill_color, opacity))
    draw.flush()
    # The key here is to resize using the ANTIALIAS filter, which is very
    # high-quality
    im = im.resize((diameter / 2, diameter / 2), Image.ANTIALIAS)
    return im
    async def circleProgress(self, percent, text=""):
        image = Image.new("RGB", (self.width, self.height))

        draw = Draw(image)
        pen = Pen("white", 7)

        radian = percent * 3.6
        draw.arc((50, 34, 110, 94), 450 - radian, 90, pen)

        draw.flush()
        imDraw = ImageDraw.Draw(image)

        if len(text) > 0:
            text = text.capitalize()
            w, h = imDraw.textsize(text, font=self.fonts['prompt'])
            imDraw.text(((self.width - w) / 2, (self.height - h) / 2),
                        text,
                        font=self.fonts['prompt'],
                        align="center",
                        fill="#fff")

        image = invert(image)
        self.display(image)
Example #11
0
def _fill_annotations(a: Annotation, label: str, color=0xFF, out=None):
    if out is None:
        out = Image.new(mode='L', size=a.image.size)

    brush = Brush(color)

    d = Draw(out)
    d.setantialias(False)

    for o in a.iter_objects(label):
        xy = a.points(o)
        d.polygon(xy.flatten(), brush)

    return d.flush()
Example #12
0
 def round_corner_jpg(image, radius):
     """Round a JPG image"""
     mask = Image.new('L', image.size)
     draw = Draw(mask)
     brush = Brush('white')
     width, height = mask.size
     draw.pieslice((0, 0, radius * 2, radius * 2), 90, 180, None, brush)
     draw.pieslice((width - radius * 2, 0, width, radius * 2), 0, 90, None,
                   brush)
     draw.pieslice((0, height - radius * 2, radius * 2, height), 180, 270,
                   None, brush)
     draw.pieslice((width - radius * 2, height - radius * 2, width, height),
                   270, 360, None, brush)
     draw.rectangle((radius, radius, width - radius, height - radius),
                    brush)
     draw.rectangle((radius, 0, width - radius, radius), brush)
     draw.rectangle((0, radius, radius, height - radius), brush)
     draw.rectangle((radius, height - radius, width - radius, height),
                    brush)
     draw.rectangle((width - radius, radius, width, height - radius), brush)
     draw.flush()
     image = image.convert('RGBA')
     image.putalpha(mask)
     return image
Example #13
0
def _stroke_annotations(a: Annotation,
                        label: str,
                        color=0xFF,
                        width=5,
                        out=None):
    if out is None:
        out = Image.new(mode='L', size=a.image.size)

    pen = Pen(color, width)

    d = Draw(out)
    d.setantialias(False)  # Should not antialias masks

    for o in a.iter_objects(label):
        xy = a.points(o)
        d.polygon(xy.flatten(), pen)

    return d.flush()
Example #14
0
from PIL import Image
from aggdraw import Draw, Brush
transBlack = (0, 0, 0, 0)  # shows your example with visible edges
solidBlack = (0, 0, 0, 255)  # shows shape on a black background
transWhite = (255, 255, 255, 0)
solidWhite = (255, 255, 255, 255)

im = Image.new("RGBA", (600, 600), solidBlack)

draw = Draw(im)

brush = Brush("yellow")

draw.polygon((
    50,
    50,
    550,
    60,
    550,
    550,
    60,
    550,
), None, brush)

draw.flush()
im.save("squar.png")
im.show()
Example #15
0
class Canvas(CanvasBase):
  # fonts appear smaller in aggdraw than with cairo
  # fix that here:
  fontScale = 1.2

  def __init__(self,
               img=None,
               imageType=None,  # determines file type
               fileName=None,  # if set determines output file name
               size=None, ):
    if img is None:
      try:
        import Image
      except ImportError:
        from PIL import Image
      if size is None:
        raise ValueError('please provide either an image or a size')
      img = Image.new('RGBA', size, "white")
    self.image = img
    self.draw = Draw(img)
    self.draw.setantialias(True)
    if size is None:
      self.size = self.draw.size
    else:
      self.size = size
    if imageType and imageType not in ('png', 'jpg'):
      raise ValueError('unsupported image type for agg canvas')
    self.drawType = imageType
    self.fileName = fileName

  def _doLine(self, p1, p2, pen, **kwargs):
    if kwargs.get('dash', (0, 0)) == (0, 0):
      self.draw.line((p1[0], p1[1], p2[0], p2[1]), pen)
    else:
      dash = kwargs['dash']
      pts = self._getLinePoints(p1, p2, dash)

      currDash = 0
      dashOn = True
      while currDash < (len(pts) - 1):
        if dashOn:
          p1 = pts[currDash]
          p2 = pts[currDash + 1]
          self.draw.line((p1[0], p1[1], p2[0], p2[1]), pen)
        currDash += 1
        dashOn = not dashOn

  def addCanvasLine(self, p1, p2, color=(0, 0, 0), color2=None, **kwargs):
    if color2 and color2 != color:
      mp = (p1[0] + p2[0]) / 2., (p1[1] + p2[1]) / 2.
      color = convertColor(color)
      self._doLine(p1, mp, Pen(color, kwargs.get('linewidth', 1)), **kwargs)
      color2 = convertColor(color2)
      self._doLine(mp, p2, Pen(color2, kwargs.get('linewidth', 1)), **kwargs)
    else:
      color = convertColor(color)
      self._doLine(p1, p2, Pen(color, kwargs.get('linewidth', 1)), **kwargs)

  def addCanvasText(self, text, pos, font, color=(0, 0, 0), **kwargs):
    orientation = kwargs.get('orientation', 'E')
    color = convertColor(color)
    aggFont = Font(color, faceMap[font.face], size=font.size * self.fontScale)

    blocks = list(re.finditer(r'\<(.+?)\>(.+?)\</\1\>', text))
    w, h = 0, 0
    supH = 0
    subH = 0
    if not len(blocks):
      w, h = self.draw.textsize(text, aggFont)
      tw, th = w, h
      offset = w * pos[2]
      dPos = pos[0] - w / 2. + offset, pos[1] - h / 2.
      self.draw.text(dPos, text, aggFont)
    else:
      dblocks = []
      idx = 0
      for block in blocks:
        blockStart, blockEnd = block.span(0)
        if blockStart != idx:
          # untagged text:
          tblock = text[idx:blockStart]
          tw, th = self.draw.textsize(tblock, aggFont)
          w += tw
          h = max(h, th)
          dblocks.append((tblock, '', tw, th))
        fmt = block.groups()[0]
        tblock = block.groups()[1]
        if fmt in ('sub', 'sup'):
          lFont = Font(color, faceMap[font.face], size=0.8 * font.size * self.fontScale)
        else:
          lFont = aggFont
        tw, th = self.draw.textsize(tblock, lFont)
        w += tw
        if fmt == 'sub':
          subH = max(subH, th)
        elif fmt == 'sup':
          supH = max(supH, th)
        else:
          h = max(h, th)
        dblocks.append((tblock, fmt, tw, th))
        idx = blockEnd
      if idx != len(text):
        # untagged text:
        tblock = text[idx:]
        tw, th = self.draw.textsize(tblock, aggFont)
        w += tw
        h = max(h, th)
        dblocks.append((tblock, '', tw, th))

      supH *= 0.5
      subH *= 0.5
      h += supH + subH
      offset = w * pos[2]
      if orientation == 'W':
        dPos = [pos[0] - w + offset, pos[1] - h / 2.]
      elif orientation == 'E':
        dPos = [pos[0] + offset, pos[1] - h / 2.]
      else:
        dPos = [pos[0] - w / 2. + offset, pos[1] - h / 2.]

      if supH:
        dPos[1] += supH
      for txt, fmt, tw, th in dblocks:
        tPos = dPos.copy()
        if fmt == 'sub':
          tPos[1] += subH
        elif fmt == 'sup':
          tPos[1] -= supH
        if fmt in ('sub', 'sup'):
          lFont = Font(color, faceMap[font.face], size=0.8 * font.size * self.fontScale)
        else:
          lFont = aggFont
        self.draw.text(tPos, txt, lFont)
        dPos[0] += tw
    return (tw + th * .4, th + th * .4, offset)

  def addCanvasPolygon(self, ps, color=(0, 0, 0), fill=True, stroke=False, **kwargs):
    if not fill and not stroke:
      return 
    dps = []
    for p in ps:
      dps.extend(p)
    color = convertColor(color)
    brush = None
    pen = None
    if fill:
      brush = Brush(color)
    if stroke:
      pen = Pen(color)
    self.draw.polygon(dps, pen, brush)

  def addCanvasDashedWedge(self, p1, p2, p3, dash=(2, 2), color=(0, 0, 0), color2=None, **kwargs):
    pen = Pen(color, kwargs.get('linewidth', 1))
    dash = (3, 3)
    pts1 = self._getLinePoints(p1, p2, dash)
    pts2 = self._getLinePoints(p1, p3, dash)

    if len(pts2) < len(pts1):
      pts2, pts1 = pts1, pts2

    for i in range(len(pts1)):
      self.draw.line((pts1[i][0], pts1[i][1], pts2[i][0], pts2[i][1]), pen)

  def flush(self):
    self.draw.flush()
    if self.fileName:
      self.image.save(self.fileName)
Example #16
0
class Canvas(CanvasBase):
  # fonts appear smaller in aggdraw than with cairo
  # fix that here:
  fontScale=1.2
  def __init__(self, img=None,
               imageType=None, # determines file type
               fileName=None,  # if set determines output file name
               size=None,
               ):
    if img is None:
      import Image
      if size is None:
        raise ValueError,'please provide either an image or a size'
      img = Image.new('RGBA',size,"white")
    self.image = img
    self.draw = Draw(img)
    self.draw.setantialias(True)
    if size is None:
      self.size = self.draw.size
    else:
      self.size = size
    if imageType and imageType not in ('png','jpg'):
      raise ValueError,'unsupported image type for agg canvas'
    self.drawType=imageType
    self.fileName=fileName
    
  def _doLine(self, p1, p2, pen, **kwargs):
    if kwargs.get('dash',(0,0)) == (0,0):
      self.draw.line((p1[0],p1[1],p2[0],p2[1]),pen)
    else:
      dash = kwargs['dash']
      pts = self._getLinePoints(p1,p2,dash)

      currDash = 0
      dashOn = True
      while currDash<(len(pts)-1):
        if dashOn:
          p1 = pts[currDash]
          p2 = pts[currDash+1]
          self.draw.line((p1[0],p1[1],p2[0],p2[1]),pen)
        currDash+=1
        dashOn = not dashOn

  def addCanvasLine(self, p1, p2, color=(0,0,0), color2=None, **kwargs):
    if color2 and color2!=color:
      mp = (p1[0]+p2[0])/2.,(p1[1]+p2[1])/2.
      color = convertColor(color)
      self._doLine(p1,mp,Pen(color,kwargs.get('linewidth',1)),**kwargs)
      color2 = convertColor(color2)
      self._doLine(mp,p2,Pen(color2,kwargs.get('linewidth',1)),**kwargs)
    else:
      color = convertColor(color)
      self._doLine(p1,p2,Pen(color,kwargs.get('linewidth',1)),**kwargs)

  def addCanvasText(self,text,pos,font,color=(0,0,0),**kwargs):
    orientation=kwargs.get('orientation','E')
    color = convertColor(color)
    aggFont = Font(color,faceMap[font.face],size=font.size*self.fontScale)

    blocks = list(re.finditer(r'\<(.+?)\>(.+?)\</\1\>',text))
    w,h = 0,0
    supH=0
    subH=0
    if not len(blocks):
      w,h=self.draw.textsize(text,aggFont)
      bw,bh=w*1.1,h*1.1
      dPos = pos[0]-bw/2.,pos[1]-bh/2.
      bgColor=kwargs.get('bgColor',(1,1,1))
      bgColor = convertColor(bgColor)
      self.draw.rectangle((dPos[0],dPos[1],dPos[0]+bw,dPos[1]+bh),
                       None,Brush(bgColor))
      dPos = pos[0]-w/2.,pos[1]-h/2.
      self.draw.text(dPos,text,aggFont)
    else:
      dblocks=[]
      idx=0
      for block in blocks:
        blockStart,blockEnd=block.span(0)
        if blockStart != idx:
          # untagged text:
          tblock = text[idx:blockStart]
          tw,th=self.draw.textsize(tblock,aggFont)
          w+=tw
          h = max(h,th)
          dblocks.append((tblock,'',tw,th))
        fmt = block.groups()[0]
        tblock = block.groups()[1]
        if fmt in ('sub','sup'):
          lFont = Font(color,faceMap[font.face],size=0.8*font.size*self.fontScale)
        else:
          lFont = aggFont
        tw,th=self.draw.textsize(tblock,lFont)
        w+=tw
        if fmt == 'sub':
          subH = max(subH,th)
        elif fmt=='sup':
          supH = max(supH,th)
        else:
          h = max(h,th)
        dblocks.append((tblock,fmt,tw,th))
        idx = blockEnd
      if idx!=len(text):
        # untagged text:
        tblock = text[idx:]
        tw,th=self.draw.textsize(tblock,aggFont)
        w+=tw
        h = max(h,th)
        dblocks.append((tblock,'',tw,th))
        
      supH *= 0.25
      subH *= 0.25
      h += supH + subH
      bw,bh=w*1.1,h
      #dPos = pos[0]-bw/2.,pos[1]-bh/2.
      dPos = [pos[0]-w/2.,pos[1]-h/2.]
      if orientation=='W':
        dPos = [pos[0]-w,pos[1]-h/2.]
      elif orientation=='E':
        dPos = [pos[0],pos[1]-h/2.]
      else:
        dPos = [pos[0]-w/2,pos[1]-h/2.]

      bgColor=kwargs.get('bgColor',(1,1,1))
      bgColor = convertColor(bgColor)
      self.draw.rectangle((dPos[0],dPos[1],dPos[0]+bw,dPos[1]+bh),
                          None,Brush(bgColor))
      if supH: dPos[1]+=supH
      for txt,fmt,tw,th in dblocks:
        tPos = dPos[:]
        if fmt=='sub':
          tPos[1]+=subH
        elif fmt=='sup':
          tPos[1]-=supH
        if fmt in ('sub','sup'):
          lFont = Font(color,faceMap[font.face],size=0.8*font.size*self.fontScale)
        else:
          lFont = aggFont
        self.draw.text(tPos,txt,lFont)
        dPos[0]+=tw


  def addCanvasPolygon(self,ps,color=(0,0,0),fill=True,stroke=False,**kwargs):
    if not fill and not stroke: return
    dps = []
    for p in ps:
      dps.extend(p)
    color = convertColor(color)
    brush=None
    pen=None
    if fill:
      brush = Brush(color)
    if stroke:
      pen = Pen(color)
    self.draw.polygon(dps,pen,brush)
 
  def addCanvasDashedWedge(self,p1,p2,p3,dash=(2,2),color=(0,0,0),
                           color2=None,**kwargs):
    pen = Pen(color,kwargs.get('linewidth',1))
    dash = (3,3)
    pts1 = self._getLinePoints(p1,p2,dash)
    pts2 = self._getLinePoints(p1,p3,dash)

    if len(pts2)<len(pts1): pts2,pts1=pts1,pts2

    for i in range(len(pts1)):
      self.draw.line((pts1[i][0],pts1[i][1],pts2[i][0],pts2[i][1]),pen)

  def flush(self):
    self.draw.flush()
    if self.fileName:
      self.image.save(self.fileName)
Example #17
0
class ELCustomDisplay(pylink.EyeLinkCustomDisplay, EnvAgent):

    #TODO: add scaling support for images without ruining performance (OpenGL scale?)

    def __init__(self):
        EnvAgent.__init__(self)
        self.size = (0, 0)
        self.imagebuffer = []
        self.palette = []
        self.img = None  # PIL.Image
        self.drawer = None  # aggdraw Draw with self.img as context
        self.title = None

        self.txtm.add_style("el_setup",
                            "20px",
                            P.default_color,
                            font_label="Hind-Medium")
        self.dc_target = drift_correct_target()

        pylink.EyeLinkCustomDisplay.__init__(self)

        # If using an EyeLink 1000 or newer, these commands need to be sent
        # to the tracker for everything to work correctly
        if self.el.getTrackerVersion() >= EYELINK_1000:
            self.el.sendCommand("enable_search_limits=YES")
            self.el.sendCommand("track_search_limits=YES")
            self.el.sendCommand("autothreshold_click=YES")
            self.el.sendCommand("autothreshold_repeat=YES")
            self.el.sendCommand("enable_camera_position_detect=YES")

        # Define dict mapping sdl2 keycodes to pylink keycodes
        self.pylink_keycodes = dict([(sdl2.SDLK_F1, pylink.F1_KEY),
                                     (sdl2.SDLK_F2, pylink.F2_KEY),
                                     (sdl2.SDLK_F3, pylink.F3_KEY),
                                     (sdl2.SDLK_F4, pylink.F4_KEY),
                                     (sdl2.SDLK_F5, pylink.F5_KEY),
                                     (sdl2.SDLK_F6, pylink.F6_KEY),
                                     (sdl2.SDLK_F7, pylink.F7_KEY),
                                     (sdl2.SDLK_F8, pylink.F8_KEY),
                                     (sdl2.SDLK_F9, pylink.F9_KEY),
                                     (sdl2.SDLK_F10, pylink.F10_KEY),
                                     (sdl2.SDLK_PAGEUP, pylink.PAGE_UP),
                                     (sdl2.SDLK_PAGEDOWN, pylink.PAGE_DOWN),
                                     (sdl2.SDLK_UP, pylink.CURS_UP),
                                     (sdl2.SDLK_DOWN, pylink.CURS_DOWN),
                                     (sdl2.SDLK_LEFT, pylink.CURS_LEFT),
                                     (sdl2.SDLK_RIGHT, pylink.CURS_RIGHT),
                                     (sdl2.SDLK_RETURN, pylink.ENTER_KEY),
                                     (sdl2.SDLK_ESCAPE, pylink.ESC_KEY),
                                     (sdl2.SDLK_BACKSPACE, ord('\b')),
                                     (sdl2.SDLK_TAB, ord('\t'))])

        # Define dict mapping pylink colour constants to RGB colours
        self.pylink_colors = [
            (0, 0, 0),  # 0 = placeholder (transparent)
            (255, 255, 255),  # 1 = pylink.CR_HAIR_COLOR (white)        
            (255, 255, 255),  # 2 = pylink.PUPIL_HAIR_COLOR (white)
            (0, 255, 0),  # 3 = pylink.PUPIL_BOX_COLOR (green)
            (255, 0, 0),  # 4 = pylink.SEARCH_LIMIT_BOX_COLOR (red)
            (255, 0, 0)  # 5 = pylink.MOUSE_CURSOR_COLOR (red)
        ]

        try:
            self.__target_beep__ = AudioClip("target_beep.wav")
            self.__target_beep__done__ = AudioClip("target_beep_done.wav")
            self.__target_beep__error__ = AudioClip("target_beep_error.wav")
        except:
            self.__target_beep__ = None
            self.__target_beep__done__ = None
            self.__target_beep__error__ = None

    def record_abort_hide(self):
        pass

    def clear_cal_display(self):
        fill()
        flip()
        fill()

    def setup_cal_display(self):
        self.clear_cal_display()

    def exit_cal_display(self):
        self.clear_cal_display()

    def draw_cal_target(self, x, y=None, pump_events=True):
        fill()
        if pump_events: pump()
        if y is None:
            y = x[1]
            x = x[0]
        blit(self.dc_target, 5, (int(x), int(y)))
        flip()

    def erase_cal_target(self):
        self.clear_cal_display()

    def play_beep(self, clip):
        try:
            if clip in [pylink.DC_TARG_BEEP, pylink.CAL_TARG_BEEP]:
                self.__target_beep__.play()
            elif clip in [pylink.CAL_ERR_BEEP, pylink.DC_ERR_BEEP]:
                self.__target_beep__error__.play()
            else:
                self.__target_beep__done__.play()
        except:
            pass

    def get_input_key(self):
        keys = []
        for event in pump(True):
            if event.type == sdl2.SDL_KEYDOWN:
                keysym = event.key.keysym
                if not self.el._quitting:
                    # don't process quit requests while already quitting
                    ui_request(keysym)
                try:
                    key = self.pylink_keycodes[keysym.sym]
                except KeyError:
                    key = keysym.sym
                # don't allow escape to control tracker unless calibrating
                if key == pylink.ESC_KEY and not self.el.in_setup:
                    key = pylink.JUNK_KEY
                keys.append(pylink.KeyInput(key, keysym.mod))
        return keys

    def get_mouse_state(self):
        x, y, b = mouse_pos(pump_event_queue=False, return_button_state=True)
        x = int(x) - (P.screen_c[0] - self.size[0] / 2)
        y = int(y) - (P.screen_c[1] - self.size[1] / 2)
        # Restrict mouse coords to within bounds of camera image
        x = clip(x, minimum=0, maximum=self.size[0])
        y = clip(y, minimum=0, maximum=self.size[1])
        if b != 1:  # Register left clicks only
            b = 0
        return ((x, y), b)

    def alert_printf(self, message):
        print("EyeLink Alert: {0}".format(message))

    def setup_image_display(self, width, height):
        '''Sets camera image to the provided size, returns 1 on success.'''
        self.size = (width, height)
        self.clear_cal_display()
        return 1

    def exit_image_display(self):
        self.clear_cal_display()

    def image_title(self, text):
        self.title = message(text, "el_setup", blit_txt=False)

    def set_image_palette(self, r, g, b):
        '''
		Sets the palette to use for the camera image and clears the image buffer.
		Converts r,g,b (lists containing the RGB palette) to a list of colours
		([R,G,B,R,G,B,...]) that can be used by PIL.Image.
		'''
        self.imagebuffer = []
        self.palette = list(sum(zip(r, g, b), ()))

    def draw_image_line(self, width, line, totlines, buff):
        '''
		Reads in the buffer from the EyeLink camera image line by line and writes it
		into a buffer of size (width * totlines). Once the last line of the image
		has been read into the buffer, the image buffer is placed in a PIL.Image
		with the palette set by set_image_palette, converted to RGBA, resized,
		and then rendered to the middle of the screen. After rendering, the image
		buffer is cleared.
		'''
        if len(self.imagebuffer) > (width * totlines):
            self.imagebuffer = []
        self.imagebuffer += buff
        if int(line) == int(totlines):
            # Render complete camera image and resize to self.size
            img = Image.new("P", (width, totlines), 0)
            img.putpalette(self.palette)
            img.putdata(self.imagebuffer)
            self.img = img.convert('RGBA').resize(self.size, Image.BILINEAR)
            # Set up aggdraw to draw crosshair/bounds/etc. on image surface
            self.drawer = Draw(self.img)
            self.drawer.setantialias(True)
            self.draw_cross_hair()
            self.drawer.flush()
            # Draw complete image to screen
            fill()
            blit(asarray(self.img), 5, P.screen_c)
            if self.title:
                loc_x = (P.screen_c[0])
                loc_y = (P.screen_c[1] + self.size[1] / 2 + 20)
                blit(self.title, 8, (loc_x, loc_y))
            flip()
            # Clear image buffer
            self.imagebuffer = []

    def draw_lozenge(self, x, y, width, height, colorindex):
        lozenge_pen = Pen(self.pylink_colors[colorindex], 3, 255)
        if width > height:
            gap = width - height
            middle = x + width / 2.0
            arc_left = (x, y, x + height, y + height)
            arc_right = (x + gap, y, x + width, y + height)
            line_top = (floor(middle - gap / 2.0), y, ceil(middle + gap / 2.0),
                        y)
            line_bottom = (floor(middle - gap / 2.0), y + height,
                           ceil(middle + gap / 2.0), y + height)
            self.drawer.arc(arc_left, 90, 270, lozenge_pen)
            self.drawer.arc(arc_right, -90, 90, lozenge_pen)
            self.drawer.line(line_top, lozenge_pen)
            self.drawer.line(line_bottom, lozenge_pen)
        elif height > width:
            gap = height - width
            middle = y + height / 2.0
            arc_top = (x, y, x + width, y + width)
            arc_bottom = (x, y + gap, x + width, y + height)
            line_left = (x, floor(middle - gap / 2.0), x,
                         ceil(middle + gap / 2.0))
            line_right = (x + width, floor(middle - gap / 2.0), x + width,
                          ceil(middle + gap / 2.0))
            self.drawer.arc(arc_top, 0, 180, lozenge_pen)
            self.drawer.arc(arc_bottom, 180, 360, lozenge_pen)
            self.drawer.line(line_left, lozenge_pen)
            self.drawer.line(line_right, lozenge_pen)
        else:
            self.drawer.ellipse((x, y, x + width, y + height), lozenge_pen)

    def draw_line(self, x1, y1, x2, y2, colorindex):
        line_pen = Pen(self.pylink_colors[colorindex], 3, 255)
        self.drawer.line((x1, y1, x2, y2), line_pen)
Example #18
0
def test_flush():
    from aggdraw import Draw
    from PIL import Image
    im = Image.new("RGB", (600, 800))
    draw = Draw(im)
    assert draw.flush().mode == 'RGB'
Example #19
0
    def draw(self):
        '''
        Render the image. Assumes that set_data has already been called.

        Returns a Python Image Library (PIL) Image object.
        '''

        img = Image.new('RGB', (self.width, self.height), self.bgcol)
        canvas = Draw(img)

        # create the projection. Here we use an equidistant cylindrical projection,
        # but others may work with tweaking of the parameters.
        proj = Proj(proj=self.proj,
                a=self.width/(2*pi), # set the radius of the earth such that our
                                     # projections work
                x_0=self.width/2,    # center horizontally on the image
                y_0=self.height/2)   # center verticallly on the image

        # two branches below will use the same sequence of commands to
        # draw a great-circle on the map, so the common elements are wrapped
        # up into a locally defined function. Given a matrix of points and
        # a pen, draw the path through the points.
        def draw_(pts, pen):
            lons, lats = pts.T
            x, y = proj(lons, lats)
            y = self.height - y
            path = reduce(operator.add, zip(x, y))
            canvas.line(path, pen)

        # loop over every coordinate pair
        for i, (lon1, lat1, lon2, lat2) in enumerate(self.data[self.order]):
            # calculate the fraction of the paths already drawn, and use
            # it to create a pen of the appropriate color
            frac = i / float(self.data_size)
            pen = Pen(self.cols(frac), self.line_width)

            # find the intermediate coordinates along a line between the two 
            # coordinates
            pts = self.geo.npts(lon1, lat1, lon2, lat2, self.gc_resolution)
            pts = np.array(pts)

            # if the longitudinal distance between the two points (travelling
            # through the prime meridian) is more than 180 degrees, it's faster
            # to *not* travel through the prime meridian, so we have to special-
            # case the drawing of the lines.
            if abs(lon1 - lon2) >= HALF_ROTATION:
                # find the index of the path where the line wraps around the image
                (cut_point,), = np.where(np.abs(np.diff(pts[:,0])) > HALF_ROTATION)
                
                # draw the two resultant lines separately
                pts1 = pts[:cut_point+1,:]
                pts2 = pts[cut_point+1:,:]

                # plot one point after the break on each sides so that the
                # paths go to the edge of the screen
                x1, y1 = pts[cut_point+2, :]
                x2, y2 = pts[cut_point+1, :]

                if x1 > 0:
                    pts1 = np.vstack((pts1, [-HALF_ROTATION, y1]))
                    pts2 = np.vstack(([HALF_ROTATION, y2], pts2))
                else:
                    pts1 = np.vstack((pts1, [HALF_ROTATION, y1]))
                    pts2 = np.vstack(([-HALF_ROTATION, y2], pts2))

                draw_(pts1, pen)
                draw_(pts2, pen)
            else:
                # the path does not wrap the image, so we can simply draw
                # it as-is
                draw_(pts, pen)
            
        canvas.flush()

        return img
Example #20
0
class Drawbject(object):
    """An abstract class that serves as the foundation for all KLDraw shapes. All Drawbjects
	are drawn on an internal surface using the aggdraw drawing library, which can then be drawn
	to the display buffer using blit() and displayed on the screen using flip(). For more
	infomration on drawing in KLibs, please refer to the guide in the documentation.

	Args:
		width (int): The width of the shape in pixels.
		height (int): The height of the shape in pixels.
		stroke (List[width, Tuple[color], alignment]): The stroke of the shape, indicating
			the width, color, and alignment (inner, center, or outer) of the stroke.
		fill (Tuple[color]): The fill color for the shape expressed as an iterable of integer 
			values from 0 to 255 representing an RGB or RGBA color (e.g. (255,0,0,128)
			for bright red with 50% transparency.)
		rotation (int|float, optional): The degrees by which to rotate the Drawbject during
			rendering. Defaults to 0.

	Attributes:
		stroke_color (None or Tuple[color]): The stroke color for the shape, expressed as an
			iterable of integer values from 0 to 255 representing an RGB or RGBA color.
			Defaults to 'None' if the shape has no stroke.
		stroke_width (int): The stroke width for the in pixels. Defaults to '0' if the
			shape has no stroke.
		stroke_alignment (int): The stroke alignment for the shape (inner, center, or
			outer). Defaults to '1' (STROKE_INNER) if the shape has no stroke.
		fill_color (None or Tuple[color]): The fill color for the shape, expressed as an
			iterable of integer values from 0 to 255 representing an RGB or RGBA color.
			Defaults to 'None' if the shape has no fill.
		opacity (int): The opacity of the shape, expressed as an integer from 0 (fully
			transparent) to 255 (fully opaque).
		object_width (int): The width of the shape in pixels.
		object_height (int): The height of the shape in pixels.
		surface_width (int): The width of the draw surface in pixels. At minimum two 
			pixels wider than the object_width (if no stroke or stroke is inner aligned),
			at maximum (2 + 2*stroke_width) pixels wider than object width (if stroke is
			outer aligned).
		surface_height (int): The height of the draw surface in pixels. At minimum two 
			pixels wider than the object_height (if no stroke or stroke is inner aligned),
			at maximum (2 + 2*stroke_height) pixels wider than object height (if stroke is
			outer aligned).
		surface (:obj:`aggdraw.Draw`): The aggdraw context on which the shape is drawn.
			When a shape is drawn to the surface, it is immediately applied to the canvas.
		canvas (:obj:`PIL.Image.Image`): The Image object that contains the shape of the
			Drawbject before opacity has been applied. Initialized upon creation with a
			size of (surface_width x surface_height).
		rendered (None or :obj:`numpy.array`): The rendered surface containing the shape,
			which is created using the render() method. If the Drawbject has not yet been
			rendered, this attribute will be 'None'.
		rotation (int): The rotation of the shape in degrees. Will be equal to 0 if no
			rotation is set.

	"""

    transparent_brush = Brush((255, 0, 0), 0)

    def __init__(self, width, height, stroke, fill, rotation=0):
        super(Drawbject, self).__init__()

        self.surface = None
        self.canvas = None
        self.rendered = None

        self.__stroke = None
        self.stroke_width = 0
        self.stroke_color = None
        self.stroke_alignment = STROKE_OUTER
        self.stroke = stroke

        self.__fill = None
        self.fill_color = None
        self.fill = fill

        self.__dimensions = None
        self.object_width = width
        self.object_height = height
        self.rotation = rotation

        self._init_surface()

    def __str__(self):
        properties = [
            self.__name__, self.surface_width, self.surface_height,
            hex(id(self))
        ]
        return "klibs.Drawbject.{0} ({1} x {2}) at {3}".format(*properties)

    def _init_surface(self):
        self._update_dimensions()
        self.rendered = None  # Clear any existing rendered texture
        if self.fill_color:
            if self.stroke_color and self.fill_color[3] == 255:
                col = self.stroke_color
            else:
                col = self.fill_color
        elif self.stroke_color:
            col = self.stroke_color
        else:
            col = (0, 0, 0)
        self.canvas = Image.new("RGBA", self.dimensions,
                                (col[0], col[1], col[2], 0))
        self.surface = Draw(self.canvas)
        self.surface.setantialias(True)

    def render(self):
        """Pre-renders the shape so it can be drawn to the screen using
		:func:`~klibs.KLGraphics.blit`. Although it is not necessary to pre-render
		shapes before drawing them to the screen, it will make the initial blit faster
		and is recommended wherever possible. 
		
		Once a Drawbject has been rendered, it will not need to be rendered again unless
		any of its properties (e.g. stroke, fill, rotation) are changed.
		
		Returns:
			:obj:`~numpy.ndarray`: A numpy array of the rendered shape.

		"""
        self._init_surface()
        self.draw()
        self.rendered = asarray(self.canvas)
        return self.rendered

    def _update_dimensions(self):
        pts = self._draw_points(outline=True)
        if pts != None:
            self.__dimensions = canvas_size_from_points(pts, flat=True)
        else:
            if self.stroke_alignment == STROKE_OUTER:
                stroke_w = self.stroke_width * 2
            elif self.stroke_alignment == STROKE_CENTER:
                stroke_w = self.stroke_width
            else:
                stroke_w = 0
            w, h = [self.object_width, self.object_height]
            self.__dimensions = [
                int(ceil(w + stroke_w)) + 2,
                int(ceil(h + stroke_w)) + 2
            ]

    @property
    def dimensions(self):
        """List[int, int]: The height and width of the internal surface on which the shape
		is drawn.
		"""
        return self.__dimensions

    @property
    def surface_width(self):
        return self.__dimensions[0]

    @property
    def surface_height(self):
        return self.__dimensions[1]

    @property
    def stroke(self):
        """None or :obj:`aggdraw.Pen`: An aggdraw Pen object set to the specified stroke width
		and color, or None if the Drawbject has no stroke.

		Raises:
			ValueError: If an invalid stroke alignment value is passed to the stroke setter.
				Valid values are 1 (STROKE_INNER), 2 (STROKE_CENTER), or 3 (STROKE_OUTER).
				For the sake of clarity, it is recommended that you define stroke alignment
				using the variable names provided in KLConstants (in brackets above).

		"""
        return self.__stroke

    @stroke.setter
    def stroke(self, style):
        if not style:
            self.stroke_width = 0
            self.stroke_color = None
            self.stroke_alignment = STROKE_OUTER
            return self
        try:
            width, color, alignment = style
        except ValueError:
            width, color = style
            alignment = STROKE_OUTER

        if alignment in [STROKE_INNER, STROKE_CENTER, STROKE_OUTER]:
            self.stroke_alignment = alignment
        else:
            raise ValueError(
                "Invalid stroke alignment, see KLConstants for accepted values"
            )

        color = list(color)
        if len(color) == 3:
            color += [255]
        self.stroke_color = color
        self.stroke_width = width
        self.__stroke = Pen(tuple(color[:3]), width, color[3])
        if self.surface:  # don't call this when initializing the Drawbject for the first time
            self._init_surface()
        return self

    @property
    def stroke_offset(self):
        if self.stroke_alignment == STROKE_OUTER:
            return self.stroke_width * 0.5
        if self.stroke_alignment == STROKE_INNER:
            return self.stroke_width * -0.5
        else:
            return 0

    @property
    def fill(self):
        """None or :obj:`aggdraw.Brush`: An aggdraw Brush object set to the specified fill
		color, or None if the Drawbject has no fill.
		
		"""
        return self.__fill

    @fill.setter
    def fill(self, color):
        if not color:
            self.fill_color = None
            return self
        color = list(color)
        if len(color) == 3:
            color += [255]
        self.fill_color = color
        self.__fill = Brush(tuple(color[:3]), color[3])
        if self.surface:  # don't call this when initializing the Drawbject for the first time
            self._init_surface()
        return self

    @abc.abstractmethod
    def _draw_points(self, outline=False):
        return None

    @abc.abstractmethod
    def draw(self):
        pts = self._draw_points()
        dx = self.surface_width / 2.0
        dy = self.surface_height / 2.0
        pts = translate_points(pts, delta=(dx, dy), flat=True)

        self.surface.polygon(pts, self.stroke, self.fill)
        self.surface.flush()
        return self.canvas

    @abc.abstractproperty
    def __name__(self):
        pass
Example #21
0
from PIL import Image
from aggdraw import Draw, Brush
transBlack = (0, 0, 0, 0)         # shows your example with visible edges
solidBlack = (0, 0, 0, 255)       # shows shape on a black background
transWhite = (255, 255, 255, 0)
solidWhite = (255, 255, 255, 255)

im = Image.new("RGBA", (600, 600), solidBlack)

draw = Draw(im)

brush = Brush("yellow")

draw.polygon(
             (
              50, 50,
              550, 60,
              550, 550,
              60, 550,
             ),
             None, brush
            )

draw.flush()
im.save("squar.png")
im.show()