Source

PyCessing / pycessing / images.py

Full commit
"""
    images.py
    Copyright 2012 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 os
import io
import cairo
import math

SCREEN = None
PROJECT_DIR = None
CTX = None

class Image:
    """All-purpose class for cairo-based pixel images in pycessing"""
    def __init__(self, file_name):
        self.file_name = file_name
        self.loaded = False
        self.rotation = 0
        self.scalex = 1.0
        self.scaley = 1.0

    def _loadSurface_(self):
        """load image from file or file_obj"""

        try:
            imagelike = io.BytesIO(self.file_name.read())
        except AttributeError:
            imagelike = os.path.join(PROJECT_DIR, self.file_name)
        surface = pygame.image.load(imagelike).convert_alpha()

        self.width = surface.get_width()
        self.height = surface.get_height()
        ar = pygame.surfarray.array2d(surface)
        stride = surface.get_width() * 4
        self.surface = cairo.ImageSurface.create_for_data(ar,
                                                          cairo.FORMAT_ARGB32, surface.get_width(),
                                                          surface.get_height(), stride)
        self.loaded = True

    def draw(self, x, y, centerx=0.0, centery=0.0):
        #draws to the cairo context
        if(not(self.loaded)):
            self._loadSurface_()

        #TODO: scaling shortcut in draw?
        #TODO: flip?

        CTX.save()

        CTX.translate(x, y)
        CTX.scale(scalex, scaley)
        CTX.rotate(self.rotation)
        CTX.set_source_surface(self.surface, -centerx, -centery)
        CTX.paint()

        CTX.restore()

    def rotate(self, angle):
        self.rotation = -math.pi * angle / 180.0

    def scale(self, pixelsx, pixelsy):
        if (pixelsx < 1) or (pixelsy < 1):
            print "image must be at least 1px wide and 1px high!"
            return
        if(not(self.loaded)):
            self._loadSurface_()
        self.scalex = float(pixelsx) / self.width
        self.scaley = float(pixelsy) / self.height

    def flip(self):
        self.flipx = True
        self.flipy = True

    def flipx(self):
        self.flipx = True

    def flipy(self):
        self.flipy = True

    def get_width(self):
        if(not(self.loaded)):
            self._loadSurface_()
        return self.scalex * self.width

    def get_height(self):
        if(not(self.loaded)):
            self._loadSurface_()
        return self.scalex * self.height