colorlab
clone your own copy | download snapshot

Snapshots | iceberg

Inside this repository

_tmp.py
text/x-python

Download raw (32.1 KB)

import re
import json
import chiplotle
from chiplotle.tools.plottertools \
        import instantiate_virtual_plotter
from chiplotle.geometry.core.coordinate \
        import Coordinate
from chiplotle.geometry.shapes.path import Path
from chiplotle.geometry.core.group import Group
from chiplotle.tools.mathtools.bezier_interpolation \
        import bezier_interpolation
import chiplotle.geometry.transforms as transforms

from random import randint
from copy import deepcopy
import os

# Object for the font. Character objects are stored inside
class Font (object):
        
        def __init__ (self, path = False, resolution = False, scale = False):
                self.path = ''
                self.cache = True
                self.source = {}
                self.chars = {}
                self.resolution = 10 if resolution == False else resolution
                self.length = 0
                self.name = ''
                self.cacheDir = 'shape_font_cache' #'~/tmp/shape_font_cache'
                self.cacheFilePath = '{0}/{1}-{2}.json' # Basepath, name, resolution
                
                if path <> False:
                        self.load (path)
                        
                        if resolution <> False:
                                self.render (resolution = resolution)
                                
                        if scale <> False:
                                self.scale (scale)
                        
                
        def load (self, path = False):
                if path <> False:
                        self.path = path
                        
                try:
                        with open(self.path, 'r') as font_file:
                                self.source = json.load (font_file)
                                font_file.close()
                                self.name = self.source["name"]
                                print self.name, self.source["name"]
                                for char in self.source["chars"]:
                                        char = Character (char)
                                        self.addChar (char)
                except:
                        return False
                
                return True
        
        def write (self, path = False):
                self.scale (1)
                writer = FontWriter (self)
                return writer.write (path)      
                        
        def get (self, key):
                if key in self.chars:
                        return deepcopy (self.chars[key])
                else:
                        return False
        
        def addChar (self, char):
                self.chars[char.key] = char
        
        def getChar (self, char):
                return self.get (ord (char))
        
        def render (self, resolution = False):
                if resolution <> False:
                        self.resolution = resolution
                
                if self.cache == True:
                        if self.loadCache () == True:
                                return True
                                
                for key in self.chars:
                        self.chars[key].render(self.resolution)
                
                if self.cache == True:
                        self.writeCache ()

        def scale (self, scale = 1):
                self.height = self.chars[self.chars.keys()[0]]._height * scale * 1.60

                for key in self.chars:
                        self.chars[key].scale = scale
        
        @property
        def cacheFile (self):
                return self.cacheFilePath.format (self.cacheDir, self.name, self.resolution)
        
        def loadCache (self):
                if self.cacheExists():
                        cache = json.load (open (self.cacheFile, 'r'))
                        self.putCacheObject (cache)
                        
                        return True
                else:
                        return False
        
        def writeCache (self):
                if self.cacheDirExists () == False:
                        self.createCacheDir ()
                        
                handle = open (self.cacheFile, 'w')
                return json.dump (self.getCacheObject (), handle)
                
        def cacheExists (self):
                if os.path.exists (self.cacheFile):
                        return True
                else:
                        if self.cacheDirExists () == False:
                                self.createCacheDir ()
                        
                        return False
                
        def cacheDirExists (self):
                return os.path.exists (self.cacheDir)
                
        def createCacheDir (self):
                os.makedirs (self.cacheDir)
                
        def getCacheObject (self):
                return {char: self.chars[char].shape for char in self.chars}
                
        def putCacheObject (self, cache):
                for char in cache:
                        self.chars[int (char)].shape = cache[char]
                
