junglejourney

changeset 147:17d0a4c8fde5

Started working on additional materials.
author David Boddie <david@boddie.org.uk>
date Mon Sep 12 23:23:09 2011 +0200
parents 8dcefb5a013d
children b7c0ad00dfa3
files materials/make_packaging.py
diffstat 1 files changed, 270 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/materials/make_packaging.py	Mon Sep 12 23:23:09 2011 +0200
     1.3 @@ -0,0 +1,270 @@
     1.4 +#!/usr/bin/env python
     1.5 +
     1.6 +import os, sys
     1.7 +from PyQt4.QtCore import QSize
     1.8 +from PyQt4.QtGui import *
     1.9 +
    1.10 +
    1.11 +class Page:
    1.12 +
    1.13 +    def __init__(self, size, objects):
    1.14 +    
    1.15 +        self.size = size
    1.16 +        self.objects = objects
    1.17 +    
    1.18 +    def render(self, image = None):
    1.19 +    
    1.20 +        if not image:
    1.21 +            image = QImage(QSize(*self.size), QImage.Format_RGB32)
    1.22 +            image.fill(qRgb(255,255,255))
    1.23 +        
    1.24 +        x, y = 0, 0
    1.25 +        for obj in self.objects:
    1.26 +        
    1.27 +            x, y = obj.render(image, x, y)
    1.28 +        
    1.29 +        return image
    1.30 +
    1.31 +class TextBox:
    1.32 +
    1.33 +    def __init__(self, bbox, text_items, follow = False):
    1.34 +    
    1.35 +        self.bbox = bbox
    1.36 +        self.text_items = text_items
    1.37 +        self.follow = follow
    1.38 +    
    1.39 +    def render(self, image, previous_x, previous_y):
    1.40 +    
    1.41 +        x, y, width, height = self.bbox
    1.42 +        
    1.43 +        if self.follow:
    1.44 +            y += previous_y
    1.45 +        
    1.46 +        p = QPainter()
    1.47 +        p.begin(image)
    1.48 +        p.setRenderHint(QPainter.TextAntialiasing)
    1.49 +        
    1.50 +        for text_item in self.text_items:
    1.51 +        
    1.52 +            for pieces, line_height in text_item.readline(width):
    1.53 +            
    1.54 +                for font, word_x, text in pieces:
    1.55 +                
    1.56 +                    p.setFont(font)
    1.57 +                    p.drawText(x + word_x, y, text)
    1.58 +                
    1.59 +                y += line_height
    1.60 +        
    1.61 +        p.end()
    1.62 +        
    1.63 +        return x, y
    1.64 +
    1.65 +class Text:
    1.66 +
    1.67 +    def __init__(self, font, font_size, text, align = "left", style = None,
    1.68 +                       weight = None):
    1.69 +    
    1.70 +        self.font = {"family": font, "size": font_size, "weight": weight,
    1.71 +                     "style": style}
    1.72 +        self.text = text
    1.73 +        self.align = align
    1.74 +        
    1.75 +        self.parse_text()
    1.76 +    
    1.77 +    def parse_text(self):
    1.78 +    
    1.79 +        lines = self.text.split("\n")
    1.80 +        self.lines = []
    1.81 +        
    1.82 +        for line in lines:
    1.83 +        
    1.84 +            words = []
    1.85 +            for word in line.split():
    1.86 +            
    1.87 +                words.append(Word(self.font, word))
    1.88 +            
    1.89 +            self.lines.append(words)
    1.90 +    
    1.91 +    def readline(self, width):
    1.92 +    
    1.93 +        for line in self.lines:
    1.94 +        
    1.95 +            w = 0
    1.96 +            used = 0
    1.97 +            words = []
    1.98 +            
    1.99 +            while w < len(line):
   1.100 +            
   1.101 +                word = line[w]
   1.102 +                word_width = word.width()
   1.103 +                
   1.104 +                if used + word_width <= width:
   1.105 +                    # Add words while there is still space.
   1.106 +                    used += word_width + word.space()
   1.107 +                    words.append(word)
   1.108 +                    w += 1
   1.109 +                
   1.110 +                elif words:
   1.111 +                    # When out of space, yield the words on the line.
   1.112 +                    yield self.format(words, width), self.height(words)
   1.113 +                    
   1.114 +                    used = 0
   1.115 +                    words = []
   1.116 +                
   1.117 +                else:
   1.118 +                    # If no words will fit on the line, just add the first
   1.119 +                    # word to the list.
   1.120 +                    yield self.format([word], width), self.height(words)
   1.121 +                    
   1.122 +                    used = 0
   1.123 +                    w += 1
   1.124 +            
   1.125 +            if words:
   1.126 +                yield self.format(words, width), self.height(words)
   1.127 +            elif not line:
   1.128 +                yield [], self.line_height()/2
   1.129 +    
   1.130 +    def format(self, words, width):
   1.131 +    
   1.132 +        output = []
   1.133 +        
   1.134 +        if len(words) == 0:
   1.135 +            spacing = 0
   1.136 +        elif self.align == "justify":
   1.137 +            # Full justify the text.
   1.138 +            total_width = sum(map(lambda word: word.width(), words))
   1.139 +            spacing = (width - total_width)/float(len(words))
   1.140 +        else:
   1.141 +            spacing = None
   1.142 +        
   1.143 +        x = 0
   1.144 +        for word in words:
   1.145 +        
   1.146 +            output.append((word.font(), x, word.text))
   1.147 +            x += word.width()
   1.148 +            if spacing is not None:
   1.149 +                x += spacing
   1.150 +            else:
   1.151 +                x += word.space()
   1.152 +        
   1.153 +        return output
   1.154 +    
   1.155 +    def height(self, words):
   1.156 +    
   1.157 +        return max(map(lambda word: word.height(), words))
   1.158 +    
   1.159 +    def line_height(self):
   1.160 +    
   1.161 +        font = QFont(self.font["family"])
   1.162 +        font.setPixelSize(self.font["size"])
   1.163 +        if self.font["weight"] == "bold":
   1.164 +            font.setWeight(QFont.Bold)
   1.165 +        if self.font["style"] == "italic":
   1.166 +            font.setItalic(True)
   1.167 +        
   1.168 +        metrics = QFontMetrics(font)
   1.169 +        return metrics.height()
   1.170 +
   1.171 +class Word:
   1.172 +
   1.173 +    def __init__(self, font, text):
   1.174 +    
   1.175 +        self._font = font
   1.176 +        self.text = text
   1.177 +    
   1.178 +    def font(self):
   1.179 +    
   1.180 +        font = QFont(self._font["family"])
   1.181 +        font.setPixelSize(self._font["size"])
   1.182 +        if self._font["weight"] == "bold":
   1.183 +            font.setWeight(QFont.Bold)
   1.184 +        if self._font["style"] == "italic":
   1.185 +            font.setItalic(True)
   1.186 +        return font
   1.187 +    
   1.188 +    def width(self):
   1.189 +    
   1.190 +        metrics = QFontMetrics(self.font())
   1.191 +        return metrics.width(self.text)
   1.192 +    
   1.193 +    def height(self):
   1.194 +    
   1.195 +        metrics = QFontMetrics(self.font())
   1.196 +        return metrics.height()
   1.197 +    
   1.198 +    def space(self):
   1.199 +    
   1.200 +        metrics = QFontMetrics(self.font())
   1.201 +        return metrics.width(" ")
   1.202 +
   1.203 +
   1.204 +if __name__ == "__main__":
   1.205 +
   1.206 +    app = QApplication(sys.argv)
   1.207 +    
   1.208 +    if len(app.arguments()) != 2:
   1.209 +    
   1.210 +        sys.stderr.write("Usage: %s <output directory>\n" % app.arguments()[0])
   1.211 +        sys.exit(1)
   1.212 +    
   1.213 +    output_dir = sys.argv[1]
   1.214 +    
   1.215 +    if not os.path.exists(output_dir):
   1.216 +        os.mkdir(output_dir)
   1.217 +    
   1.218 +    pages = [
   1.219 +        Page((800, 1000),
   1.220 +             [TextBox((80, 40, 640, 1120), 
   1.221 +                      [Text("FreeSerif", 24, "Jungle Journey\n", weight = "bold"),
   1.222 +                       Text("FreeSerif", 24,
   1.223 +                            "The last flames of the campfire fade to glowing embers and I am alone. "
   1.224 +                            "My recent acquaintances, their packs and paraphernalia have gone, leaving "
   1.225 +                            "me stranded deep in the heart of this jungle realm. Clouds momentarily "
   1.226 +                            "sweep the cold face of the moon and I perceive the clicks, whistles and "
   1.227 +                            "cries of creatures in the hot air that cloaks this place. Desperately, I "
   1.228 +                            "try to stay my panic and remember those fragments of wilderness craft "
   1.229 +                            "learned and unlearned many years ago.\n")]),
   1.230 +              TextBox((120, 0, 560, 0),
   1.231 +                      [Text("FreeSerif", 24,
   1.232 +                            "Choose your weapon carefully,\n"
   1.233 +                            "Get ready for a fight.\n"
   1.234 +                            "The jungle can be dangerous\n"
   1.235 +                            "If you go there at night.\n"
   1.236 +                            "There's time to pick up treasure,\n"
   1.237 +                            "But no time to stop and stare.\n"
   1.238 +                            "If you don't find the hidden gate\n"
   1.239 +                            "You won't get out of there.\n", style = "italic")],
   1.240 +                      follow = True),
   1.241 +              TextBox((80, 0, 640, 0),
   1.242 +                      [Text("FreeSerif", 24,
   1.243 +                            "Hopeless, I scramble to my feet, reaching for any weapon still left to me. "
   1.244 +                            "Struggling through the dense undergrowth, I search for signs of a track or "
   1.245 +                            "trail. At first glance, paths that seemed to lead to safety turn out to be "
   1.246 +                            "impassable, overgrown by tangled and twisted vines. I remember the words of "
   1.247 +                            "an old teacher:\n")],
   1.248 +                      follow = True),
   1.249 +              TextBox((120, 0, 560, 0),
   1.250 +                      [Text("FreeSerif", 22,
   1.251 +                            u'\u201cDo not be tempted to use fire to make your way. '
   1.252 +                            'Many a traveller has strayed from the path, using fire to blaze a trail, '
   1.253 +                            'only to reach a dead end. Trying to return, they find that the jungle '
   1.254 +                            'has grown back. Those who are desperate enough will even seek out '
   1.255 +                            u'forgotten routes when the way home is in sight.\u201d\n')],
   1.256 +                      follow = True),
   1.257 +              TextBox((80, 0, 640, 0),
   1.258 +                      [Text("FreeSerif", 24,
   1.259 +                            "Sensing my presence, obscene creatures emerge from the darkness, hungry "
   1.260 +                            "for prey. Only through skill and luck am I able to dispatch them back "
   1.261 +                            "into the shadows. Even though I know I must journey deeper into this "
   1.262 +                            "uncharted land to find the way home, the thought of vengeance drives me on.")],
   1.263 +                      follow = True)
   1.264 +              ])]
   1.265 +    
   1.266 +    i = 0
   1.267 +    for page in pages:
   1.268 +    
   1.269 +        path = os.path.join(output_dir, "page-%i.png" % i)
   1.270 +        image = page.render()
   1.271 +        image.save(path)
   1.272 +    
   1.273 +    sys.exit()