summaryrefslogtreecommitdiff
path: root/third_party/freetype-py/examples
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/freetype-py/examples')
-rw-r--r--third_party/freetype-py/examples/Vera.ttfbin0 -> 65932 bytes
-rw-r--r--third_party/freetype-py/examples/VeraMono.ttfbin0 -> 49224 bytes
-rw-r--r--third_party/freetype-py/examples/agg-trick.py73
-rw-r--r--third_party/freetype-py/examples/ascii.py121
-rw-r--r--third_party/freetype-py/examples/example_1.py89
-rw-r--r--third_party/freetype-py/examples/font-info.py42
-rw-r--r--third_party/freetype-py/examples/ftdump.py295
-rw-r--r--third_party/freetype-py/examples/glyph-alpha.py31
-rw-r--r--third_party/freetype-py/examples/glyph-color.py94
-rw-r--r--third_party/freetype-py/examples/glyph-lcd.py32
-rw-r--r--third_party/freetype-py/examples/glyph-metrics.py233
-rw-r--r--third_party/freetype-py/examples/glyph-monochrome.py43
-rw-r--r--third_party/freetype-py/examples/glyph-outline.py37
-rw-r--r--third_party/freetype-py/examples/glyph-vector-2.py98
-rw-r--r--third_party/freetype-py/examples/glyph-vector.py91
-rw-r--r--third_party/freetype-py/examples/hello-world.py54
-rw-r--r--third_party/freetype-py/examples/opengl.py122
-rw-r--r--third_party/freetype-py/examples/sfnt-names.py66
-rw-r--r--third_party/freetype-py/examples/shader.py163
-rw-r--r--third_party/freetype-py/examples/subpixel-positioning.py236
-rw-r--r--third_party/freetype-py/examples/texture_font.py421
-rw-r--r--third_party/freetype-py/examples/wordle.py137
22 files changed, 2478 insertions, 0 deletions
diff --git a/third_party/freetype-py/examples/Vera.ttf b/third_party/freetype-py/examples/Vera.ttf
new file mode 100644
index 0000000..58cd6b5
--- /dev/null
+++ b/third_party/freetype-py/examples/Vera.ttf
Binary files differ
diff --git a/third_party/freetype-py/examples/VeraMono.ttf b/third_party/freetype-py/examples/VeraMono.ttf
new file mode 100644
index 0000000..139f0b4
--- /dev/null
+++ b/third_party/freetype-py/examples/VeraMono.ttf
Binary files differ
diff --git a/third_party/freetype-py/examples/agg-trick.py b/third_party/freetype-py/examples/agg-trick.py
new file mode 100644
index 0000000..c0bc134
--- /dev/null
+++ b/third_party/freetype-py/examples/agg-trick.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+from freetype import *
+import numpy as np
+import Image
+
+
+def render(filename = "Vera.ttf", hinting = (False,False), gamma = 1.5, lcd=False):
+ text = "A Quick Brown Fox Jumps Over The Lazy Dog 0123456789"
+
+ W,H,D = 680, 280, 1
+ Z = np.zeros( (H,W), dtype=np.ubyte )
+ face = Face(filename)
+ pen = Vector(5*64, (H-10)*64)
+
+ flags = FT_LOAD_RENDER
+ if hinting[1]: flags |= FT_LOAD_FORCE_AUTOHINT
+ else: flags |= FT_LOAD_NO_HINTING
+ if hinting[0]: hres, hscale = 72, 1.0
+ else: hres, hscale = 72*10, 0.1
+ if lcd:
+ flags |= FT_LOAD_TARGET_LCD
+ Z = np.zeros( (H,W,3), dtype=np.ubyte )
+ set_lcd_filter( FT_LCD_FILTER_DEFAULT )
+
+
+ for size in range(9,23):
+ face.set_char_size( size * 64, 0, hres, 72 )
+ matrix = Matrix( int((hscale) * 0x10000L), int((0.0) * 0x10000L),
+ int((0.0) * 0x10000L), int((1.0) * 0x10000L) )
+ previous = 0
+ pen.x = 5*64
+ for current in text:
+ face.set_transform( matrix, pen )
+ face.load_char( current, flags)
+ kerning = face.get_kerning( previous, current, FT_KERNING_UNSCALED )
+ pen.x += kerning.x
+ glyph = face.glyph
+ bitmap = glyph.bitmap
+ x, y = glyph.bitmap_left, glyph.bitmap_top
+ w, h, p = bitmap.width, bitmap.rows, bitmap.pitch
+ buff = np.array(bitmap.buffer, dtype=np.ubyte).reshape((h,p))
+ if lcd:
+ Z[H-y:H-y+h,x:x+w/3].flat |= buff[:,:w].flatten()
+ else:
+ Z[H-y:H-y+h,x:x+w].flat |= buff[:,:w].flatten()
+ pen.x += glyph.advance.x
+ previous = current
+ pen.y -= (size+4)*64
+
+ # Gamma correction
+ Z = (Z/255.0)**(gamma)
+ Z = ((1-Z)*255).astype(np.ubyte)
+ if lcd:
+ I = Image.fromarray(Z, mode='RGB')
+ else:
+ I = Image.fromarray(Z, mode='L')
+
+ name = filename.split('.')[0]
+ filename = '%s-gamma(%.1f)-hinting(%d,%d)-lcd(%d).png' % (name,gamma,hinting[0],hinting[1],lcd)
+ I.save(filename)
+
+
+
+if __name__ == '__main__':
+ render('Vera.ttf', (0,1), 1.25, True)
+
diff --git a/third_party/freetype-py/examples/ascii.py b/third_party/freetype-py/examples/ascii.py
new file mode 100644
index 0000000..ce718d3
--- /dev/null
+++ b/third_party/freetype-py/examples/ascii.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+import numpy
+import os, sys
+from freetype import *
+
+
+class ColorMap:
+ ''' A colormap is used to map scalar values to colors. It is build by
+ adding couples of (value,color) where value must be between 0 and 1.
+ The 'scale' method allows to specify the range of the colormap and
+ the 'color' method then returns a color for any value. '''
+
+ def __init__ (self, colors):
+ self.colors = colors
+ self.min = 0
+ self.max = 1
+
+ def scale (self, min, max):
+ self.min, self.max = min,max
+
+ def color (self, value):
+ ''' Return the color corresponding to value. '''
+ if not len(self.colors):
+ return (0,0,0)
+ elif len(self.colors) == 1:
+ return self.colors[0][1]
+ elif value < self.min:
+ return self.colors[0][1]
+ elif value > self.max:
+ return self.colors[-1][1]
+ value = (value-self.min)/(self.max-self.min)
+ sup_color = self.colors[0]
+ inf_color = self.colors[-1]
+ for i in range (len(self.colors)-1):
+ if value < self.colors[i+1][0]:
+ inf_color = self.colors[i]
+ sup_color = self.colors[i+1]
+ break
+ r = (value-inf_color[0]) / (sup_color[0] - inf_color[0])
+ if r < 0: r = -r
+ color = [sup_color[1][0]*r + inf_color[1][0]*(1-r),
+ sup_color[1][1]*r + inf_color[1][1]*(1-r),
+ sup_color[1][2]*r + inf_color[1][2]*(1-r)]
+ return color
+
+# Some colormaps
+CM_IceAndFire = ColorMap([(0.00, (0.0, 0.0, 1.0)),
+ (0.25, (0.0, 0.5, 1.0)),
+ (0.50, (1.0, 1.0, 1.0)),
+ (0.75, (1.0, 1.0, 0.0)),
+ (1.00, (1.0, 0.0, 0.0))])
+CM_Ice = ColorMap([(0.00, (0.0, 0.0, 1.0)),
+ (0.50, (0.5, 0.5, 1.0)),
+ (1.00, (1.0, 1.0, 1.0))])
+CM_Fire = ColorMap([(0.00, (1.0, 1.0, 1.0)),
+ (0.50, (1.0, 1.0, 0.0)),
+ (1.00, (1.0, 0.0, 0.0))])
+CM_Hot = ColorMap([(0.00, (0.0, 0.0, 0.0)),
+ (0.33, (1.0, 0.0, 0.0)),
+ (0.66, (1.0, 1.0, 0.0)),
+ (1.00, (1.0, 1.0, 1.0))])
+CM_Grey = ColorMap([(0.00, (0.0, 0.0, 0.0)),
+ (1.00, (1.0, 1.0, 1.0))])
+
+
+
+def imshow (Z, vmin=None, vmax=None, cmap=CM_Hot, show_cmap=False):
+ ''' Show a 2D numpy array using terminal colors '''
+
+ if len(Z.shape) != 2:
+ print "Cannot display non 2D array"
+ return
+
+ vmin = vmin or Z.min()
+ vmax = vmax or Z.max()
+ cmap.scale (vmin, vmax)
+
+ # Build initialization string that setup terminal colors
+ init = ''
+ for i in range(240):
+ v = cmap.min + (i/240.0)* (cmap.max - cmap.min)
+ r,g,b = cmap.color (v)
+ init += "\x1b]4;%d;rgb:%02x/%02x/%02x\x1b\\" % (16+i, int(r*255),int(g*255),int(b*255))
+
+ # Build array data string
+ data = ''
+ for i in range(Z.shape[0]):
+ for j in range(Z.shape[1]):
+ c = 16 + int( ((Z[Z.shape[0]-i-1,j]-cmap.min) / (cmap.max-cmap.min))*239)
+ if (c < 16):
+ c=16
+ elif (c > 255):
+ c=255
+ data += "\x1b[48;5;%dm " % c
+ u = cmap.max - (i/float(Z.shape[0]-1)) * ((cmap.max-cmap.min))
+ if show_cmap:
+ data += "\x1b[0m "
+ data += "\x1b[48;5;%dm " % (16 + (1-i/float(Z.shape[0]))*239)
+ data += "\x1b[0m %+.2f" % u
+ data += "\x1b[0m\n"
+ print init+data[:-1]+'\x1b[0m'
+
+
+if __name__ == '__main__':
+ face = Face('./Vera.ttf')
+ face.set_char_size( 32*64 )
+ face.load_glyph(face.get_char_index('S'))
+ slot = face.glyph
+ bitmap = slot.bitmap
+ data, rows, width = bitmap.buffer, bitmap.rows, bitmap.width
+ Z = numpy.array(data,dtype=float).reshape(rows,width)
+ Z = Z[::-1,:]
+ imshow (Z, cmap=CM_Grey)
+
diff --git a/third_party/freetype-py/examples/example_1.py b/third_party/freetype-py/examples/example_1.py
new file mode 100644
index 0000000..a21512b
--- /dev/null
+++ b/third_party/freetype-py/examples/example_1.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011-2014 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+#
+# Direct translation of example 1 from the freetype tutorial:
+# http://www.freetype.org/freetype2/docs/tutorial/step1.html
+#
+import math
+from freetype import *
+
+
+if __name__ == '__main__':
+ from PIL import Image
+ from freetype import *
+
+ WIDTH, HEIGHT = 640, 480
+ image = Image.new('L', (WIDTH,HEIGHT))
+ def draw_bitmap( bitmap, x, y):
+ x_max = x + bitmap.width
+ y_max = y + bitmap.rows
+ p = 0
+ for p,i in enumerate(range(x,x_max)):
+ for q,j in enumerate(range(y,y_max)):
+ if i < 0 or j < 0 or i >= WIDTH or j >= HEIGHT:
+ continue;
+ pixel = image.getpixel((i,j))
+ pixel |= int(bitmap.buffer[q * bitmap.width + p]);
+ image.putpixel((i,j), pixel)
+
+ library = FT_Library()
+ matrix = FT_Matrix()
+ face = FT_Face()
+ pen = FT_Vector()
+ filename= './Vera.ttf'
+ text = 'Hello World !'
+ num_chars = len(text)
+ angle = ( 25.0 / 360 ) * 3.14159 * 2
+
+ # initialize library, error handling omitted
+ error = FT_Init_FreeType( byref(library) )
+
+ # create face object, error handling omitted
+ error = FT_New_Face( library, filename, 0, byref(face) )
+
+ # set character size: 50pt at 100dpi, error handling omitted
+ error = FT_Set_Char_Size( face, 50 * 64, 0, 100, 0 )
+ slot = face.contents.glyph
+
+ # set up matrix
+ matrix.xx = (int)( math.cos( angle ) * 0x10000L )
+ matrix.xy = (int)(-math.sin( angle ) * 0x10000L )
+ matrix.yx = (int)( math.sin( angle ) * 0x10000L )
+ matrix.yy = (int)( math.cos( angle ) * 0x10000L )
+
+ # the pen position in 26.6 cartesian space coordinates; */
+ # start at (300,200) relative to the upper left corner */
+ pen.x = 200 * 64;
+ pen.y = ( HEIGHT - 300 ) * 64
+
+ for n in range(num_chars):
+ # set transformation
+ FT_Set_Transform( face, byref(matrix), byref(pen) )
+
+ # load glyph image into the slot (erase previous one)
+ charcode = ord(text[n])
+ index = FT_Get_Char_Index( face, charcode )
+ FT_Load_Glyph( face, index, FT_LOAD_RENDER )
+
+ # now, draw to our target surface (convert position)
+ draw_bitmap( slot.contents.bitmap,
+ slot.contents.bitmap_left,
+ HEIGHT - slot.contents.bitmap_top )
+
+ # increment pen position
+ pen.x += slot.contents.advance.x
+ pen.y += slot.contents.advance.y
+
+ FT_Done_Face(face)
+ FT_Done_FreeType(library)
+
+ import matplotlib.pyplot as plt
+ plt.imshow(image, origin='lower',
+ interpolation='nearest', cmap=plt.cm.gray)
+ plt.show()
diff --git a/third_party/freetype-py/examples/font-info.py b/third_party/freetype-py/examples/font-info.py
new file mode 100644
index 0000000..015ee94
--- /dev/null
+++ b/third_party/freetype-py/examples/font-info.py
@@ -0,0 +1,42 @@
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+from freetype import *
+
+if __name__ == '__main__':
+ import sys
+
+ if len(sys.argv) < 2:
+ print("Usage: %s font_filename" % sys.argv[0])
+ sys.exit()
+
+ face = Face(sys.argv[1])
+
+ print 'Family name: ', face.family_name
+ print 'Style name: ', face.style_name
+ print 'Charmaps: ', [charmap.encoding_name for charmap in face.charmaps]
+ print
+ print 'Face number: ', face.num_faces
+ print 'Glyph number: ', face.num_glyphs
+ print 'Available sizes: ', face.available_sizes
+ print
+ print 'units per em: ', face.units_per_EM
+ print 'ascender: ', face.ascender
+ print 'descender: ', face.descender
+ print 'height: ', face.height
+ print
+ print 'max_advance_width: ', face.max_advance_width
+ print 'max_advance_height: ', face.max_advance_height
+ print
+ print 'underline_position: ', face.underline_position
+ print 'underline_thickness:', face.underline_thickness
+ print
+ print 'Has horizontal: ', face.has_horizontal
+ print 'Has vertical: ', face.has_vertical
+ print 'Has kerning: ', face.has_kerning
+ print 'Is fixed width: ', face.is_fixed_width
+ print 'Is scalable: ', face.is_scalable
+ print
diff --git a/third_party/freetype-py/examples/ftdump.py b/third_party/freetype-py/examples/ftdump.py
new file mode 100644
index 0000000..13662aa
--- /dev/null
+++ b/third_party/freetype-py/examples/ftdump.py
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+# -----------------------------------------------------------------------------
+from __future__ import print_function
+from __future__ import division
+import sys
+from freetype import *
+
+verbose = 0
+debug = 0
+name_tables = 0
+
+def usage( execname ):
+ print( )
+ print( "ftdump: simple font dumper -- part of the FreeType project" )
+ print( "----------------------------------------------------------" )
+ print( "Usage: %s [options] fontname", execname )
+ print( )
+ print( " -n print SFNT name tables" )
+ print( " -v be verbose" )
+ print( )
+ sys.exit()
+
+
+def Print_Name( face ):
+ print( "font name entries" );
+ print( " family: %s" % face.family_name )
+ print( " style: %s" % face.style_name )
+ ps_name = face.postscript_name or "UNAVAILABLE"
+ print( " postscript: %s" % ps_name )
+
+
+def Print_Type( face ):
+
+ print( "font type entries" )
+
+ # module = &face->driver->root;
+ # printf( " FreeType driver: %s\n", module->clazz->module_name );
+
+ # Is it better to dump all sfnt tag names?
+ print( " sfnt wrapped: ",end="")
+ if face.is_sfnt: print( "yes")
+ else: print( "no")
+
+ # is scalable ?
+ print( " type: ", end="")
+ if face.is_scalable:
+ print( "scalable, ", end="")
+ if face.has_multiple_masters:
+ print( "multiple_masters, ", end="")
+ if face.has_fixed_sizes:
+ print( "fixed size",end="")
+ print()
+
+ # Direction
+ print( " direction: ", end="" )
+ if face.has_horizontal:
+ print( "horizontal, ", end="")
+ if face.has_vertical:
+ print( "vertical", end="")
+ print( )
+
+ # Fixed width
+ print( " fixed width: ", end="")
+ if face.is_fixed_width: print( "yes")
+ else: print( "no")
+
+ # Glyph names
+ print( " glyph names: ", end="")
+ if face.has_glyph_names: print( "yes")
+ else: print( "no")
+
+ if face.is_scalable:
+ print( " EM size: %d" % face.units_per_EM )
+ print( " global BBox: (%ld,%ld):(%ld,%ld)" %
+ (face.bbox.xMin, face.bbox.yMin,
+ face.bbox.xMax, face.bbox.yMax ))
+ print( " ascent: %d" % face.ascender )
+ print( " descent: %d" % face.descender )
+ print( " text height: %d" % face.height )
+
+
+def get_platform_id( platform_id ):
+ if platform_id == TT_PLATFORM_APPLE_UNICODE:
+ return "Apple (Unicode)"
+ elif platform_id == TT_PLATFORM_MACINTOSH:
+ return "Macintosh"
+ elif platform_id == TT_PLATFORM_ISO:
+ return "ISO (deprecated)"
+ elif platform_id == TT_PLATFORM_MICROSOFT:
+ return "Microsoft"
+ elif platform_id == TT_PLATFORM_CUSTOM:
+ return "custom"
+ elif platform_id == TT_PLATFORM_ADOBE:
+ return "Adobe"
+ else:
+ return "UNKNOWN"
+
+def get_name_id( name_id ):
+ if name_id == TT_NAME_ID_COPYRIGHT:
+ return "copyright"
+ elif name_id == TT_NAME_ID_FONT_FAMILY:
+ return "font family"
+ elif name_id == TT_NAME_ID_FONT_SUBFAMILY:
+ return "font subfamily"
+ elif name_id == TT_NAME_ID_UNIQUE_ID:
+ return "unique ID"
+ elif name_id == TT_NAME_ID_FULL_NAME:
+ return "full name"
+ elif name_id == TT_NAME_ID_VERSION_STRING:
+ return "version string"
+ elif name_id == TT_NAME_ID_PS_NAME:
+ return "PostScript name"
+ elif name_id == TT_NAME_ID_TRADEMARK:
+ return "trademark"
+
+ # the following values are from the OpenType spec
+ elif name_id == TT_NAME_ID_MANUFACTURER:
+ return "manufacturer"
+ elif name_id == TT_NAME_ID_DESIGNER:
+ return "designer"
+ elif name_id == TT_NAME_ID_DESCRIPTION:
+ return "description"
+ elif name_id == TT_NAME_ID_VENDOR_URL:
+ return "vendor URL"
+ elif name_id == TT_NAME_ID_DESIGNER_URL:
+ return "designer URL"
+ elif name_id == TT_NAME_ID_LICENSE:
+ return "license"
+ elif name_id == TT_NAME_ID_LICENSE_URL:
+ return "license URL"
+ # number 15 is reserved
+ elif name_id == TT_NAME_ID_PREFERRED_FAMILY:
+ return "preferred family"
+ elif name_id == TT_NAME_ID_PREFERRED_SUBFAMILY:
+ return "preferred subfamily"
+ elif name_id == TT_NAME_ID_MAC_FULL_NAME:
+ return "Mac full name"
+
+ # The following code is new as of 2000-01-21
+ elif name_id == TT_NAME_ID_SAMPLE_TEXT:
+ return "sample text"
+
+ # This is new in OpenType 1.3
+ elif name_id == TT_NAME_ID_CID_FINDFONT_NAME:
+ return "CID 'findfont' name"
+ else:
+ return "UNKNOWN";
+
+
+def Print_Sfnt_Names( face ):
+ print( "font string entries" );
+
+ for i in range(face.sfnt_name_count):
+
+ name = face.get_sfnt_name(i)
+ print( " %-15s [%s]" % ( get_name_id( name.name_id ),
+ get_platform_id( name.platform_id )),end="")
+
+ if name.platform_id == TT_PLATFORM_APPLE_UNICODE:
+ if name.encoding_id in [TT_APPLE_ID_DEFAULT,
+ TT_APPLE_ID_UNICODE_1_1,
+ TT_APPLE_ID_ISO_10646,
+ TT_APPLE_ID_UNICODE_2_0]:
+ print(name.string.decode('utf-16be', 'ignore'))
+ else:
+ print( "{unsupported encoding %d}" % name.encoding_id )
+
+ elif name.platform_id == TT_PLATFORM_MACINTOSH:
+ if name.language_id != TT_MAC_LANGID_ENGLISH:
+ print( " (language=%d)" % name.language_id )
+ print ( " : " )
+ if name.encoding_id == TT_MAC_ID_ROMAN:
+ # FIXME: convert from MacRoman to ASCII/ISO8895-1/whatever
+ # (MacRoman is mostly like ISO8895-1 but there are differences)
+ print(name.string)
+ else:
+ print( "{unsupported encoding %d}" % name.encoding_id )
+
+ elif name.platform_id == TT_PLATFORM_ISO:
+ if name.encoding_id in [ TT_ISO_ID_7BIT_ASCII,
+ TT_ISO_ID_8859_1]:
+ print(name.string)
+ print ( " : " )
+ if name.encoding_id == TT_ISO_ID_10646:
+ print(name.string.decode('utf-16be', 'ignore'))
+ else:
+ print( "{unsupported encoding %d}" % name.encoding_id )
+
+ elif name.platform_id == TT_PLATFORM_MICROSOFT:
+ if name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES:
+ print( " (language=0x%04x)" % name.language_id );
+ print( " : " )
+ if name.encoding_id in [TT_MS_ID_SYMBOL_CS,
+ TT_MS_ID_UNICODE_CS]:
+ print(name.string.decode('utf-16be', 'ignore'))
+ else:
+ print( "{unsupported encoding %d}" % name.encoding_id )
+ else:
+ print( "{unsupported platform}" )
+
+ print( )
+
+
+def Print_Fixed( face ):
+
+ # num_fixed_size
+ print( "fixed size\n" )
+
+ # available size
+ for i,bsize in enumerate(face.available_sizes):
+ print( " %3d: height %d, width %d\n",
+ i, bsize.height, bsize.width )
+ print( " size %.3f, x_ppem %.3f, y_ppem %.3f\n",
+ bsize.size / 64.0,
+ bsize.x_ppem / 64.0, bsize.y_ppem / 64.0 )
+
+
+def Print_Charmaps( face ):
+ global verbose
+ active = -1
+ if face.charmap:
+ active = face.charmap.index
+
+ # CharMaps
+ print( "charmaps" )
+ for i,charmap in enumerate(face.charmaps):
+ print( " %d: platform %d, encoding %d, language %d" %
+ (i, charmap.platform_id, charmap.encoding_id,
+ int(charmap.cmap_language_id)), end="" )
+ if i == active:
+ print( " (active)", end="" )
+ print ( )
+ if verbose:
+ face.set_charmap( charmap )
+ charcode, gindex = face.get_first_char()
+ while ( gindex ):
+ print( " 0x%04lx => %d" % (charcode, gindex) )
+ charcode, gindex = face.get_next_char( charcode, gindex )
+
+
+
+# -----------------------------------------------------------------------------
+if __name__ == '__main__':
+ import getopt
+ execname = sys.argv[0]
+
+ if len(sys.argv) < 2:
+ usage( execname )
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], ':nv')
+ except getopt.GetoptError, err:
+ usage( execname )
+
+ verbose = False
+ name_tables = False
+
+ for o, a in opts:
+ if o == "-v": verbose = True
+ elif o == "-n": name_tables = True
+ else: usage( execname )
+
+
+ face = Face(args[0])
+ num_faces = face.num_faces
+
+ if num_faces > 1:
+ print( "There are %d faces in this file." % num_faces)
+ else:
+ print( "There is 1 face in this file.")
+
+ for i in range(num_faces):
+ face = Face(args[0], i)
+
+ print( "\n----- Face number: %d -----\n" % i )
+ Print_Name( face )
+ print( "" )
+ Print_Type( face )
+ print( " glyph count: %d" % face.num_glyphs )
+
+ if name_tables and face.is_sfnt:
+ print( )
+ Print_Sfnt_Names( face )
+
+ if face.num_fixed_sizes:
+ print( )
+ Print_Fixed( face )
+
+ if face.num_charmaps:
+ print( )
+ Print_Charmaps( face )
diff --git a/third_party/freetype-py/examples/glyph-alpha.py b/third_party/freetype-py/examples/glyph-alpha.py
new file mode 100644
index 0000000..2477450
--- /dev/null
+++ b/third_party/freetype-py/examples/glyph-alpha.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+'''
+Glyph bitmap monochrome rendering
+'''
+from freetype import *
+
+if __name__ == '__main__':
+ import numpy
+ import matplotlib.pyplot as plt
+
+ face = Face('./Vera.ttf')
+ face.set_char_size( 48*64 )
+ face.load_char('S', FT_LOAD_RENDER )
+ bitmap = face.glyph.bitmap
+ width = face.glyph.bitmap.width
+ rows = face.glyph.bitmap.rows
+ pitch = face.glyph.bitmap.pitch
+
+ data = []
+ for i in range(rows):
+ data.extend(bitmap.buffer[i*pitch:i*pitch+width])
+ Z = numpy.array(data,dtype=numpy.ubyte).reshape(rows, width)
+ plt.imshow(Z, interpolation='nearest', cmap=plt.cm.gray, origin='lower')
+ plt.show()
diff --git a/third_party/freetype-py/examples/glyph-color.py b/third_party/freetype-py/examples/glyph-color.py
new file mode 100644
index 0000000..7f3b28e
--- /dev/null
+++ b/third_party/freetype-py/examples/glyph-color.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+'''
+Glyph colored rendering (with outline)
+'''
+from freetype import *
+
+if __name__ == '__main__':
+ import numpy as np
+ import matplotlib.pyplot as plt
+
+ face = Face('./Vera.ttf')
+ face.set_char_size( 96*64 )
+ RGBA = [('R',float), ('G',float), ('B',float), ('A',float)]
+
+ # Outline
+ flags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP
+ face.load_char('S', flags )
+ slot = face.glyph
+ glyph = slot.get_glyph()
+ stroker = Stroker( )
+ stroker.set(64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 )
+ glyph.stroke( stroker )
+ blyph = glyph.to_bitmap(FT_RENDER_MODE_NORMAL, Vector(0,0))
+ bitmap = blyph.bitmap
+ width, rows, pitch = bitmap.width, bitmap.rows, bitmap.pitch
+ top, left = blyph.top, blyph.left
+ data = []
+ for i in range(rows):
+ data.extend(bitmap.buffer[i*pitch:i*pitch+width])
+ Z = np.array(data).reshape(rows, width)/255.0
+ O = np.zeros((rows,width), dtype=RGBA)
+ O['A'] = Z
+ O['R'] = 1
+ O['G'] = 0
+ O['B'] = 0
+
+ # Plain
+ flags = FT_LOAD_RENDER
+ face.load_char('S', flags)
+ F = np.zeros((rows,width), dtype=RGBA)
+ Z = np.zeros((rows, width))
+ bitmap = face.glyph.bitmap
+ width, rows, pitch = bitmap.width, bitmap.rows, bitmap.pitch
+ top, left = face.glyph.bitmap_top, face.glyph.bitmap_left
+ dy = blyph.top - face.glyph.bitmap_top
+ dx = face.glyph.bitmap_left - blyph.left
+ data = []
+ for i in range(rows):
+ data.extend(bitmap.buffer[i*pitch:i*pitch+width])
+ Z[dx:dx+rows,dy:dy+width] = np.array(data).reshape(rows, width)/255.
+ F['R'] = 1
+ F['G'] = 1
+ F['B'] = 0
+ F['A'] = Z
+
+ # Combine outline and plain
+ R1,G1,B1,A1 = O['R'],O['G'],O['B'],O['A']
+ R2,G2,B2,A2 = F['R'],F['G'],F['B'],F['A']
+ Z = np.zeros(O.shape, dtype=RGBA)
+ Z['R'] = (A1 * R1 + A2 * (1 - A1) * R2)
+ Z['G'] = (A1 * G1 + A2 * (1 - A1) * G2)
+ Z['B'] = (A1 * B1 + A2 * (1 - A1) * B2)
+ Z['A'] = (A1 + A2 * (1 - A1))
+
+
+ # Draw
+ plt.figure(figsize=(12,5))
+
+ plt.subplot(1,3,1)
+ plt.title('Plain')
+ plt.xticks([]), plt.yticks([])
+ I = F.view(dtype=float).reshape(O.shape[0],O.shape[1],4)
+ plt.imshow(I, interpolation='nearest', origin='lower')
+
+ plt.subplot(1,3,2)
+ plt.title('Outline')
+ plt.xticks([]), plt.yticks([])
+ I = O.view(dtype=float).reshape(O.shape[0],O.shape[1],4)
+ plt.imshow(I, interpolation='nearest', origin='lower')
+
+ plt.subplot(1,3,3)
+ plt.title('Outline + Plain')
+ plt.xticks([]), plt.yticks([])
+ I = Z.view(dtype=float).reshape(O.shape[0],O.shape[1],4)
+ plt.imshow(I, interpolation='nearest', origin='lower')
+
+ plt.show()
diff --git a/third_party/freetype-py/examples/glyph-lcd.py b/third_party/freetype-py/examples/glyph-lcd.py
new file mode 100644
index 0000000..5992c12
--- /dev/null
+++ b/third_party/freetype-py/examples/glyph-lcd.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+'''
+Glyph bitmap monochrome rendring
+'''
+from freetype import *
+
+if __name__ == '__main__':
+ import numpy
+ import matplotlib.pyplot as plt
+
+ face = Face('./Vera.ttf')
+ face.set_char_size( 48*64 )
+ face.load_char('S', FT_LOAD_RENDER |
+ FT_LOAD_TARGET_LCD )
+ bitmap = face.glyph.bitmap
+ width = face.glyph.bitmap.width
+ rows = face.glyph.bitmap.rows
+ pitch = face.glyph.bitmap.pitch
+
+ data = []
+ for i in range(rows):
+ data.extend(bitmap.buffer[i*pitch:i*pitch+width])
+ Z = numpy.array(data,dtype=numpy.ubyte).reshape(rows, width/3, 3)
+ plt.imshow(Z, interpolation='nearest', origin='lower')
+ plt.show()
diff --git a/third_party/freetype-py/examples/glyph-metrics.py b/third_party/freetype-py/examples/glyph-metrics.py
new file mode 100644
index 0000000..f0bb21a
--- /dev/null
+++ b/third_party/freetype-py/examples/glyph-metrics.py
@@ -0,0 +1,233 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+'''
+Show glyph metrics in horizontal and vertical layout
+'''
+from freetype import *
+
+def arrow( x,y, dx, dy, **kwargs):
+ kwargs['shape'] = 'full'
+ kwargs['head_width'] = 30
+ kwargs['head_length'] = 40
+ kwargs['length_includes_head'] =True
+ kwargs['facecolor'] = 'k'
+ kwargs['edgecolor'] ='k'
+ kwargs['linewidth'] =.5
+ plt.arrow(x,y,dx,dy,**kwargs)
+
+def double_arrow(x, y, dx, dy, **kwargs):
+ cx,cy = x+dx/2., y+dy/2.
+ dx /= 2.0
+ dy /= 2.0
+ arrow(cx,cy,+dx,+dy,**kwargs)
+ arrow(cx,cy,-dx,-dy,**kwargs)
+
+def line(x, y, dx, dy, **kwargs):
+ kwargs['color'] = 'k'
+ kwargs['linewidth'] =.5
+ plt.plot([x,x+dx],[y,y+dy],**kwargs)
+
+def point(x, y, r, **kwargs):
+ kwargs['color'] = 'k'
+ plt.scatter([x],[y],r,**kwargs)
+
+def text( x,y,text, **kwargs):
+ kwargs['fontsize'] = 18
+ plt.text(x, y, text, **kwargs)
+
+
+
+if __name__ == '__main__':
+ import numpy as np
+ import matplotlib.pyplot as plt
+ from matplotlib.path import Path
+ import matplotlib.patches as patches
+
+
+ face = Face('./Vera.ttf')
+ face.set_char_size( 32*64 )
+ face.load_char('g')
+ slot = face.glyph
+ bitmap = slot.bitmap
+ width = slot.bitmap.width
+ rows = slot.bitmap.rows
+ pitch = slot.bitmap.pitch
+ outline= slot.outline
+
+ start, end = 0, 0
+ VERTS, CODES = [], []
+ # Iterate over each contour
+ for i in range(len(outline.contours)):
+ end = outline.contours[i]
+ points = outline.points[start:end+1]
+ points.append(points[0])
+ tags = outline.tags[start:end+1]
+ tags.append(tags[0])
+ segments = [ [points[0],], ]
+ for j in range(1, len(points) ):
+ segments[-1].append(points[j])
+ if tags[j] & (1 << 0) and j < (len(points)-1):
+ segments.append( [points[j],] )
+ verts = [points[0], ]
+ codes = [Path.MOVETO,]
+ for segment in segments:
+ if len(segment) == 2:
+ verts.extend(segment[1:])
+ codes.extend([Path.LINETO])
+ elif len(segment) == 3:
+ verts.extend(segment[1:])
+ codes.extend([Path.CURVE3, Path.CURVE3])
+ else:
+ verts.append(segment[1])
+ codes.append(Path.CURVE3)
+ for i in range(1,len(segment)-2):
+ A,B = segment[i], segment[i+1]
+ C = ((A[0]+B[0])/2.0, (A[1]+B[1])/2.0)
+ verts.extend([ C, B ])
+ codes.extend([ Path.CURVE3, Path.CURVE3])
+ verts.append(segment[-1])
+ codes.append(Path.CURVE3)
+ VERTS.extend(verts)
+ CODES.extend(codes)
+ start = end+1
+ VERTS = np.array(VERTS)
+ x,y = VERTS[:,0], VERTS[:,1]
+ VERTS[:,0], VERTS[:,1] = x, y
+
+
+ path = Path(VERTS, CODES)
+ xmin, xmax = x.min(), x.max()
+ ymin, ymax = y.min(), y.max()
+ width,height = xmax-xmin, ymax-ymin
+ dw, dh = 0.2*width, 0.1*height
+ bearing = xmin - slot.metrics.horiBearingX, ymin - slot.metrics.horiBearingY
+ advance = slot.advance
+ origin = bearing
+
+
+ figure = plt.figure(figsize=(16,10), frameon=False, facecolor="white")
+
+ axes = plt.subplot(121, frameon=False, aspect=1)
+ glyph = patches.PathPatch(path, fill = True, facecolor='k', lw=0)
+ plt.xlim(xmin - .25*width, xmax + .75*width)
+ plt.ylim(ymin - .5*height, xmax + .75*height)
+ plt.xticks([]), plt.yticks([])
+ axes.add_patch(glyph)
+
+ # Y axis
+ arrow(origin[0], ymin-dh, 0, height+3*dh)
+
+ # X axis
+ arrow(origin[0]-dw, 0, width+3*dw, 0)
+
+ # origin
+ point(0,0,50)
+ text( -20, -20, "$origin$", va='top', ha='right')
+
+ # Bounding box
+ bbox = patches.Rectangle( (xmin,ymin), width, height, fill = False, lw=.5)
+ axes.add_patch(bbox)
+
+ # Width
+ line(xmin, ymax, 0, 3*dh, linestyle="dotted")
+ text( xmin, ymax+3.25*dh, "$x_{min}$", va='bottom', ha='center')
+ line(xmax, ymax, 0, 3*dh, linestyle="dotted")
+ text( xmax, ymax+3.25*dh, "$x_{max}$", va='bottom', ha='center')
+ double_arrow(xmin, ymax+2.5*dh, width, 0)
+ text(xmin+width/2., ymax+1.75*dh, "$width$", va='bottom', ha='center')
+
+ # Height
+ line(xmax, ymin, 3*dw, 0, linestyle="dotted")
+ text(xmax+3.25*dw, ymin, "$y_{min}$", va='baseline', ha='left')
+ line(xmax, ymax, 3*dw, 0, linestyle="dotted")
+ text(xmax+3.25*dw, ymax, "$y_{max}$", va='baseline', ha='left')
+ double_arrow(xmax+2.5*dw, ymin, 0, height)
+ text(xmax+2.75*dw, ymin+height/2., "$height$", va='center', ha='left')
+
+ # Advance
+ point(advance.x,0,50)
+ line(advance.x, 0, 0, ymin-dh, linestyle="dotted")
+ arrow(0, ymin-.5*dh, advance.x, 0)
+ text(advance.x/2., ymin-1.25*dh, "$advance$", va='bottom', ha='center')
+
+ # Bearing Y
+ arrow(xmax+.25*dw, 0, 0, ymax)
+ text(xmax+.5*dw, ymax/2, "$Y_{bearing}$", va='center', ha='left')
+
+ # Bearing X
+ arrow(0, ymax/2., xmin, 0)
+ text(-10, ymax/2, "$X_{bearing}$", va='baseline', ha='right')
+
+
+ # -------------------------------------------------------------------------
+
+ axes = plt.subplot(122, frameon=False, aspect=1)
+ glyph = patches.PathPatch(path, fill = True, facecolor='k', lw=0)
+ axes.add_patch(glyph)
+
+ plt.xlim(xmin - .25*width, xmax + .75*width)
+ plt.ylim(ymin - .5*height, xmax + .75*height)
+ plt.xticks([]), plt.yticks([])
+
+
+ advance = slot.metrics.vertAdvance
+ x_bearing = slot.metrics.vertBearingX
+ y_bearing = slot.metrics.vertBearingY
+
+ # Y axis
+ arrow(xmin-x_bearing, ymax+y_bearing+2*dh, 0, -advance-3*dh)
+
+ # X axis
+ arrow(xmin-2*dw, ymax+y_bearing, width+4*dw, 0)
+
+ # origin
+ point( xmin-x_bearing, ymax+y_bearing, 50)
+ text( xmin-x_bearing-30, ymax+y_bearing+10, "$origin$", va='bottom', ha='right')
+
+ # Bounding box
+ bbox = patches.Rectangle( (xmin,ymin), width, height, fill = False, lw=.5)
+ axes.add_patch(bbox)
+
+
+ # # Advance
+ point(xmin-x_bearing, ymax+y_bearing-advance, 50)
+ line(xmin-x_bearing, ymax+y_bearing-advance, xmax-dw, 0, linestyle="dotted")
+ arrow(xmax+dw, ymax+y_bearing, 0, -advance)
+ text(xmax+1.25*dw, ymax+y_bearing-advance/2., "$advance$", va='baseline', ha='left')
+
+
+ # Width
+ line(xmin, ymin, 0, -4*dh, linestyle="dotted")
+ text( xmin, ymin-4.25*dh, "$x_{min}$", va='top', ha='center')
+ line(xmax, ymin, 0, -4*dh, linestyle="dotted")
+ text( xmax, ymin-4.25*dh, "$x_{max}$", va='top', ha='center')
+ double_arrow(xmin, ymin-3.5*dh, width, 0)
+ text(xmin+width/2., ymin-3.75*dh, "$width$", va='top', ha='center')
+
+ # Height
+ line(xmin, ymin, -3*dw, 0, linestyle="dotted")
+ text(xmin-1.5*dw, ymin, "$y_{min}$", va='baseline', ha='right')
+ line(xmin, ymax, -3*dw, 0, linestyle="dotted")
+ text(xmin-1.5*dw, ymax, "$y_{max}$", va='baseline', ha='right')
+ double_arrow(xmin-.5*dw, ymin, 0, height)
+ text(xmin-.75*dw, ymin+height/2., "$height$", va='center', ha='right')
+
+
+ #point(xmin-x_bearing, ymax+y_bearing, 50)
+ # Bearing Y
+ arrow(xmax-.5*dw, ymax+y_bearing, 0, -y_bearing)
+ text(xmax-.5*dw, ymax+y_bearing+.25*dh, "$Y_{bearing}$", va='bottom', ha='center')
+
+ # # Bearing X
+ line(xmin, ymax, 0, 3*dh, linestyle="dotted")
+ arrow(xmin-x_bearing, ymax+y_bearing+dh, x_bearing, 0)
+ text(xmin-.25*dw, ymax+y_bearing+dh, "$X_{bearing}$", va='baseline', ha='right')
+
+ plt.savefig('glyph-metrics.pdf')
+ plt.show()
diff --git a/third_party/freetype-py/examples/glyph-monochrome.py b/third_party/freetype-py/examples/glyph-monochrome.py
new file mode 100644
index 0000000..3714ceb
--- /dev/null
+++ b/third_party/freetype-py/examples/glyph-monochrome.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+'''
+Glyph bitmap monochrome rendring
+'''
+from freetype import *
+
+def bits(x):
+ data = []
+ for i in range(8):
+ data.insert(0, int((x & 1) == 1))
+ x = x >> 1
+ return data
+
+if __name__ == '__main__':
+ import numpy
+ import matplotlib.pyplot as plt
+
+ face = Face('./Vera.ttf')
+ face.set_char_size( 48*64 )
+ face.load_char('S', FT_LOAD_RENDER |
+ FT_LOAD_TARGET_MONO )
+
+ bitmap = face.glyph.bitmap
+ width = face.glyph.bitmap.width
+ rows = face.glyph.bitmap.rows
+ pitch = face.glyph.bitmap.pitch
+
+ data = []
+ for i in range(bitmap.rows):
+ row = []
+ for j in range(bitmap.pitch):
+ row.extend(bits(bitmap.buffer[i*bitmap.pitch+j]))
+ data.extend(row[:bitmap.width])
+ Z = numpy.array(data).reshape(bitmap.rows, bitmap.width)
+ plt.imshow(Z, interpolation='nearest', cmap=plt.cm.gray, origin='lower')
+ plt.show()
diff --git a/third_party/freetype-py/examples/glyph-outline.py b/third_party/freetype-py/examples/glyph-outline.py
new file mode 100644
index 0000000..6588e21
--- /dev/null
+++ b/third_party/freetype-py/examples/glyph-outline.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+'''
+Glyph outline rendering
+'''
+from freetype import *
+
+if __name__ == '__main__':
+ import numpy
+ import matplotlib.pyplot as plt
+
+ face = Face('./Vera.ttf')
+ face.set_char_size( 4*48*64 )
+ flags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP
+ face.load_char('S', flags )
+ slot = face.glyph
+ glyph = slot.get_glyph()
+ stroker = Stroker( )
+ stroker.set(64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 )
+ glyph.stroke( stroker )
+ blyph = glyph.to_bitmap(FT_RENDER_MODE_NORMAL, Vector(0,0))
+ bitmap = blyph.bitmap
+ width, rows, pitch = bitmap.width, bitmap.rows, bitmap.pitch
+ top, left = blyph.top, blyph.left
+ data = []
+ for i in range(rows):
+ data.extend(bitmap.buffer[i*pitch:i*pitch+width])
+ Z = numpy.array(data,dtype=numpy.ubyte).reshape(rows, width)
+ plt.figure(figsize=(6,8))
+ plt.imshow(Z, interpolation='nearest', cmap=plt.cm.gray_r, origin='lower')
+ plt.show()
diff --git a/third_party/freetype-py/examples/glyph-vector-2.py b/third_party/freetype-py/examples/glyph-vector-2.py
new file mode 100644
index 0000000..fc2c7da
--- /dev/null
+++ b/third_party/freetype-py/examples/glyph-vector-2.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+'''
+Show how to access glyph outline description.
+'''
+from freetype import *
+
+if __name__ == '__main__':
+ import numpy
+ import matplotlib.pyplot as plt
+ from matplotlib.path import Path
+ import matplotlib.patches as patches
+
+ face = Face('./Vera.ttf')
+ face.set_char_size( 32*64 )
+ face.load_char('g')
+ slot = face.glyph
+
+ bitmap = face.glyph.bitmap
+ width = face.glyph.bitmap.width
+ rows = face.glyph.bitmap.rows
+ pitch = face.glyph.bitmap.pitch
+
+ data = []
+ for i in range(rows):
+ data.extend(bitmap.buffer[i*pitch:i*pitch+width])
+ Z = numpy.array(data,dtype=numpy.ubyte).reshape(rows, width)
+
+ outline = slot.outline
+ points = numpy.array(outline.points, dtype=[('x',float), ('y',float)])
+ x, y = points['x'], points['y']
+
+ figure = plt.figure(figsize=(8,10))
+ axis = figure.add_subplot(111)
+ #axis.scatter(points['x'], points['y'], alpha=.25)
+ start, end = 0, 0
+
+ VERTS, CODES = [], []
+ # Iterate over each contour
+ for i in range(len(outline.contours)):
+ end = outline.contours[i]
+ points = outline.points[start:end+1]
+ points.append(points[0])
+ tags = outline.tags[start:end+1]
+ tags.append(tags[0])
+
+ segments = [ [points[0],], ]
+ for j in range(1, len(points) ):
+ segments[-1].append(points[j])
+ if tags[j] & (1 << 0) and j < (len(points)-1):
+ segments.append( [points[j],] )
+ verts = [points[0], ]
+ codes = [Path.MOVETO,]
+ for segment in segments:
+ if len(segment) == 2:
+ verts.extend(segment[1:])
+ codes.extend([Path.LINETO])
+ elif len(segment) == 3:
+ verts.extend(segment[1:])
+ codes.extend([Path.CURVE3, Path.CURVE3])
+ else:
+ verts.append(segment[1])
+ codes.append(Path.CURVE3)
+ for i in range(1,len(segment)-2):
+ A,B = segment[i], segment[i+1]
+ C = ((A[0]+B[0])/2.0, (A[1]+B[1])/2.0)
+ verts.extend([ C, B ])
+ codes.extend([ Path.CURVE3, Path.CURVE3])
+ verts.append(segment[-1])
+ codes.append(Path.CURVE3)
+ VERTS.extend(verts)
+ CODES.extend(codes)
+ start = end+1
+
+
+ # Draw glyph
+ path = Path(VERTS, CODES)
+ glyph = patches.PathPatch(path, fill = True, facecolor=(0.8,0.5,0.8), alpha=.25, lw=0)
+ glyph_outline = patches.PathPatch(path, fill = False, edgecolor='black', lw=3)
+
+ plt.imshow(Z, extent=[x.min(), x.max(),y.min(), y.max()], origin='lower',
+ interpolation='nearest', cmap = plt.cm.gray_r, vmin=0, vmax=400)
+ plt.xticks(numpy.linspace(x.min(), x.max(), Z.shape[1]+1), ())
+ plt.yticks(numpy.linspace(y.min(), y.max(), Z.shape[0]+1), ())
+ plt.grid(color='k', linewidth=1, linestyle='-')
+ axis.add_patch(glyph)
+ axis.add_patch(glyph_outline)
+ axis.set_xlim(x.min(), x.max())
+ axis.set_ylim(y.min(), y.max())
+
+ plt.savefig('test.svg')
+ plt.show()
diff --git a/third_party/freetype-py/examples/glyph-vector.py b/third_party/freetype-py/examples/glyph-vector.py
new file mode 100644
index 0000000..8cc34bf
--- /dev/null
+++ b/third_party/freetype-py/examples/glyph-vector.py
@@ -0,0 +1,91 @@
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+'''
+Show how to access glyph outline description.
+'''
+from freetype import *
+
+if __name__ == '__main__':
+ import numpy
+ import matplotlib.pyplot as plt
+ from matplotlib.path import Path
+ import matplotlib.patches as patches
+
+ face = Face('./Vera.ttf')
+ face.set_char_size( 48*64 )
+ face.load_char('S')
+ slot = face.glyph
+
+ outline = slot.outline
+ points = numpy.array(outline.points, dtype=[('x',float), ('y',float)])
+ x, y = points['x'], points['y']
+
+ figure = plt.figure(figsize=(8,10))
+ axis = figure.add_subplot(111)
+ #axis.scatter(points['x'], points['y'], alpha=.25)
+ start, end = 0, 0
+
+ VERTS, CODES = [], []
+ # Iterate over each contour
+ for i in range(len(outline.contours)):
+ end = outline.contours[i]
+ points = outline.points[start:end+1]
+ points.append(points[0])
+ tags = outline.tags[start:end+1]
+ tags.append(tags[0])
+
+ segments = [ [points[0],], ]
+ for j in range(1, len(points) ):
+ segments[-1].append(points[j])
+ if tags[j] & (1 << 0) and j < (len(points)-1):
+ segments.append( [points[j],] )
+ verts = [points[0], ]
+ codes = [Path.MOVETO,]
+ for segment in segments:
+ if len(segment) == 2:
+ verts.extend(segment[1:])
+ codes.extend([Path.LINETO])
+ elif len(segment) == 3:
+ verts.extend(segment[1:])
+ codes.extend([Path.CURVE3, Path.CURVE3])
+ else:
+ verts.append(segment[1])
+ codes.append(Path.CURVE3)
+ for i in range(1,len(segment)-2):
+ A,B = segment[i], segment[i+1]
+ C = ((A[0]+B[0])/2.0, (A[1]+B[1])/2.0)
+ verts.extend([ C, B ])
+ codes.extend([ Path.CURVE3, Path.CURVE3])
+ verts.append(segment[-1])
+ codes.append(Path.CURVE3)
+ VERTS.extend(verts)
+ CODES.extend(codes)
+ start = end+1
+
+
+ # Draw glyph lines
+ path = Path(VERTS, CODES)
+ glyph = patches.PathPatch(path, facecolor='.75', lw=1)
+
+ # Draw "control" lines
+ for i, code in enumerate(CODES):
+ if code == Path.CURVE3:
+ CODES[i] = Path.LINETO
+ path = Path(VERTS, CODES)
+ patch = patches.PathPatch(path, ec='.5', fill=False, ls='dashed', lw=1 )
+
+ axis.add_patch(patch)
+ axis.add_patch(glyph)
+
+ axis.set_xlim(x.min()-100, x.max()+100)
+ plt.xticks([])
+ axis.set_ylim(y.min()-100, y.max()+100)
+ plt.yticks([])
+ plt.show()
+
+
+
diff --git a/third_party/freetype-py/examples/hello-world.py b/third_party/freetype-py/examples/hello-world.py
new file mode 100644
index 0000000..72126ae
--- /dev/null
+++ b/third_party/freetype-py/examples/hello-world.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+from freetype import *
+
+if __name__ == '__main__':
+ import numpy
+ import matplotlib.pyplot as plt
+
+ face = Face('./Vera.ttf')
+ text = 'Hello World !'
+ face.set_char_size( 48*64 )
+ slot = face.glyph
+
+ # First pass to compute bbox
+ width, height, baseline = 0, 0, 0
+ previous = 0
+ for i,c in enumerate(text):
+ face.load_char(c)
+ bitmap = slot.bitmap
+ height = max(height,
+ bitmap.rows + max(0,-(slot.bitmap_top-bitmap.rows)))
+ baseline = max(baseline, max(0,-(slot.bitmap_top-bitmap.rows)))
+ kerning = face.get_kerning(previous, c)
+ width += (slot.advance.x >> 6) + (kerning.x >> 6)
+ previous = c
+
+ Z = numpy.zeros((height,width), dtype=numpy.ubyte)
+
+ # Second pass for actual rendering
+ x, y = 0, 0
+ previous = 0
+ for c in text:
+ face.load_char(c)
+ bitmap = slot.bitmap
+ top = slot.bitmap_top
+ left = slot.bitmap_left
+ w,h = bitmap.width, bitmap.rows
+ y = height-baseline-top
+ kerning = face.get_kerning(previous, c)
+ x += (kerning.x >> 6)
+ Z[y:y+h,x:x+w] += numpy.array(bitmap.buffer).reshape(h,w)
+ x += (slot.advance.x >> 6)
+ previous = c
+
+ plt.figure(figsize=(10, 10*Z.shape[0]/float(Z.shape[1])))
+ plt.imshow(Z, interpolation='nearest', origin='upper', cmap=plt.cm.gray)
+ plt.xticks([]), plt.yticks([])
+ plt.show()
diff --git a/third_party/freetype-py/examples/opengl.py b/third_party/freetype-py/examples/opengl.py
new file mode 100644
index 0000000..19309be
--- /dev/null
+++ b/third_party/freetype-py/examples/opengl.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+import numpy
+from freetype import *
+import OpenGL.GL as gl
+import OpenGL.GLUT as glut
+
+base, texid = 0, 0
+text = '''Hello World !'''
+
+def on_display( ):
+ global texid
+ gl.glClearColor(1,1,1,1)
+ gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
+ gl.glBindTexture( gl.GL_TEXTURE_2D, texid )
+ gl.glColor(0,0,0,1)
+ gl.glPushMatrix( )
+ gl.glTranslate( 10, 100, 0 )
+ gl.glPushMatrix( )
+ gl.glListBase( base+1 )
+ gl.glCallLists( [ord(c) for c in text] )
+ gl.glPopMatrix( )
+ gl.glPopMatrix( )
+ glut.glutSwapBuffers( )
+
+def on_reshape( width, height ):
+ gl.glViewport( 0, 0, width, height )
+ gl.glMatrixMode( gl.GL_PROJECTION )
+ gl.glLoadIdentity( )
+ gl.glOrtho( 0, width, 0, height, -1, 1 )
+ gl.glMatrixMode( gl.GL_MODELVIEW )
+ gl.glLoadIdentity( )
+
+def on_keyboard( key, x, y ):
+ if key == '\033': sys.exit( )
+
+def makefont(filename, size):
+ global texid
+
+ # Load font and check it is monotype
+ face = Face(filename)
+ face.set_char_size( size*64 )
+ if not face.is_fixed_width:
+ raise 'Font is not monotype'
+
+ # Determine largest glyph size
+ width, height, ascender, descender = 0, 0, 0, 0
+ for c in range(32,128):
+ face.load_char( chr(c), FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT )
+ bitmap = face.glyph.bitmap
+ width = max( width, bitmap.width )
+ ascender = max( ascender, face.glyph.bitmap_top )
+ descender = max( descender, bitmap.rows-face.glyph.bitmap_top )
+ height = ascender+descender
+
+ # Generate texture data
+ Z = numpy.zeros((height*6, width*16), dtype=numpy.ubyte)
+ for j in range(6):
+ for i in range(16):
+ face.load_char(chr(32+j*16+i), FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT )
+ bitmap = face.glyph.bitmap
+ x = i*width + face.glyph.bitmap_left
+ y = j*height + ascender - face.glyph.bitmap_top
+ Z[y:y+bitmap.rows,x:x+bitmap.width].flat = bitmap.buffer
+
+ # Bound texture
+ texid = gl.glGenTextures(1)
+ gl.glBindTexture( gl.GL_TEXTURE_2D, texid )
+ gl.glTexParameterf( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR )
+ gl.glTexParameterf( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR )
+ gl.glTexImage2D( gl.GL_TEXTURE_2D, 0, gl.GL_ALPHA, Z.shape[1], Z.shape[0], 0,
+ gl.GL_ALPHA, gl.GL_UNSIGNED_BYTE, Z )
+
+ # Generate display lists
+ dx, dy = width/float(Z.shape[1]), height/float(Z.shape[0])
+ base = gl.glGenLists(8*16)
+ for i in range(8*16):
+ c = chr(i)
+ x = i%16
+ y = i//16-2
+ gl.glNewList(base+i, gl.GL_COMPILE)
+ if (c == '\n'):
+ gl.glPopMatrix( )
+ gl.glTranslatef( 0, -height, 0 )
+ gl.glPushMatrix( )
+ elif (c == '\t'):
+ gl.glTranslatef( 4*width, 0, 0 )
+ elif (i >= 32):
+ gl.glBegin( gl.GL_QUADS )
+ gl.glTexCoord2f( (x )*dx, (y+1)*dy ), gl.glVertex( 0, -height )
+ gl.glTexCoord2f( (x )*dx, (y )*dy ), gl.glVertex( 0, 0 )
+ gl.glTexCoord2f( (x+1)*dx, (y )*dy ), gl.glVertex( width, 0 )
+ gl.glTexCoord2f( (x+1)*dx, (y+1)*dy ), gl.glVertex( width, -height )
+ gl.glEnd( )
+ gl.glTranslatef( width, 0, 0 )
+ gl.glEndList( )
+
+
+if __name__ == '__main__':
+ import sys
+ glut.glutInit( sys.argv )
+ glut.glutInitDisplayMode( glut.GLUT_DOUBLE | glut.GLUT_RGB | glut.GLUT_DEPTH )
+ glut.glutCreateWindow( "Freetype OpenGL" )
+ glut.glutReshapeWindow( 600, 100 )
+ glut.glutDisplayFunc( on_display )
+ glut.glutReshapeFunc( on_reshape )
+ glut.glutKeyboardFunc( on_keyboard )
+ gl.glTexEnvf( gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_MODULATE )
+ gl.glEnable( gl.GL_DEPTH_TEST )
+ gl.glEnable( gl.GL_BLEND )
+ gl.glEnable( gl.GL_COLOR_MATERIAL )
+ gl.glColorMaterial( gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT_AND_DIFFUSE )
+ gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA )
+ gl.glEnable( gl.GL_TEXTURE_2D )
+ makefont( './VeraMono.ttf', 64 )
+ glut.glutMainLoop( )
diff --git a/third_party/freetype-py/examples/sfnt-names.py b/third_party/freetype-py/examples/sfnt-names.py
new file mode 100644
index 0000000..ffebc00
--- /dev/null
+++ b/third_party/freetype-py/examples/sfnt-names.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+# -----------------------------------------------------------------------------
+from __future__ import print_function
+from __future__ import division
+from freetype import *
+
+def platform_name(platform_id):
+ for key, value in TT_PLATFORMS.items():
+ if value == platform_id:
+ return key
+ return 'Unknown platform'
+
+def encoding_name(platform_id, encoding_id):
+ if platform_id == TT_PLATFORM_APPLE_UNICODE:
+ encodings = TT_APPLE_IDS
+ elif platform_id == TT_PLATFORM_MACINTOSH:
+ encodings = TT_MAC_IDS
+ elif platform_id == TT_PLATFORM_MICROSOFT:
+ encodings = TT_MS_IDS
+ elif platform_id == TT_PLATFORM_ADOBE:
+ encodings = TT_ADOBE_IDS
+ else:
+ return 'Unknown encoding'
+ for key, value in encodings.items():
+ if value == encoding_id:
+ return key
+ return 'Unknown encoding'
+
+def language_name(platform_id, language_id):
+ if platform_id == TT_PLATFORM_MACINTOSH:
+ languages = TT_MAC_LANGIDS
+ elif platform_id == TT_PLATFORM_MICROSOFT:
+ languages = TT_MS_LANGIDS
+ else:
+ return 'Unknown language'
+ for key, value in languages.items():
+ if value == language_id:
+ return key
+ return 'Unknown language'
+
+
+if __name__ == '__main__':
+ import os, sys
+
+ if len(sys.argv) < 2:
+ print("Usage: %s font_filename" % sys.argv[0])
+ sys.exit()
+ face = Face(sys.argv[1])
+
+ name = face.get_sfnt_name(0)
+ print( 'platform_id:', platform_name(name.platform_id) )
+ print( 'encoding_id:', encoding_name(name.platform_id,
+ name.encoding_id) )
+ print( 'language_id:', language_name(name.platform_id,
+ name.language_id) )
+ for i in range(face.sfnt_name_count):
+ name = face.get_sfnt_name(i).string
+ print(i, name.decode('utf-8', 'ignore'))
+
+
+
+
diff --git a/third_party/freetype-py/examples/shader.py b/third_party/freetype-py/examples/shader.py
new file mode 100644
index 0000000..998dd8b
--- /dev/null
+++ b/third_party/freetype-py/examples/shader.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (C) 2009-2010 Nicolas P. Rougier
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+# -----------------------------------------------------------------------------
+#
+# Copyright Tristam Macdonald 2008.
+#
+# Distributed under the Boost Software License, Version 1.0
+# (see http://www.boost.org/LICENSE_1_0.txt)
+#
+''' Base shader class.
+
+ Example:
+ --------
+ shader = Shader()
+
+ shader.bind()
+ glActiveTexture(GL_TEXTURE1)
+ glBindTexture(lut.target, lut.id)
+ shader.uniformi('lut', 1)
+
+ glActiveTexture(GL_TEXTURE0)
+ glBindTexture(texture.target, texture.id)
+ shader.uniformi('texture', 0)
+ shader.uniformf('pixel', 1.0/texture.width, 1.0/texture.height)
+
+ texture.blit(x,y,w,h)
+ shader.unbind()
+'''
+import os
+import OpenGL.GL as gl
+import ctypes
+
+class Shader:
+ ''' Base shader class. '''
+
+ def __init__(self, vert = None, frag = None, name=''):
+ ''' vert, frag and geom take arrays of source strings
+ the arrays will be concatenated into one string by OpenGL.'''
+
+ self.uniforms = {}
+ self.name = name
+ # create the program handle
+ self.handle = gl.glCreateProgram()
+ # we are not linked yet
+ self.linked = False
+ # create the vertex shader
+ self._build_shader(vert, gl.GL_VERTEX_SHADER)
+ # create the fragment shader
+ self._build_shader(frag, gl.GL_FRAGMENT_SHADER)
+ # the geometry shader will be the same, once pyglet supports the
+ # extension self.createShader(frag, GL_GEOMETRY_SHADER_EXT) attempt to
+ # link the program
+ self._link()
+
+ def _build_shader(self, strings, stype):
+ ''' Actual building of the shader '''
+
+ count = len(strings)
+ # if we have no source code, ignore this shader
+ if count < 1:
+ return
+
+ # create the shader handle
+ shader = gl.glCreateShader(stype)
+
+ # Upload shader code
+ gl.glShaderSource(shader, strings)
+
+ # compile the shader
+ gl.glCompileShader(shader)
+
+ # retrieve the compile status
+ status = gl.glGetShaderiv(shader, gl.GL_COMPILE_STATUS)
+
+ # if compilation failed, print the log
+ if not status:
+ # display the log
+ print gl.glGetShaderInfoLog(shader)
+ else:
+ # all is well, so attach the shader to the program
+ gl.glAttachShader(self.handle, shader)
+
+ def _link(self):
+ ''' Link the program '''
+
+ gl.glLinkProgram(self.handle)
+ # retrieve the link status
+ temp = ctypes.c_int(0)
+ gl.glGetProgramiv(self.handle, gl.GL_LINK_STATUS, ctypes.byref(temp))
+
+ # if linking failed, print the log
+ if not temp:
+ # retrieve the log length
+ gl.glGetProgramiv(self.handle,
+ gl.GL_INFO_LOG_LENGTH, ctypes.byref(temp))
+ # create a buffer for the log
+ #buffer = ctypes.create_string_buffer(temp.value)
+ # retrieve the log text
+ log = gl.glGetProgramInfoLog(self.handle) #, temp, None, buffer)
+ # print the log to the console
+ print log
+ else:
+ # all is well, so we are linked
+ self.linked = True
+
+ def bind(self):
+ ''' Bind the program, i.e. use it. '''
+ gl.glUseProgram(self.handle)
+
+ def unbind(self):
+ ''' Unbind whatever program is currently bound - not necessarily this
+ program, so this should probably be a class method instead. '''
+ gl.glUseProgram(0)
+
+ def uniformf(self, name, *vals):
+ ''' Uploads float uniform(s), program must be currently bound. '''
+
+ loc = self.uniforms.get(name,
+ gl.glGetUniformLocation(self.handle,name))
+ self.uniforms[name] = loc
+
+ # Check there are 1-4 values
+ if len(vals) in range(1, 5):
+ # Select the correct function
+ { 1 : gl.glUniform1f,
+ 2 : gl.glUniform2f,
+ 3 : gl.glUniform3f,
+ 4 : gl.glUniform4f
+ # Retrieve uniform location, and set it
+ }[len(vals)](loc, *vals)
+
+ def uniformi(self, name, *vals):
+ ''' Upload integer uniform(s), program must be currently bound. '''
+
+ loc = self.uniforms.get(name,
+ gl.glGetUniformLocation(self.handle,name))
+ self.uniforms[name] = loc
+
+ # Checks there are 1-4 values
+ if len(vals) in range(1, 5):
+ # Selects the correct function
+ { 1 : gl.glUniform1i,
+ 2 : gl.glUniform2i,
+ 3 : gl.glUniform3i,
+ 4 : gl.glUniform4i
+ # Retrieves uniform location, and set it
+ }[len(vals)](loc, *vals)
+
+
+ def uniform_matrixf(self, name, mat):
+ ''' Upload uniform matrix, program must be currently bound. '''
+
+ loc = self.uniforms.get(name,
+ gl.glGetUniformLocation(self.handle,name))
+ self.uniforms[name] = loc
+
+ # Upload the 4x4 floating point matrix
+ gl.glUniformMatrix4fv(loc, 1, False, (ctypes.c_float * 16)(*mat))
diff --git a/third_party/freetype-py/examples/subpixel-positioning.py b/third_party/freetype-py/examples/subpixel-positioning.py
new file mode 100644
index 0000000..6483517
--- /dev/null
+++ b/third_party/freetype-py/examples/subpixel-positioning.py
@@ -0,0 +1,236 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+'''
+Subpixel rendering AND positioning using OpenGL and shaders.
+
+'''
+import numpy as np
+import OpenGL.GL as gl
+import OpenGL.GLUT as glut
+from texture_font import TextureFont, TextureAtlas
+from shader import Shader
+
+
+vert='''
+uniform sampler2D texture;
+uniform vec2 pixel;
+attribute float modulo;
+varying float m;
+void main() {
+ gl_FrontColor = gl_Color;
+ gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;
+ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+ m = modulo;
+}
+'''
+
+frag='''
+uniform sampler2D texture;
+uniform vec2 pixel;
+varying float m;
+void main() {
+ float gamma = 1.0;
+
+ vec2 uv = gl_TexCoord[0].xy;
+ vec4 current = texture2D(texture, uv);
+ vec4 previous= texture2D(texture, uv+vec2(-1,0)*pixel);
+
+ current = pow(current, vec4(1.0/gamma));
+ previous = pow(previous, vec4(1.0/gamma));
+
+ float r = current.r;
+ float g = current.g;
+ float b = current.b;
+ float a = current.a;
+ if( m <= 0.333 )
+ {
+ float z = m/0.333;
+ r = mix(current.r, previous.b, z);
+ g = mix(current.g, current.r, z);
+ b = mix(current.b, current.g, z);
+ }
+ else if( m <= 0.666 )
+ {
+ float z = (m-0.33)/0.333;
+ r = mix(previous.b, previous.g, z);
+ g = mix(current.r, previous.b, z);
+ b = mix(current.g, current.r, z);
+ }
+ else if( m < 1.0 )
+ {
+ float z = (m-0.66)/0.334;
+ r = mix(previous.g, previous.r, z);
+ g = mix(previous.b, previous.g, z);
+ b = mix(current.r, previous.b, z);
+ }
+
+ float t = max(max(r,g),b);
+ vec4 color = vec4(0.,0.,0., (r+g+b)/2.);
+ color = t*color + (1.-t)*vec4(r,g,b, min(min(r,g),b));
+ gl_FragColor = vec4( color.rgb, color.a);
+}
+'''
+
+
+
+
+
+class Label:
+ def __init__(self, text, font, color=(1.0, 1.0, 1.0, 0.0), x=0, y=0,
+ width=None, height=None, anchor_x='left', anchor_y='baseline'):
+ self.text = text
+ self.vertices = np.zeros((len(text)*4,3), dtype=np.float32)
+ self.indices = np.zeros((len(text)*6, ), dtype=np.uint)
+ self.colors = np.zeros((len(text)*4,4), dtype=np.float32)
+ self.texcoords= np.zeros((len(text)*4,2), dtype=np.float32)
+ self.attrib = np.zeros((len(text)*4,1), dtype=np.float32)
+ pen = [x,y]
+ prev = None
+
+ for i,charcode in enumerate(text):
+ glyph = font[charcode]
+ kerning = glyph.get_kerning(prev)
+ x0 = pen[0] + glyph.offset[0] + kerning
+ dx = x0-int(x0)
+ x0 = int(x0)
+ y0 = pen[1] + glyph.offset[1]
+ x1 = x0 + glyph.size[0]
+ y1 = y0 - glyph.size[1]
+ u0 = glyph.texcoords[0]
+ v0 = glyph.texcoords[1]
+ u1 = glyph.texcoords[2]
+ v1 = glyph.texcoords[3]
+
+ index = i*4
+ indices = [index, index+1, index+2, index, index+2, index+3]
+ vertices = [[x0,y0,1],[x0,y1,1],[x1,y1,1], [x1,y0,1]]
+ texcoords = [[u0,v0],[u0,v1],[u1,v1], [u1,v0]]
+ colors = [color,]*4
+
+ self.vertices[i*4:i*4+4] = vertices
+ self.indices[i*6:i*6+6] = indices
+ self.texcoords[i*4:i*4+4] = texcoords
+ self.colors[i*4:i*4+4] = colors
+ self.attrib[i*4:i*4+4] = dx
+ pen[0] = pen[0]+glyph.advance[0]/64.0 + kerning
+ pen[1] = pen[1]+glyph.advance[1]/64.0
+ prev = charcode
+
+ width = pen[0]-glyph.advance[0]/64.0+glyph.size[0]
+
+ if anchor_y == 'top':
+ dy = -round(font.ascender)
+ elif anchor_y == 'center':
+ dy = +round(-font.height/2-font.descender)
+ elif anchor_y == 'bottom':
+ dy = -round(font.descender)
+ else:
+ dy = 0
+
+ if anchor_x == 'right':
+ dx = -width/1.0
+ elif anchor_x == 'center':
+ dx = -width/2.0
+ else:
+ dx = 0
+ self.vertices += (round(dx), round(dy), 0)
+
+
+ def draw(self):
+ gl.glEnable( gl.GL_TEXTURE_2D )
+ gl.glDisable( gl.GL_DEPTH_TEST )
+
+ gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
+ gl.glEnableClientState(gl.GL_COLOR_ARRAY)
+ gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY)
+ gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
+
+ gl.glVertexPointer(3, gl.GL_FLOAT, 0, self.vertices)
+ gl.glColorPointer(4, gl.GL_FLOAT, 0, self.colors)
+ gl.glTexCoordPointer(2, gl.GL_FLOAT, 0, self.texcoords)
+
+ r,g,b = 0,0,0
+ gl.glColor( 1, 1, 1, 1 )
+ gl.glEnable( gl.GL_BLEND )
+ #gl.glBlendFunc( gl.GL_CONSTANT_COLOR_EXT, gl.GL_ONE_MINUS_SRC_COLOR )
+ #gl.glBlendColor(r,g,b,1)
+ gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA )
+ gl.glBlendColor( 1, 1, 1, 1 )
+
+ gl.glEnableVertexAttribArray( 1 );
+ gl.glVertexAttribPointer( 1, 1, gl.GL_FLOAT, gl.GL_FALSE, 0, self.attrib)
+ shader.bind()
+ shader.uniformi('texture', 0)
+ shader.uniformf('pixel', 1.0/512, 1.0/512)
+ gl.glDrawElements(gl.GL_TRIANGLES, len(self.indices),
+ gl.GL_UNSIGNED_INT, self.indices)
+ shader.unbind()
+ gl.glDisableVertexAttribArray( 1 );
+ gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
+ gl.glDisableClientState(gl.GL_COLOR_ARRAY)
+ gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY)
+ gl.glDisable( gl.GL_TEXTURE_2D )
+ gl.glDisable( gl.GL_BLEND )
+
+
+
+
+if __name__ == '__main__':
+ import sys
+
+ atlas = TextureAtlas(512,512,3)
+
+ def on_display( ):
+ #gl.glClearColor(0,0,0,1)
+ gl.glClearColor(1,1,1,1)
+ gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
+ gl.glBindTexture( gl.GL_TEXTURE_2D, atlas.texid )
+ for label in labels:
+ label.draw()
+
+ gl.glColor(0,0,0,1)
+ gl.glBegin(gl.GL_LINES)
+ gl.glVertex2i(15,0)
+ gl.glVertex2i(15, 330)
+ gl.glVertex2i(225, 0)
+ gl.glVertex2i(225, 330)
+ gl.glEnd()
+ glut.glutSwapBuffers( )
+
+ def on_reshape( width, height ):
+ gl.glViewport( 0, 0, width, height )
+ gl.glMatrixMode( gl.GL_PROJECTION )
+ gl.glLoadIdentity( )
+ gl.glOrtho( 0, width, 0, height, -1, 1 )
+ gl.glMatrixMode( gl.GL_MODELVIEW )
+ gl.glLoadIdentity( )
+
+ def on_keyboard( key, x, y ):
+ if key == '\033':
+ sys.exit( )
+
+ glut.glutInit( sys.argv )
+ glut.glutInitDisplayMode( glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH )
+ glut.glutCreateWindow( "Freetype OpenGL" )
+ glut.glutReshapeWindow( 240, 330 )
+ glut.glutDisplayFunc( on_display )
+ glut.glutReshapeFunc( on_reshape )
+ glut.glutKeyboardFunc( on_keyboard )
+
+ font = TextureFont(atlas, './Arial.ttf', 9)
+ text = "|... A Quick Brown Fox Jumps Over The Lazy Dog"
+ labels = []
+ x,y = 20,310
+ for i in range(30):
+ labels.append(Label(text=text, font=font, x=x, y=y))
+ x += 0.1000000000001
+ y -= 10
+ atlas.upload()
+ shader = Shader(vert,frag)
+ glut.glutMainLoop( )
diff --git a/third_party/freetype-py/examples/texture_font.py b/third_party/freetype-py/examples/texture_font.py
new file mode 100644
index 0000000..8abdd2e
--- /dev/null
+++ b/third_party/freetype-py/examples/texture_font.py
@@ -0,0 +1,421 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+'''
+Texture font class
+
+'''
+import sys
+import math
+import numpy as np
+import OpenGL.GL as gl
+from freetype import *
+
+
+class TextureAtlas:
+ '''
+ Group multiple small data regions into a larger texture.
+
+ The algorithm is based on the article by Jukka Jylänki : "A Thousand Ways
+ to Pack the Bin - A Practical Approach to Two-Dimensional Rectangle Bin
+ Packing", February 27, 2010. More precisely, this is an implementation of
+ the Skyline Bottom-Left algorithm based on C++ sources provided by Jukka
+ Jylänki at: http://clb.demon.fi/files/RectangleBinPack/
+
+ Example usage:
+ --------------
+
+ atlas = TextureAtlas(512,512,3)
+ region = atlas.get_region(20,20)
+ ...
+ atlas.set_region(region, data)
+ '''
+
+ def __init__(self, width=1024, height=1024, depth=1):
+ '''
+ Initialize a new atlas of given size.
+
+ Parameters
+ ----------
+
+ width : int
+ Width of the underlying texture
+
+ height : int
+ Height of the underlying texture
+
+ depth : 1 or 3
+ Depth of the underlying texture
+ '''
+ self.width = int(math.pow(2, int(math.log(width, 2) + 0.5)))
+ self.height = int(math.pow(2, int(math.log(height, 2) + 0.5)))
+ self.depth = depth
+ self.nodes = [ (0,0,self.width), ]
+ self.data = np.zeros((self.height, self.width, self.depth),
+ dtype=np.ubyte)
+ self.texid = 0
+ self.used = 0
+
+
+
+ def upload(self):
+ '''
+ Upload atlas data into video memory.
+ '''
+
+ if not self.texid:
+ self.texid = gl.glGenTextures(1)
+
+ gl.glBindTexture( gl.GL_TEXTURE_2D, self.texid )
+ gl.glTexParameteri( gl.GL_TEXTURE_2D,
+ gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP )
+ gl.glTexParameteri( gl.GL_TEXTURE_2D,
+ gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP )
+ gl.glTexParameteri( gl.GL_TEXTURE_2D,
+ gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR )
+ gl.glTexParameteri( gl.GL_TEXTURE_2D,
+ gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR )
+ if self.depth == 1:
+ gl.glTexImage2D( gl.GL_TEXTURE_2D, 0, gl.GL_ALPHA,
+ self.width, self.height, 0,
+ gl.GL_ALPHA, gl.GL_UNSIGNED_BYTE, self.data )
+ else:
+ gl.glTexImage2D( gl.GL_TEXTURE_2D, 0, gl.GL_RGB,
+ self.width, self.height, 0,
+ gl.GL_RGB, gl.GL_UNSIGNED_BYTE, self.data )
+
+
+
+ def set_region(self, region, data):
+ '''
+ Set a given region width provided data.
+
+ Parameters
+ ----------
+
+ region : (int,int,int,int)
+ an allocated region (x,y,width,height)
+
+ data : numpy array
+ data to be copied into given region
+ '''
+
+ x, y, width, height = region
+ self.data[y:y+height,x:x+width, :] = data
+
+
+
+ def get_region(self, width, height):
+ '''
+ Get a free region of given size and allocate it
+
+ Parameters
+ ----------
+
+ width : int
+ Width of region to allocate
+
+ height : int
+ Height of region to allocate
+
+ Return
+ ------
+ A newly allocated region as (x,y,width,height) or (-1,-1,0,0)
+ '''
+
+ best_height = sys.maxint
+ best_index = -1
+ best_width = sys.maxint
+ region = 0, 0, width, height
+
+ for i in range(len(self.nodes)):
+ y = self.fit(i, width, height)
+ if y >= 0:
+ node = self.nodes[i]
+ if (y+height < best_height or
+ (y+height == best_height and node[2] < best_width)):
+ best_height = y+height
+ best_index = i
+ best_width = node[2]
+ region = node[0], y, width, height
+
+ if best_index == -1:
+ return -1,-1,0,0
+
+ node = region[0], region[1]+height, width
+ self.nodes.insert(best_index, node)
+
+ i = best_index+1
+ while i < len(self.nodes):
+ node = self.nodes[i]
+ prev_node = self.nodes[i-1]
+ if node[0] < prev_node[0]+prev_node[2]:
+ shrink = prev_node[0]+prev_node[2] - node[0]
+ x,y,w = self.nodes[i]
+ self.nodes[i] = x+shrink, y, w-shrink
+ if self.nodes[i][2] <= 0:
+ del self.nodes[i]
+ i -= 1
+ else:
+ break
+ else:
+ break
+ i += 1
+
+ self.merge()
+ self.used += width*height
+ return region
+
+
+
+ def fit(self, index, width, height):
+ '''
+ Test if region (width,height) fit into self.nodes[index]
+
+ Parameters
+ ----------
+
+ index : int
+ Index of the internal node to be tested
+
+ width : int
+ Width or the region to be tested
+
+ height : int
+ Height or the region to be tested
+
+ '''
+
+ node = self.nodes[index]
+ x,y = node[0], node[1]
+ width_left = width
+
+ if x+width > self.width:
+ return -1
+
+ i = index
+ while width_left > 0:
+ node = self.nodes[i]
+ y = max(y, node[1])
+ if y+height > self.height:
+ return -1
+ width_left -= node[2]
+ i += 1
+ return y
+
+
+
+ def merge(self):
+ '''
+ Merge nodes
+ '''
+
+ i = 0
+ while i < len(self.nodes)-1:
+ node = self.nodes[i]
+ next_node = self.nodes[i+1]
+ if node[1] == next_node[1]:
+ self.nodes[i] = node[0], node[1], node[2]+next_node[2]
+ del self.nodes[i+1]
+ else:
+ i += 1
+
+
+class TextureFont:
+ '''
+ A texture font gathers a set of glyph relatively to a given font filename
+ and size.
+ '''
+
+ def __init__(self, atlas, filename, size):
+ '''
+ Initialize font
+
+ Parameters:
+ -----------
+
+ atlas: TextureAtlas
+ Texture atlas where glyph texture will be stored
+
+ filename: str
+ Font filename
+
+ size : float
+ Font size
+ '''
+ self.atlas = atlas
+ self.filename = filename
+ self.size = size
+ self.glyphs = {}
+ face = Face( self.filename )
+ face.set_char_size( int(self.size*64))
+ self._dirty = False
+ metrics = face.size
+ self.ascender = metrics.ascender/64.0
+ self.descender = metrics.descender/64.0
+ self.height = metrics.height/64.0
+ self.linegap = self.height - self.ascender + self.descender
+ self.depth = atlas.depth
+ set_lcd_filter(FT_LCD_FILTER_LIGHT)
+
+
+ def __getitem__(self, charcode):
+ '''
+ x.__getitem__(y) <==> x[y]
+ '''
+ if charcode not in self.glyphs.keys():
+ self.load('%c' % charcode)
+ return self.glyphs[charcode]
+
+
+
+ def get_texid(self):
+ '''
+ Get underlying texture identity .
+ '''
+
+ if self._dirty:
+ self.atlas.upload()
+ self._dirty = False
+ return self.atlas.texid
+
+ texid = property(get_texid,
+ doc='''Underlying texture identity.''')
+
+
+
+ def load(self, charcodes = ''):
+ '''
+ Build glyphs corresponding to individual characters in charcodes.
+
+ Parameters:
+ -----------
+
+ charcodes: [str | unicode]
+ Set of characters to be represented
+ '''
+ face = Face( self.filename )
+ pen = Vector(0,0)
+ hres = 16*72
+ hscale = 1.0/16
+
+ for charcode in charcodes:
+ face.set_char_size( int(self.size * 64), 0, hres, 72 )
+ matrix = Matrix( int((hscale) * 0x10000L), int((0.0) * 0x10000L),
+ int((0.0) * 0x10000L), int((1.0) * 0x10000L) )
+ face.set_transform( matrix, pen )
+ if charcode in self.glyphs.keys():
+ continue
+
+ self.dirty = True
+ flags = FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT
+ flags |= FT_LOAD_TARGET_LCD
+
+ face.load_char( charcode, flags )
+ bitmap = face.glyph.bitmap
+ left = face.glyph.bitmap_left
+ top = face.glyph.bitmap_top
+ width = face.glyph.bitmap.width
+ rows = face.glyph.bitmap.rows
+ pitch = face.glyph.bitmap.pitch
+
+ x,y,w,h = self.atlas.get_region(width/self.depth+2, rows+2)
+ if x < 0:
+ print 'Missed !'
+ continue
+ x,y = x+1, y+1
+ w,h = w-2, h-2
+ data = []
+ for i in range(rows):
+ data.extend(bitmap.buffer[i*pitch:i*pitch+width])
+ data = np.array(data,dtype=np.ubyte).reshape(h,w,3)
+ gamma = 1.5
+ Z = ((data/255.0)**(gamma))
+ data = (Z*255).astype(np.ubyte)
+ self.atlas.set_region((x,y,w,h), data)
+
+ # Build glyph
+ size = w,h
+ offset = left, top
+ advance= face.glyph.advance.x, face.glyph.advance.y
+
+ u0 = (x + 0.0)/float(self.atlas.width)
+ v0 = (y + 0.0)/float(self.atlas.height)
+ u1 = (x + w - 0.0)/float(self.atlas.width)
+ v1 = (y + h - 0.0)/float(self.atlas.height)
+ texcoords = (u0,v0,u1,v1)
+ glyph = TextureGlyph(charcode, size, offset, advance, texcoords)
+ self.glyphs[charcode] = glyph
+
+ # Generate kerning
+ for g in self.glyphs.values():
+ # 64 * 64 because of 26.6 encoding AND the transform matrix used
+ # in texture_font_load_face (hres = 64)
+ kerning = face.get_kerning(g.charcode, charcode, mode=FT_KERNING_UNFITTED)
+ if kerning.x != 0:
+ glyph.kerning[g.charcode] = kerning.x/(64.0*64.0)
+ kerning = face.get_kerning(charcode, g.charcode, mode=FT_KERNING_UNFITTED)
+ if kerning.x != 0:
+ g.kerning[charcode] = kerning.x/(64.0*64.0)
+
+ # High resolution advance.x calculation
+ # gindex = face.get_char_index( charcode )
+ # a = face.get_advance(gindex, FT_LOAD_RENDER | FT_LOAD_TARGET_LCD)/(64*72)
+ # glyph.advance = a, glyph.advance[1]
+
+
+class TextureGlyph:
+ '''
+ A texture glyph gathers information relative to the size/offset/advance and
+ texture coordinates of a single character. It is generally built
+ automatically by a TextureFont.
+ '''
+
+ def __init__(self, charcode, size, offset, advance, texcoords):
+ '''
+ Build a new texture glyph
+
+ Parameter:
+ ----------
+
+ charcode : char
+ Represented character
+
+ size: tuple of 2 ints
+ Glyph size in pixels
+
+ offset: tuple of 2 floats
+ Glyph offset relatively to anchor point
+
+ advance: tuple of 2 floats
+ Glyph advance
+
+ texcoords: tuple of 4 floats
+ Texture coordinates of bottom-left and top-right corner
+ '''
+ self.charcode = charcode
+ self.size = size
+ self.offset = offset
+ self.advance = advance
+ self.texcoords = texcoords
+ self.kerning = {}
+
+
+ def get_kerning(self, charcode):
+ ''' Get kerning information
+
+ Parameters:
+ -----------
+
+ charcode: char
+ Character preceding this glyph
+ '''
+ if charcode in self.kerning.keys():
+ return self.kerning[charcode]
+ else:
+ return 0
diff --git a/third_party/freetype-py/examples/wordle.py b/third_party/freetype-py/examples/wordle.py
new file mode 100644
index 0000000..249f86d
--- /dev/null
+++ b/third_party/freetype-py/examples/wordle.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+#
+# FreeType high-level python API - Copyright 2011 Nicolas P. Rougier
+# Distributed under the terms of the new BSD license.
+#
+# -----------------------------------------------------------------------------
+import math
+import numpy as np
+from freetype import *
+import matplotlib.pyplot as plt
+
+
+def make_label(text, filename, size=12, angle=0):
+ '''
+ Parameters:
+ -----------
+ text : string
+ Text to be displayed
+ filename : string
+ Path to a font
+ size : int
+ Font size in 1/64th points
+ angle : float
+ Text angle in degrees
+ '''
+ face = Face(filename)
+ face.set_char_size( size*64 )
+ angle = (angle/180.0)*math.pi
+ matrix = FT_Matrix( (int)( math.cos( angle ) * 0x10000L ),
+ (int)(-math.sin( angle ) * 0x10000L ),
+ (int)( math.sin( angle ) * 0x10000L ),
+ (int)( math.cos( angle ) * 0x10000L ))
+ flags = FT_LOAD_RENDER
+ pen = FT_Vector(0,0)
+ FT_Set_Transform( face._FT_Face, byref(matrix), byref(pen) )
+ previous = 0
+ xmin, xmax = 0, 0
+ ymin, ymax = 0, 0
+ for c in text:
+ face.load_char(c, flags)
+ kerning = face.get_kerning(previous, c)
+ previous = c
+ bitmap = face.glyph.bitmap
+ pitch = face.glyph.bitmap.pitch
+ width = face.glyph.bitmap.width
+ rows = face.glyph.bitmap.rows
+ top = face.glyph.bitmap_top
+ left = face.glyph.bitmap_left
+ pen.x += kerning.x
+ x0 = (pen.x >> 6) + left
+ x1 = x0 + width
+ y0 = (pen.y >> 6) - (rows - top)
+ y1 = y0 + rows
+ xmin, xmax = min(xmin, x0), max(xmax, x1)
+ ymin, ymax = min(ymin, y0), max(ymax, y1)
+ pen.x += face.glyph.advance.x
+ pen.y += face.glyph.advance.y
+
+ L = np.zeros((ymax-ymin, xmax-xmin),dtype=np.ubyte)
+ previous = 0
+ pen.x, pen.y = 0, 0
+ for c in text:
+ face.load_char(c, flags)
+ kerning = face.get_kerning(previous, c)
+ previous = c
+ bitmap = face.glyph.bitmap
+ pitch = face.glyph.bitmap.pitch
+ width = face.glyph.bitmap.width
+ rows = face.glyph.bitmap.rows
+ top = face.glyph.bitmap_top
+ left = face.glyph.bitmap_left
+ pen.x += kerning.x
+ x = (pen.x >> 6) - xmin + left
+ y = (pen.y >> 6) - ymin - (rows - top)
+ data = []
+ for j in range(rows):
+ data.extend(bitmap.buffer[j*pitch:j*pitch+width])
+ if len(data):
+ Z = np.array(data,dtype=np.ubyte).reshape(rows, width)
+ L[y:y+rows,x:x+width] |= Z[::-1,::1]
+ pen.x += face.glyph.advance.x
+ pen.y += face.glyph.advance.y
+
+ return L
+
+
+if __name__ == '__main__':
+ from PIL import Image
+
+ n_words = 100
+ H, W, dpi = 600, 800, 72.0
+ I = np.zeros((H, W, 3), dtype=np.ubyte)
+ S = np.random.normal(0,1,n_words)
+ S = (S-S.min())/(S.max()-S.min())
+ S = np.sort(1-np.sqrt(S))[::-1]
+ sizes = (12 + S*48).astype(int).tolist()
+
+ def spiral():
+ eccentricity = 1.5
+ radius = 8
+ step = 0.1
+ t = 0
+ while True:
+ t += step
+ yield eccentricity*radius*t*math.cos(t), radius*t*math.sin(t)
+
+ fails = 0
+ for size in sizes:
+ angle = np.random.randint(-25,25)
+ L = make_label('Hello', './Vera.ttf', size, angle=angle)
+ h,w = L.shape
+ if h < H and w < W:
+ x0 = W//2 + (np.random.uniform()-.1)*50
+ y0 = H//2 + (np.random.uniform()-.1)*50
+ for dx,dy in spiral():
+ c = .25+.75*np.random.random()
+ x = int(x0+dx)
+ y = int(y0+dy)
+ if x <= w//2 or y <= h//2 or x >= (W-w//2) or y >= (H-h//2):
+ fails += 1
+ break
+ if (I[y-h//2:y-h//2+h, x-w//2:x-w//2+w,0] * L).sum() == 0:
+ I[y-h//2:y-h//2+h, x-w//2:x-w//2+w,0] |= (c * L).astype(int)
+ I[y-h//2:y-h//2+h, x-w//2:x-w//2+w,1] |= (c * L).astype(int)
+ I[y-h//2:y-h//2+h, x-w//2:x-w//2+w,2] |= (c * L).astype(int)
+ break
+
+ print "Number of fails:", fails
+ fig = plt.figure(figsize=(W/dpi,H/dpi), dpi=dpi)
+ ax = fig.add_axes([0,0,1,1], frameon=False)
+ ax.imshow(I, interpolation='nearest', cmap=plt.cm.gray, origin='upper')
+ #plt.axis('off')
+ plt.show()
+ I = Image.fromarray(I[::-1,::1,::1], mode='RGB')
+ I.save('wordle.png')