# Character object. Character information is stored inside this object
class Character (object):
        def __init__ (self, source = False):
                self.key = source["key"]
                self._width = source["width"]
                self._height = source["height"]
                self._lines = source["lines"]
                
                if 'margins' in source:
                        self._margins = source["margins"]
                else:
                        self._margins = [0,0,0,0]
                
                self.lines = deepcopy (self._lines)
                self.shape = []
                self.curve_resolution = 10
                self.length = 0
                self._scale = 1

        @property
        def width (self):
                return self._width * self.scale
        
        @property
        def height (self):
                return self._height * self.scale
        
        @property
        def margins (self):
                return [val * self.scale for val in self._margins]
        
        def render (self, resolution = False):
                if resolution <> False:
                        self.curve_resolution = resolution
                
                if len (self.lines) > 0 and len (self.lines[0]) > 0:
                        self.shape = []
                        position = (self._height, 0)
                        
                        for line in self.lines:
                                points = []
                                
                                for segment in line:
                                        if len(segment) > 2:
                                                # Curve
                                                if len (points) > 0:
                                                        curve_points = [position]
                                                else:
                                                        curve_points = []
                                                
                                                for i in range (0,len(segment),2):
                                                        curve_points.append ((segment[i], segment[i+1]))
                                                        
                                                        
                                                for point in bezier_interpolation (curve_points, self.curve_resolution, 1):
                                                        points.append ((point[0] - position[0], point[1] - position[1]))
                                                        #points.append ((point[0], point[1]))
                                                        position = (point[0], point[1])
                                        else:
                                                points.append ((segment[0] - position[0], segment[1] - position[1]))
                                                #points.append ((segment[0], segment[1]))
                                                position = (segment[0], segment[1])

                                
                                self.shape.append(points)
                        
        def hpgl (self, offset = (0,0)):
                buff = ['PA{0},{1}'.format (self.y + offset[0], self.x + offset[1])]
                
                for line in self.shape:
                        buff.append ('PR{0:.1f},{1:.1f}'.format (float (line[0][0]), float (line[0][1]))) # switch to relative.
                        
                        points = ['{0:.1f},{1:.1f}'.format (float (point[0]), float (point[1])) for point in line[1:]]
                        
                        buff.append ('PD{0}'.format (','.join (points)))
                        buff.append ('PU')
                        
                return ';'.join (buff)
        
        @property
        def scale (self):
                return self._scale
        
        @scale.setter
        def scale (self, scale):
                self._scale = scale
                self.shape = [[(point[0] * scale, point[1] * scale) for point in line] for line in self.shape]
                # Loop through all lines, and points to scale them
        
        def validate (self):
                return True if self.patt.match (self.source) <> None else False

# Whitespace buffer. Behaves like a character object
class Whitespace (object):
        def __init__ (self, width = False):
                self.width = width if width <> False else 0
                
                return 'PR0,{0:.1f}'.format (self.width)
                
# Textbox. Wrapper for lines.
class Textbox (object):
        alignLeft = 'left'
        alignCenter = 'center'
        alignRight = 'right'
        
        def __init__ (self, font = False, width = False, position = False, align = False, height = False, lineHeight = 1):
                if isinstance(position, Coordinate):
                        self.position = position
                else:
                        self.position = Coordinate (0, 0)
                
                self.width = width if width <> False else 0
                self.maxHeight = height if height <> False else False
                self.height = 0
                self.int_y = 0
                self.lineHeight = lineHeight
                
                self._lines = []
                
                if isinstance (font, Font):
                        self.font = font
                else:
                        self.font = None
                
                if align <> False:
                        self.align = align
                else:
                        self.align = self.alignLeft
                
                self.newLine()
        
        @property
        def lines (self):
                buff = []
                for line in self._lines:
                        if self.align == self.alignCenter or self.align == self.alignRight:
                                line = deepcopy (line)
                                delta_x = (self.width - line.int_x) * .5 if self.align == self.alignCenter else (self.width - line.int_x)
                                line.offset ((0, delta_x))
                        buff.append (line)
                return buff
        
        def clear (self):
                self._lines = []
                self.newLine()
        
        def newLine (self):
                if self.maxHeight == False or (self.int_y + self.font.height < self.maxHeight):
                        self._lines.append (Textline (width = self.width, position = Coordinate (self.position[0] + self.int_y, self.position[1])))
                        self.int_y += self.font.height * self.lineHeight
                        self.height = self.int_y
                        
                        return True
                else:
                        return False
                
        def setFont (self, font):
                if isinstance (font, Font):
                        self.font = font
        
        def setSize (self, size):
                if type (size) == int:
                        self.size = size
        
        def insertText (self, text):
                if len (self._lines) == 0:
                        self.newLine ()
                
                for char in text:
                        if char  == '\n':
                                if self.newLine() == False:
                                        # Could not add the new line. Return False
                                        return False
                        else:
                                charObj = self.font.getChar (char)
                                if charObj <> False:
                                        if self._lines[-1].add (charObj) == False:
                                                if (self.newLine()):
                                                        # Still space to add a new line
                                                        if self._lines[-1].add (charObj) == False:
                                                                # Could not fit the char on a second try
                                                                return False
                                                else:
                                                        # No space left for a new line
                                                        return False
                                
                return True

        def write (self, plotter):
                for line in self.lines:
                        plotter.write (line.characters)
                                                
        def hpgl (self, offset = (0,0)):
                hpgl = [line.hpgl(offset) for line in self.lines]
                
                return ';'.join (hpgl)

