PyCessing / pycessing / images.py

"""
    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

#TODO: write a generic transform stack to manage arbitrary sequences of
#      transformations:
#       ctx.save()
#

class Image2:
    """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, sx=None, sy=None):
        #draws to the cairo context
        if(not(self.loaded)):
            self._loadSurface_()
        if(sx and sy):
            if(width and height):
                area = (sx, sy, width, height)
            else:
                area = (sx, sy, self.surface.get_width(),
						self.surface.get_height())
        else:
            area = None

        scaley = self.scaley
        scalex = self.scalex

        #do flips if needed
        if self.flipy:
            scaley = scaley * -1
            y = (1 - scaley) * (self.width / 2)
        if self.flipx:
            scalex = scalex * -1
            x = (1 - scalex) * (self.height / 2)

        CTX.save()

        CTX.scale(self.scalex, self.scaley)
        CTX.translate(x, y)
        CTX.rotate(self.rotation)

        CTX.set_source_surface(self.surface, 0, 0)
        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_()
        if self.scalex:
            return self.scalex
        else:
            return self.width

    def get_height(self):
        if(not(self.loaded)):
            self._loadSurface_()
        dx, dy = self.matrix.transform_distance(0, self.height)
        if self.scaley:
            return self.scaley
        else:
            return self.height

class Image:
    """All-purpose class for pixel images in pycessing"""
    def __init__(self, file_name):
        self.file_name = file_name
        self.loaded = False
        self.transformed = False

    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)
        self.surface = pygame.image.load(imagelike).convert_alpha()

        self.original_surface = self.surface.copy()
        self.loaded = True

    def draw(self, x, y, sx=None, sy=None, width=None, height=None):
        if(not(self.loaded)):
            self._loadSurface_()
        if(sx and sy):
            if(width and height):
                area = (sx, sy, width, height)
            else:
                area = (sx, sy, self.surface.get_width(),
						self.surface.get_height())
        else:
            area = None
        SCREEN.unlock()
        SCREEN.blit(self.surface, (x, y), area)
        self.transformed = False

    def scale(self,width,height):
        if not(self.loaded):
            self._loadSurface_()
        if not(self.transformed):
            img = self.original_surface
            self.transformed = True
        else:
            img = self.surface
        self.surface = pygame.transform.smoothscale(img, (width, height))

    def flip(self,flipx=True,flipy=True):
        if not(self.loaded):
           self._loadSurface_()
        self.surface = pygame.transform.flip(self.surface, flipx, flipy)

    def rotate(self, angle):
        if not(self.loaded):
            self._loadSurface_()
        if not(self.transformed):
            img = self.original_surface
            self.transformed = True
        else:
            img = self.surface
        self.surface = pygame.transform.rotate(img, angle)

    def getWidth(self):
        if(not(self.loaded)):
            self._loadSurface_()
        return self.surface.get_width()

    def getHeight(self):
        if(not(self.loaded)):
            self._loadSurface_()
        return self.surface.get_height()

    def getPixel(self, x, y):
        if(not(self.loaded)):
            self._loadSurface_()
        return self.surface.get_at((x,y))

    def setPixel(self, x, y, r, g, b, a=None):
        if(not(self.loaded)):
            self._loadSurface_()
        if (a):
            self.surface.set_at((x, y), (r, g, b, a))
        else:
            self.surface.set_at((x, y), (r, g, b))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.