Advertisement
Guest User

[pygame] PixelFont - a grainy bitmap font - version 1

a guest
Aug 22nd, 2012
249
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.95 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. #       pixelfont.py
  5. #      
  6. #       Copyright 2012 Maximilian Timmerkamp
  7. #      
  8. #       This program is free software; you can redistribute it and/or modify
  9. #       it under the terms of the GNU General Public License as published by
  10. #       the Free Software Foundation; either version 2 of the License, or
  11. #       (at your option) any later version.
  12. #      
  13. #       This program is distributed in the hope that it will be useful,
  14. #       but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. #       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. #       GNU General Public License for more details.
  17. #      
  18. #       You should have received a copy of the GNU General Public License
  19. #       along with this program; if not, write to the Free Software
  20. #       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  21. #       MA 02110-1301, USA.
  22.  
  23. """
  24. Contains a small and nice class to print scaled bitmap fonts
  25. on a surface (if you like grainy fonts).
  26. """
  27.  
  28. import pygame
  29. from pygame.locals import SRCALPHA, RLEACCEL
  30.  
  31. #from utils import load_image
  32.  
  33. def load_image(path, colorkey=None, return_rect=True):
  34.     """Loads an image from path and returns a
  35.    (transparent/alpha-converted) Surface containing it.
  36.    
  37.    path (str) - path of the image to load
  38.    colorkey (pygame.Color or RBG-tuple) - color to use as colorkey of
  39.        the surface (default: None)
  40.    return_rect (boolean) - additionally return the image's rect?
  41.        (default: True)
  42.    """
  43.     try:
  44.         image = pygame.image.load(path)
  45.     except pygame.error, message:
  46.         print('Cannot load image:', path)
  47.         raise SystemExit, message
  48.     image = image.convert_alpha()
  49.     if colorkey is not None:
  50.         if colorkey == -1:
  51.             colorkey = image.get_at((0, 0))
  52.         image.set_colorkey(colorkey, RLEACCEL)
  53.     if return_rect:
  54.         return (image, image.get_rect())
  55.     else:
  56.         return image
  57.  
  58.  
  59. CHARORDER_ASCII = (' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTU'+
  60.                    'VWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ')
  61.  
  62.  
  63. class PixelFont(object):
  64.     """A PixelFont is a bitmap font which is scaled up to see the
  65.    pixels of the bitmap.
  66.    
  67.    fontimage (str or pygame.Surface) - image to extract the chars
  68.        from
  69.    size (tuple) - size (width, height) of a single char
  70.    foreground_color (pygame.Color or RGB-tuple) - color of the
  71.        chars on the fontimage (necessary to change the foreground
  72.        color) (default: black)
  73.    background_color (pygame.Color or RGB-tuple) - color the
  74.        the background in output should have
  75.    scale (float) - the scale of the chars
  76.    charorder (str) - order of the chars on fontimage from left to
  77.        right, up to down
  78.    """
  79.    
  80.     def __init__(self, fontimage, size, foreground_color=(0, 0, 0),
  81.             background_color=None, scale=1, charorder=CHARORDER_ASCII):
  82.         if isinstance(fontimage, str):
  83.             # using my own load_image():
  84.             fontimage = load_image(fontimage, return_rect=False)
  85.             # using a more or less standard load_image():
  86.             #fontimage = load_image(fontimage)[0].convert_alpha()
  87.        
  88.         self.fontdict = {}
  89.        
  90.         width, height = size
  91.         scaled_width = width * scale
  92.         scaled_height = height * scale
  93.         self.scaled_size = (scaled_width, scaled_height)
  94.        
  95.         self._font_foreground = foreground_color
  96.        
  97.         self.foreground_color = foreground_color
  98.         self.background_color = background_color
  99.        
  100.         self._render_font(fontimage, size, charorder)
  101.         self._scale_font()
  102.    
  103.     def _render_font(self, fontimage, size, charorder):
  104.         """Cuts self.fontimage into small character images.
  105.        
  106.        fontimage (pygame.Surface) - the surface to extract the chars
  107.            from
  108.        size (tuple) - size of a char on fontimage
  109.        charorder (str) - order of the chars on fontimage from left to
  110.            right, top to bottom
  111.        """
  112.         width, height = size
  113.         fontimage_rect = fontimage.get_rect()
  114.        
  115.         rect = pygame.Rect((0, 0), size)
  116.         char_index = 0
  117.         for top_coord in xrange(0, fontimage_rect.height, height):
  118.             for left_coord in xrange(0, fontimage_rect.width, width):
  119.                 char_image = pygame.surface.Surface(size,
  120.                                                    flags=SRCALPHA)
  121.                 rect.top = top_coord
  122.                 rect.left = left_coord
  123.                
  124.                 char_image.blit(fontimage, (0, 0), rect)
  125.                
  126.                 self.fontdict[charorder[char_index]] = char_image
  127.                 char_index += 1
  128.    
  129.     def _scale_font(self):
  130.         """Scales all characters using PixelFont.scaled_size to resize
  131.        the characters.
  132.        """
  133.         scaled_width, scaled_height = self.scaled_size
  134.        
  135.         rect = pygame.Rect(0, 0, scaled_width, scaled_height)
  136.         for char in self.fontdict:
  137.             char_image = self.fontdict[char]
  138.             char_image = pygame.transform.scale(char_image, rect.size)
  139.             self.fontdict[char] = char_image
  140.    
  141.     def write(self, surface, text, position=(0, 0)):
  142.         """Writes a string at the given position on the given surface.
  143.        PixelFont.foreground_color and background_color are used to
  144.        color the text.
  145.        
  146.        surface (pygame.Surface) - the surface to write the text on
  147.        text (str) - string to be written on the surface
  148.        position (tuple) - tuple with the destination position (x, y)
  149.            (default: (0, 0))
  150.        """
  151.         self.write_color(surface, text, position=position,
  152.                          foreground=self.foreground_color,
  153.                          background=self.background_color)
  154.    
  155.     def write_args(self, surface, position, *args):
  156.         """Writes strings at the given position on the given surface.
  157.        Each argument from *args is seperated by a space.
  158.        
  159.        surface (pygame.Surface) - the surface to write the text on
  160.        position (tuple) - tuple with the destination position (x, y)
  161.        *args (object) - objects which are converted to strings using
  162.            str()
  163.        """
  164.         string = ' '.join(map(str, args))
  165.         self.write_color(surface, string, position=position,
  166.                          foreground=self.foreground_color,
  167.                          background=self.background_color)
  168.    
  169.     def write_color(self, surface, text, position=(0, 0), foreground=None,
  170.                          background=None):
  171.         """Writes a string at the given position on the given surface.
  172.        If foreground is None, the color of the chars will not be
  173.        changed. If background is None, the background will be
  174.        transparent.
  175.        
  176.        surface (pygame.Surface) - the surface to write the text on
  177.        text (str) - string to be written on the surface
  178.        position (tuple) - tuple with the destination position (x, y)
  179.            (default: (0, 0))
  180.        foreground (pygame.Color or RGB-tuple) - color of the characters
  181.            (default: standard color from fontimage)
  182.        background (pygame.Coloror RGB-tuple) - background color
  183.            (default: None)
  184.        
  185.        """
  186.         scaled_width, scaled_height = self.scaled_size
  187.        
  188.         rect = pygame.Rect(position, (scaled_width, scaled_height))
  189.         for row in text.splitlines():
  190.             rect.left = position[0]
  191.             for char in row:
  192.                 try:
  193.                     char_image = self.fontdict[char]
  194.                 except KeyError:
  195.                     # TODO: Macht das Sinn: Erst abfangen und dann neu werfen?
  196.                     raise KeyError('font does not contain char: ' + char)
  197.                
  198.                 if (foreground is not None and
  199.                         foreground != self._font_foreground):
  200.                     array = pygame.PixelArray(char_image)
  201.                     array.replace(self._font_foreground, foreground)
  202.                     char_image = array.make_surface()
  203.                
  204.                 if background is not None:
  205.                     surface.fill(background, rect)
  206.                
  207.                 surface.blit(char_image, rect)
  208.                
  209.                 rect.left += scaled_width
  210.             rect.top += scaled_height
  211.    
  212.     def get_textarea_size(self, *args):
  213.         """Returns a tuple with the size (width, height) of the area
  214.        which might be affected by a call of PixelFont.write().
  215.        """
  216.         text = ' '.join(map(str, args))
  217.         scaled_width, scaled_height = self.scaled_size
  218.        
  219.         rows = text.splitlines()
  220.         row_count = len(rows)
  221.         max_line_length = max(map(len, rows))
  222.        
  223.         width = max_line_length * scaled_width
  224.         height = row_count * scaled_height
  225.         return (width, height)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement