Commits

Anonymous committed bf7a40c

pygame.transform.scale2x and .flip implemented

Comments (0)

Files changed (2)

examples_pygame/moveit.py

         o = GameObject(player, x*40, x)
         objects.append(o)
 
+    frames = 0
+    then = pygame.time.get_ticks()
     while 1:
+        frames += 1
         for event in pygame.event.get():
             if event.type in (QUIT, KEYDOWN):
+                time = pygame.time.get_ticks() - then
+                print '%d frames in %.2f seconds' % (frames, time / 1000.0)
+                print '  %f milliseconds per frame (%d FPS)' % \
+                    (float(time) / frames, frames * 1000 / time)
                 return
 
         for o in objects:

pygame/transform.py

+#!/usr/bin/env python
+
+'''Pygame module to transform surfaces.
+
+A Surface transform is an operation that moves or resizes the pixels. All
+these functions take a Surface to operate on and return a new Surface with
+the results.
+
+Some of the transforms are considered destructive. These means every time
+they are performed they lose pixel data. Common examples of this are resizing
+and rotating. For this reason, it is better to retransform the original surface than to 
+keep transforming an image multiple times. (For example, suppose you are animating
+a bouncing spring which expands and contracts. If you applied the size changes
+incrementally to the previous images, you would lose detail. Instead, always
+begin with the original image and scale to the desired size.)
+'''
+
+__docformat__ = 'restructuredtext'
+__version__ = '$Id$'
+
+import re
+
+from SDL import *
+
+import pygame.base
+import pygame.surface
+
+def _newsurf_fromsurf(surf, width, height):
+    format = surf.format
+    newsurf = SDL_CreateRGBSurface(surf.flags, width, height,
+        format.BitsPerPixel, 
+        format.Rmask, format.Gmask, format.Bmask, format.Amask)
+    
+    if format.BytesPerPixel == 1 and format._palette:
+        SDL_SetColors(newsurf, format.palette.colors, 0)
+    if surf.flags & SDL_SRCCOLORKEY:
+        SDL_SetColorKey(newsurf, (surf.flags & SDL_RLEACCEL) | SDL_SRCCOLORKEY,
+                        format.colorkey)
+    if surf.flags & SDL_SRCALPHA:
+        SDL_SetAlpha(newsurf, surf.flags, format.alpha)
+
+    return newsurf
+
+def flip(surface, x=False, y=False):
+    '''Flip vertically and horizontally.
+
+    This can flip a Surface either vertically, horizontally, or both. Flipping
+    a Surface is nondestructive and returns a new Surface with the same
+    dimensions.
+    
+    :Parameters:
+        `surface` : `Surface`
+            Surface to flip.
+        `x` : bool
+            If True, the surface will be flipped horizontally.
+        `y` : bool
+            If True, the surface will be flipped vertically.
+
+    :rtype: `Surface`
+    '''
+    # Currently implemented by doing regular expressions over string data,
+    # which is pretty fast (much faster than working with lists of ints).
+
+    surf = surface._surf
+    newsurf = _newsurf_fromsurf(surf, surf.w, surf.h)
+
+    surface.lock()
+    data = surf.pixels.to_string()
+    surface.unlock()
+
+    rows = re.findall('.' * surf.pitch, data, re.DOTALL)
+    if newsurf.pitch < surf.pitch:
+        for i in range(len(rows)):
+            rows[i] = rows[i][:newsurf.pitch]
+    elif newsurf.pitch > surf.pitch:
+        pad = '\000' * newsurf.pitch - surf.pitch
+        for i in range(len(rows)):
+            rows[i] = rows[i] + pad
+
+    if y:
+        rows.reverse()
+    if x:
+        pattern = re.compile('.' * surf.format.BytesPerPixel, re.DOTALL)
+        for i in range(len(rows)):
+            pixels = pattern.findall(rows[i])
+            pixels.reverse()
+            rows[i] = ''.join(pixels)
+    data = ''.join(rows)
+
+    SDL_LockSurface(newsurf)
+    memmove(newsurf.pixels.ptr, data, len(data))
+    SDL_UnlockSurface(newsurf)
+
+    return pygame.surface.Surface(surf=newsurf)
+
+def scale(surface, size, dest=None):
+    '''Resize to new resolution.
+
+    Resizes the Surface to a new resolution. This is a fast scale operation
+    that does not sample the results. 
+
+    An optional destination surface can be used, rather than have it create 
+    a new one.  This is quicker if you want to repeatedly scale something.  
+    However the destination must be the same size as the (width, height) passed 
+    in.  Also the destination surface must be the same format.
+    
+    :Parameters:
+        `surface` : `Surface`
+            Surface to resize.
+        `size` : int, int
+            Width, height to resize to.
+        `dest` : `Surface`
+            Optional destination surface to write to.
+
+    :rtype: `Surface`
+    '''
+
+def rotate(surface, angle):
+    '''Rotate an image.
+
+    Unfiltered counterclockwise rotation. The angle argument represents degrees
+    and can be any floating point value. Negative angle amounts will rotate
+    clockwise.
+
+    Unless rotating by 90 degree increments, the image will be padded larger
+    to hold the new size. If the image has pixel alphas, the padded area will
+    be transparent. Otherwise pygame will pick a color that matches the Surface
+    colorkey or the topleft pixel value.
+    
+    :Parameters:
+        `surface` : `Surface`
+            Surface to rotate.
+        `angle` : float
+            Degrees to rotate anticlockwise.
+
+    :rtype: `Surface`
+    '''
+
+def rotozoom(surface, angle, scale):
+    '''Filtered scale and rotation.
+
+    This is a combined scale and rotation transform. The resulting Surface will
+    be a filtered 32-bit Surface. The scale argument is a floating point value
+    that will be multiplied by the current resolution. The angle argument is
+    a floating point value that represents the counterclockwise degrees to
+    rotate. A negative rotation angle will rotate clockwise.
+    
+    :Parameters:
+        `surface` : `Surface`
+            Surface to transform.
+        `angle` : float
+            Degrees to rotate anticlockwise.
+        `scale` : float
+            Scale to apply to surface size.
+    '''
+
+def scale2x(surface, dest=None):
+    '''Specialized image doubler.
+
+    This will return a new image that is double the size of the original. It
+    uses the AdvanceMAME Scale2X algorithm which does a 'jaggie-less' scale of
+    bitmap graphics.
+     
+    This really only has an effect on simple images with solid colors. On
+    photographic and antialiased images it will look like a regular unfiltered
+    scale.
+
+    An optional destination surface can be used, rather than have it create 
+    a new one.  This is quicker if you want to repeatedly scale something.  
+    However the destination must be twice the size of the source surface passed 
+    in.  Also the destination surface must be the same format.
+    
+    :Parameters:
+        `surface` : `Surface`
+            Surface to resize.
+        `dest` : `Surface`
+            Optional destination surface to write to.
+
+    :rtype: `Surface`
+    '''
+    # XXX differ from Pygame: allow subsurfaces.
+    surf = surface._surf
+    if not dest:
+        newsurf = _newsurf_fromsurf(surf, surf.w * 2, surf.h * 2)
+    else:
+        dest._prep()
+        newsurf = dest._surf
+
+    if newsurf.w != surf.w * 2 or newsurf.h != surf.h * 2:
+        raise ValueError, 'Destination surface not 2x bigger.'
+
+    if surf.format.BytesPerPixel != newsurf.format.BytesPerPixel:
+        raise ValueError, \
+              'Source and destination surfaces need the same format.'
+
+    width, height = surf.w, surf.h
+    source_pitch = surf.pitch / surf.format.BytesPerPixel
+    dest_pitch = newsurf.pitch / newsurf.format.BytesPerPixel
+
+    surface.lock()
+    SDL_LockSurface(newsurf)
+    
+    srcpix = surf.pixels.as_ctypes()
+    dstpix = newsurf.pixels.as_ctypes()
+    for y in range(surf.h):
+        b_y = max(0, y - 1) * source_pitch
+        mid_y = y * source_pitch
+        h_y = min(height - 1, y + 1) * source_pitch
+        dest_y = y * 2 * dest_pitch
+        for x in range(surf.w):
+            twox = 2 * x
+            b = srcpix[b_y + x]
+            d = srcpix[mid_y + max(0, x - 1)]
+            e = srcpix[mid_y + x]
+            f = srcpix[mid_y + min(width - 1, x + 1)]
+            h = srcpix[h_y + x]
+            if b != h and d != f:
+                if d == b: 
+                    dstpix[dest_y + twox] = d
+                else: 
+                    dstpix[dest_y + twox] = e
+                if b == f:
+                    dstpix[dest_y + twox + 1] = b
+                else:
+                    dstpix[dest_y + twox + 1] = e
+                if d == h:
+                    dstpix[dest_y + dest_pitch + twox] = d
+                else:
+                    dstpix[dest_y + dest_pitch + twox] = e
+                if h == f:
+                    dstpix[dest_y + dest_pitch + twox + 1] = h
+                else:
+                    dstpix[dest_y + dest_pitch + twox + 1] = e
+            else:
+                dstpix[dest_y + twox] = e
+                dstpix[dest_y + twox + 1] = e
+                dstpix[dest_y + dest_pitch + twox] = e
+                dstpix[dest_y + dest_pitch + twox + 1] = e
+
+    SDL_UnlockSurface(newsurf)
+    surface.unlock()
+
+    if dest:
+        dest._unprep()
+        return dest
+    else:
+        return pygame.surface.Surface(surf=newsurf)
+
+def chop(surface, rect):
+    '''Extract a rectangular area of an image.
+
+    Extracts a portion of an image. All vertical and
+    horizontal pixels surrounding the given rectangle area are removed. The
+    resulting image is shrunken by the size of pixels removed.
+    (The original image is not altered by this operation.)
+
+    :Parameters:
+        `surface` : `Surface`
+            Surface to crop.
+        `rect` : `Rect`
+            Area to extract.
+
+    :rtype: `Surface`
+    '''