Source

PyCessing / drawing_cairo.py

Full commit
"""
    drawing.py
    Copyright 2009 Brendan Howell (brendan@howell-ersatz.com)

    This file is part of PyCessing.

    PyCessing is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    PyCessing is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with PyCessing.  If not, see <http://www.gnu.org/licenses/>.
"""


import pygame
import cairo
import numpy
import math
import Image
import array

#TODO: could add filters since we are now using PIL

def bgra_surf_to_rgba_string(cairo_surface):
    # use PIL to do this
    img = Image.frombuffer(
        'RGBA', (cairo_surface.get_width(),
                 cairo_surface.get_height()),
        cairo_surface.get_data(), 'raw', 'BGRA', 0, 1)
 
    return img.tostring('raw', 'RGBA', 0, 1)

class Drawing:
    def __init__(self):
        self.sdl_surface = None
        self.surface = None
        self.ctx = None
        self.stroke = False
        self.stroke_color = (1, 0, 0, 1)
        self.stroke_width = 0
        self.fill = True
        self.fill_color = (0.5, 0, 0.5, 1)
        
    #TODO: see if this can be optimized and just grab the context every time
    def setSurface(self, sdl_surface):
        self.sdl_surface = sdl_surface
        width = sdl_surface.get_width()
        height = sdl_surface.get_height()
        
        stride = width * 4
        #pixels = pygame.surfarray.pixels2d(sdl_surface)
        #self.surface = cairo.ImageSurface.create_for_data(bytes, cairo.FORMAT_RGBA32, width, height)
        #self.data = numpy.empty(width * height * 4, dtype=numpy.int8)
        self.data = array.array("c",chr(0) * width * height * 4)
        self.surface = cairo.ImageSurface.create_for_data(self.data, cairo.FORMAT_ARGB32, width, height, stride)
        #self.surface = cairo.ImageSurface.create_for_data(sdl_surface.get_buffer(), cairo.FORMAT_RGB24, width, height, stride)
        self.ctx = cairo.Context(self.surface)
        
    def setBackground(self, red, green, blue):
        self.setSurface(self.sdl_surface)
        self.ctx.set_source_rgba(blue/255.0, green/255.0, red/255.0, 1)
        #self.ctx.set_source_rgba(0.4, 0.4, 0.4, 1)
        self.ctx.paint()
        #self.surface.finish()
        self._blitToScreen()
        #self.sdl_surface.fill((red, green, blue))
        
    def setStroke(self, red, green, blue, alpha=255, width=1):
        self.setStrokeWidth(width)
        self.setStrokeColor(red, green, blue, alpha)
        
    def setStrokeColor(self, red, green, blue, alpha=255):
        self.stroke_color = (red/255.0, green/255.0, blue/255.0, alpha/255.0)
    
    def setStrokeWidth(self, width):
        self.stroke_width = width
        
    def setFillColor(self, red, green, blue, alpha=255):
        self.fill_color = (red/255.0, green/255.0, blue/255.0, alpha/255.0)
        
    def setFillState(self, fill):
        self.fill = fill
        
    def rect(self, x, y, width, height): 
        self.setSurface(self.sdl_surface)
        self.ctx.rectangle(x, y, width, height)
        self._fillAndStroke()
    
    def circle(self, cx, cy, radius):
        self.setSurface(self.sdl_surface)
        self.ctx.arc(cx, cy, radius, 0, 2.0 * math.pi)
        self._fillAndStroke()
    
    def ellipse(self, cx, cy, width, height):
        self.setSurface(self.sdl_surface)
        self.ctx.save()
        self.ctx.translate(cx, cy)
        self.ctx.scale(width / 2.0, height / 2.0)
        self.ctx.arc(0.0, 0.0, 1.0, 0.0, 2.0 * math.pi)
        self.ctx.restore()
        self._fillAndStroke()
    
    def arc(self, cx, cy, radius, startAngle, endAngle):
        self.setSurface(self.sdl_surface)
        self.ctx.arc(cx, cy, radius, math.radians(startAngle), math.radians(endAngle))
        self._fillAndStroke()
        
    def line(self, x1, y1, x2, y2):
        self.setSurface(self.sdl_surface)
        self.ctx.move_to(x1, y1)
        self.ctx.line_to(x2, y2)
        self._fillAndStroke()
    
    def polygon(self, pointlist):
        self.setSurface(self.sdl_surface)
        x, y = pointlist[0]
        self.ctx.move_to(x, y)
        for point in pointlist[1:]:
            x, y = point
            self.ctx.line_to(x, y)
        self.ctx.close_path()
        self._fillAndStroke()
                
    def curve(self, x1, y1, cx1, cy1, cx2, cy2, x2, y2):
        self.setSurface(self.sdl_surface)
        self.ctx.move_to(x1, y1)
        self.ctx.curve_to(cx1, cy1, cx2, cy2, x2, y2)
        self._fillAndStroke()

    def screenGrab(self, fileName):
	pygame.image.save(self.sdl_surface, fileName)
        
    def _fillAndStroke(self):
        if(self.fill):
            self.ctx.set_source_rgba(self.fill_color[0], self.fill_color[1], self.fill_color[2], self.fill_color[3])
            self.ctx.fill_preserve()
        if(self.stroke_width > 0):
            self.ctx.set_line_width(self.stroke_width)
            self.ctx.set_source_rgba(self.stroke_color[0], self.stroke_color[1], self.stroke_color[2], self.stroke_color[3])
            self.ctx.stroke()
        else:
            self.ctx.new_path()
        #self.surface.finish()
        self._blitToScreen()
        
    def renderToPDF(self, fileName):
    	self.surface = cairo.PDFSurface(fileName, self.sdl_surface.get_width(), self.sdl_surface.get_height())
    	
    	#
    	
    	
        
    def _blitToScreen(self):
        #data_string = bgra_surf_to_rgba_string(self.surface)
        blue = self.data[0::4]
        red = self.data[2::4]
        self.data[0::4] = red 
        self.data[2::4] = blue
        pygame_surface = pygame.image.frombuffer(self.data.tostring(), 
                (self.sdl_surface.get_width(), 
                 self.sdl_surface.get_height()
                ), 
                'RGBA')
        self.sdl_surface.unlock()
        self.sdl_surface.blit(pygame_surface, (0,0))