# Textline combines wrapper for characters
class MultiTextbox (object):
        def __init__ (self, font = False, width = False, position = False, align = False, height = False, cols = 1, spacing = 400):
                self.font = font
                self.width = width
                
                if isinstance(position, Coordinate):
                        self.position = position
                else:
                        self.position = Coordinate (0, 0)
                
                self.width = width if width <> False else 0
                self.height = height if height <> False else False
                self.maxCols = int (cols)
                self.spacing = int (spacing)
                self.cols = []
                
                if isinstance (font, Font):
                        self.font = font
                else:
                        self.font = None
                
                if align <> False:
                        self.align = align
                else:
                        self.align = Textbox.alignLeft
                
                self.newCol()
                
        @property
        def colWidth (self):
                return (self.width - ((self.maxCols - 1) * self.spacing)) / self.maxCols
                
        def newCol (self):
                if len(self.cols) < self.maxCols:
                        pos = Coordinate (self.position[0], self.position[1] + ((len(self.cols) * (self.colWidth + self.spacing))))
                        self.cols.append (Textbox (font = self.font, width = self.colWidth, position = pos, align = self.align, height = self.height))
                        
                        return True
                else:
                        return False
                        
        def insertText (self, text):
                for char in text:
                        if self.cols[-1].insertText (char) == False:
                                if self.newCol ():
                                        if self.cols[-1].insertText (char) == False:
                                                return False
                                else:
                                        return False

class Textline (object):
        
        def __init__ (self, width = False, position = False):
                if isinstance(position, Coordinate):
                        self.position = position
                else:
                        self.position = Coordinate (0, 0)
                        
                self.length = 0
                
                self.int_x = 0
                
                self.height = 0
                self.width = width if width <> False else 0
                
                self.characters = self.chars = []
                
        def add (self, char):
                ## Tries to add the given character, if the character
                ## doens't fit it returns false
                if isinstance (char, Character):
                        if self.room_for (char.width):
                                self.int_x += char.margins[3] # Add left margins
                                char.x = self.position[1] + self.int_x
                                char.y = self.position[0]
                                
                                self.chars.append (char)
                                
                                self.int_x += char.width + char.margins[1]
                                self.length += 1
                                return True;
                        else:
                                return False
                                
        def calc_space (self, char):
                return char.unit * .75
        
        def calc_space_width (self, key = -2):
                return self.chars[key].width
        
        def room_for (self, width):
                if self.int_x + width <= self.width:
                        return True
                else:
                        return False
                        
        def insert_whitespace (self, width):
                self.chars.append (Whitespace (width))
        
        def hpgl (self, offset = (0,0)):
                return ';'.join ([char.hpgl(offset) for char in self.chars])
        
        def offset (self, offset):
                for char in self.chars:
                        char.x += offset[1]
                        char.y += offset[0]

# Exports the font object to an JSON file
class FontWriter (object):
        pointReplacementPatt = re.compile ("(\s+)(\-?\d+),\n\s+(\-?\d+)", flags=re.M)
        
        def __init__ (self, font = False):
                if font <> False:
                        self.font = font
                
        def write (self, path):
                if self.font <> False:
                        writeList = []
                        
                        for char in self.font.chars:
                                #writeObject = {}
                                #writeObject['key'] = self.font.chars[char].key
                                #writeObject['width'] = self.font.chars[char].width
                                #writeObject['height'] = self.font.chars[char].height
                                #writeObject['lines'] = self.font.chars[char].lines
                                #
                                writeObject = dict (
                                        key = self.font.chars[char].key,
                                        width = self.font.chars[char].width,
                                        height = self.font.chars[char].height,
                                        lines = self.font.chars[char].lines,
                                        margins = self.font.chars[char].margins
                                )
                                writeList.append (writeObject)
                        
                        self.writer = Writer ({'name': self.font.name, 'chars': writeList})
                        
                        buff = self.pointReplacementPatt.sub ("\\1\\2,\\3", self.writer.build ())
                        
                        try:
                                with open (path, 'w') as self.f:
                                        self.f.write (buff)
                                        self.f.close ()
                        
                        except IOError:
                                return False
                        
                        return True 
                        
# Exports a Python iterable to JSON. Currently supports list, tuple and dict
class Writer (object):
        buff = ''
        newLine = '\n'
        tab = '\t'
        
        _stringBuff = ''
        
        __tabs = 0
        _terminator = ',{0}'.format (newLine)
        _key = '"{0}": '
        _list = ('[', ']')
        _dict = ('{', '}')
        
        def __init__ (self, value = False):
                if (value <> False):
                        self.buff = value
        
        def write (self, path):
                self.build ()
                
                try:
                        with open (path, 'w') as self.f:
                                self.f.write (self._stringBuff)
                                self.f.close ()
                except IOError:
                        return False
                
                return True
        
        def build (self):
                self._stringBuff = self._writeValue (self.buff)
                
                return self._stringBuff
        
        def _tabs (self):
                return self.__tabs * self.tab
        
        def _increaseTabs (self, amount = 1):
                self.__tabs += amount
        
        def _decreaseTabs (self, amount = 1):
                self.__tabs += -1 * amount
                
        def _writeKey (self, key):
                return self._key.format (key)
        
        def _writeValue (self, value):
                if (type (value) == int):
                        return self._writeInt (value)
                        
                if (type (value) == float):
                        return self._writeFloat (value)
                        
                if (type (value) == str or type (value) == unicode):
                        return self._writeStr (value)
                
                if (type (value) == list):
                        return self._writeList (value)
                        
                if (type (value) == dict):
                        return self._writeDict (value)
                        
                if (type (value) == tuple):
                        return self._writeTuple (value)
        
        def _writeInt (self, value):
                return '{0:d}'.format (value)
        
        def _writeFloat (self, value):
                return '{0:n}'.format (value)
        
        def _writeStr (self, value):
                return '"{0}"'.format (value)
        
        def _writeList (self, _list):
                buffList = []
                
                self._increaseTabs ()
                buff = self._list[0] + self.newLine
                
                for value in _list:
                        buffList.append (self._tabs() + self._writeValue (value))
                
                buff += self._terminator.join (buffList)
                buff += self.newLine
                self._decreaseTabs ()
                buff += self._tabs () + self._list[1]
                
                return buff
        
        def _writeTuple (self, _tuple):
                return self._writeList (_tuple)
        
        def _writeDict (self, _dict):
                buffList = []
                
                self._increaseTabs ()
                buff = self._dict[0] + self.newLine

                for key in _dict:
                        buffList.append (self._tabs() + self._writeKey(key) + self._writeValue (_dict[key]))
                
                buff += self._terminator.join (buffList)
                buff += self.newLine
                self._decreaseTabs ()
                buff += self._tabs () + self._dict[1]
                
                return buff
                                
                        
def write (text, box, plotter):
        box.insertText (text)
        plotter.write (box.hpgl())
        box.clear ()

def setFontSize (size, box, plotter):
        font = Font ('first.fnt')
        font.render (int (size))
        box.setFont (font)

def setPen (pen, plotter):
        plotter.write ('SP{0}'.format (int (pen)))
        
def setForce (force, plotter):
        plotter.write ('FS{0}'.format (int (force)))
        
def move (movement, plotter):
        plotter.write ('PU;PR{0},{1}'.format (movement[0], movement[1]))
        
def getInput (box, plotter):
        mode = raw_input ('Select workingmode (w: write, m: move, s: set fontsize, p: set pen, f: set force, q: quit)')
        
        if (mode == 'w'):
                text = raw_input ('Text to write?')
                write (text, box, plotter)
                getInput (box, plotter)
                
        elif (mode == 'm'):
                movement = [raw_input ('Vertical movement'), raw_input ('Horizontal movement')]
                move (movement, plotter)
                getInput (box, plotter)
        
        elif (mode == 's'):
                size = raw_input ('New fontsize?')
                setFontSize (size, box, plotter)
                getInput (box, plotter)
        
        elif (mode == 'p'):
                pen = raw_input ('New pen?')
                setPen (pen, plotter)
                getInput (box, plotter)
        
        elif (mode == 'f'):
                pen = raw_input ('New force?')
                setForce (pen, plotter)
                getInput (box, plotter)
        
        elif (mode == 'q'):
                return
        
if __name__ == '__main__':
        import chiplotle
        
        plotter = chiplotle.tools.plottertools.instantiate_virtual_plotter(type="HP7576A")
        
        #plotter = chiplotle.instantiate_plotters()[0]
        
        font = Font (path = '../handwriting.fnt', resolution = 10, scale = 10)
        
        #plotter.write ('AP0;SP4;FS7;cS5')
        
        textbox = Textbox (font=font, width = 3000, position = Coordinate (0, 0), align = Textbox.alignCenter, lineHeight = .75)
        #textBox.insertText ('In Doorn is een grote zoektocht aan de gang naar twee vermiste kinderen. Ze waren bij hun vader, die dood is aangetroffen in een recreatiegebied in de bossen. De man blijkt zelfmoord te hebben gepleegd.\n\nDe twee broertjes van 7 en 9 jaar oud uit Zeist zijn spoorloos. De politie doorzoekt het gebied met een helikopter, speurhonden en paarden. Ook het Korps Mariniers is ingezet.'.upper())
        textbox.insertText ('Obama\nis\na\nsex-god')
        
        plotter.write ('SP1')
        plotter.write (textbox.hpgl())
        
        #font.write ('../skeleton.fnt')
        
        #chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        
        #chars = 'S'
        
        #size = 1400
        #scale = 60
        
        
        #for char in chars:
                #if char in font.chars:
                        ##scale = size / font.chars[char].length
                        #shape = font.chars[char].group
                        #transforms.scale (shape, scale)
                        #transforms.offset (shape, offset)
                        ##transforms.offset (shape, (offset[0] + (size - (font.chars[char].height * scale)), offset[1]))
                        #width = font.chars[char].width * scale
                        
                        #plotter.write (shape)
                        
                        #offset = (offset[0], offset[1] + width)
        
        
        
        #for pen in range (1, 4):
        
                #plot = Group ([])
                
                #offset = [-3500,-2200]
                #plotter.write ('AP0;SP{0};VS20;FS7'.format (pen))
                
                #for char in chars:
                        ##if char in font.chars:
                        #for x in range (0,20):
                                #old_char = deepcopy (font.chars[char])
                                
                                ##for line in range (0, len (font.chars[char].lines)):
                                        ##for p in range (0, len (font.chars[char].lines[l])):
                                                ##for c in range (0, len (font.chars[char].lines[l][p])):
                                                        ##font.chars[char].lines[l][p][c] += randint (-10,10)
                                                
                                
                                #for line in font.chars[char].lines:
                                        #for point in line:
                                                #for c in range (0, len (point)):
                                                        #point[c] += randint (-15,15)
                                                
                                
                                #font.chars[char].render (20)
                                
                                #shape = font.chars[char].group
                                
                                #print shape
                                
                                #transforms.scale (shape, scale)
                                #transforms.offset (shape, offset)
                                
                                #plot.append (deepcopy (shape))
                                
                                ##offset[1] += 1000
                                #font.chars[char] = deepcopy (old_char)
                
                #plotter.write (plot)
                
                #for char in chars:
                        ##if char in font.chars:
                        #for y in range (0, 10):
                                #for x in range (0,10):
                                        #old_char = deepcopy (font.chars[char])
                                        
                                        ##for line in range (0, len (font.chars[char].lines)):
                                                ##for p in range (0, len (font.chars[char].lines[l])):
                                                        ##for c in range (0, len (font.chars[char].lines[l][p])):
                                                                ##font.chars[char].lines[l][p][c] += randint (-10,10)
                                                        
                                        
                                        #for line in font.chars[char].lines:
                                                #for point in line:
                                                        #for c in range (0, len (point)):
                                                                #point[c] += randint (-15,15)
                                                        
                                        
                                        #font.chars[char].render (15)
                                        
                                        #shape = font.chars[char].group
                                        
                                        #print shape
                                        
                                        #transforms.scale (shape, scale)
                                        #transforms.offset (shape, offset)
                                        
                                        #plotter.write (shape)
                                        
                                        #offset[1] += 1000
                                        #font.chars[char] = deepcopy (old_char)
                                
                                #offset[1] = -5000
                                #offset[0] += 1200
                        
        #plotter.write ('SP2;VS1;FS7')
        #for char in chars:
                #if char in font.chars:
                        #shape = font.chars[char].group
                        #plotter.write (shape)
        
        #plotter.write ('SP3;VS1;FS7')
        #for char in chars:
                #if char in font.chars:
                        #shape = font.chars[char].group
                        #plotter.write (shape)
        
        #plotter.write ('SP4;VS1;FS7')
        #for char in chars:
                #if char in font.chars:
                        #shape = font.chars[char].group
                        #plotter.write (shape)
        
        chiplotle.io.view (plotter)