def createFontAtlas(self): if self.atlas: self.atlas.free() self.atlas=None self.charcode2glyph={} self.charcode2unichr={} self.max_ascender = None self.max_descender = None self.max_tile_width = None self.max_tile_height = None self.max_bitmap_size = None self.total_bitmap_area=0 # load font glyphs and calculate max. char size. # This is used when the altas is created to properly size the tex. # i.e. max glyph size * num glyphs # max_w,max_h=0,0 max_ascender, max_descender, max_tile_width = 0, 0, 0 face=self._face face.set_char_size(height=self.size*64,vres=self.dpi) # Create texAtlas for glyph set. x_ppem=face.size.x_ppem y_ppem=face.size.x_ppem units_ppem=self.font_info.units_per_em est_max_width=(face.bbox.xMax-face.bbox.xMin)/float(units_ppem)*x_ppem est_max_height=face.size.ascender/float(units_ppem)*y_ppem target_atlas_area=int(est_max_width*est_max_height)*face.num_glyphs # make sure it is big enough. ;) # height is trimmed before sending to video ram anyhow. target_atlas_area=target_atlas_area*3.0 pow2_area=nextPow2(target_atlas_area) atlas_width=2048 atlas_height=pow2_area/atlas_width self.atlas=TextureAtlas(atlas_width,atlas_height) charcode, gindex=face.get_first_char() while gindex: uchar = unichr(charcode) if ud.category(uchar) not in (u'Zl',u'Zp',u'Cc',u'Cf',u'Cs',u'Co',u'Cn'): self.charcode2unichr[charcode]=uchar face.load_char(uchar, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT ) bitmap = face.glyph.bitmap self.total_bitmap_area+=bitmap.width*bitmap.rows max_ascender = max( max_ascender, face.glyph.bitmap_top) max_descender = max( max_descender, bitmap.rows - face.glyph.bitmap_top ) max_tile_width = max( max_tile_width,bitmap.width) max_w=max(bitmap.width,max_w) max_h=max(bitmap.rows,max_h) x,y,w,h = self.atlas.get_region(bitmap.width+2, bitmap.rows+2) if x < 0: raise Exception("MonospaceFontAtlas.get_region failed for: {0}, requested area: {1}. Atlas Full!".format(charcode,(bitmap.width+2, bitmap.rows+2))) x,y = x+1, y+1 w,h = w-2, h-2 data = np.array(bitmap._FT_Bitmap.buffer[:(bitmap.rows*bitmap.width)],dtype=np.ubyte).reshape(h,w,1) self.atlas.set_region((x,y,w,h), data) self.charcode2glyph[charcode]=dict( offset=(face.glyph.bitmap_left, face.glyph.bitmap_top), size=(w,h), atlas_coords=(x,y,w,h), texcoords = [x, y, x + w, y + h], index=gindex, unichar=uchar ) charcode, gindex = face.get_next_char(charcode, gindex) self.max_ascender = max_ascender self.max_descender = max_descender self.max_tile_width = max_tile_width self.max_tile_height = max_ascender+max_descender self.max_bitmap_size=max_w,max_h # resize atlas height=nextPow2(self.atlas.max_y+1) self.atlas.resize(height) self.atlas.upload() self.createDisplayLists() self._face=None
class MonospaceFontAtlas(object): def __init__(self,font_info,size,dpi): self.font_info=font_info self.size=size self.dpi=dpi self.id=self.getIdFromArgs(font_info,size,dpi) self._face=Face(font_info.path) self._face.set_char_size(height=self.size*64,vres=self.dpi) self.charcode2glyph=None self.charcode2unichr=None self.charcode2displaylist=None self.max_ascender = None self.max_descender = None self.max_tile_width = None self.max_tile_height = None self.max_bitmap_size = None self.total_bitmap_area=0 self.atlas=None def getID(self): return self.id @staticmethod def getIdFromArgs(font_info,size,dpi): return "%s_%d_%d"%(font_info.getID(),size,dpi) def createFontAtlas(self): if self.atlas: self.atlas.free() self.atlas=None self.charcode2glyph={} self.charcode2unichr={} self.max_ascender = None self.max_descender = None self.max_tile_width = None self.max_tile_height = None self.max_bitmap_size = None self.total_bitmap_area=0 # load font glyphs and calculate max. char size. # This is used when the altas is created to properly size the tex. # i.e. max glyph size * num glyphs # max_w,max_h=0,0 max_ascender, max_descender, max_tile_width = 0, 0, 0 face=self._face face.set_char_size(height=self.size*64,vres=self.dpi) # Create texAtlas for glyph set. x_ppem=face.size.x_ppem y_ppem=face.size.x_ppem units_ppem=self.font_info.units_per_em est_max_width=(face.bbox.xMax-face.bbox.xMin)/float(units_ppem)*x_ppem est_max_height=face.size.ascender/float(units_ppem)*y_ppem target_atlas_area=int(est_max_width*est_max_height)*face.num_glyphs # make sure it is big enough. ;) # height is trimmed before sending to video ram anyhow. target_atlas_area=target_atlas_area*3.0 pow2_area=nextPow2(target_atlas_area) atlas_width=2048 atlas_height=pow2_area/atlas_width self.atlas=TextureAtlas(atlas_width,atlas_height) charcode, gindex=face.get_first_char() while gindex: uchar = unichr(charcode) if ud.category(uchar) not in (u'Zl',u'Zp',u'Cc',u'Cf',u'Cs',u'Co',u'Cn'): self.charcode2unichr[charcode]=uchar face.load_char(uchar, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT ) bitmap = face.glyph.bitmap self.total_bitmap_area+=bitmap.width*bitmap.rows max_ascender = max( max_ascender, face.glyph.bitmap_top) max_descender = max( max_descender, bitmap.rows - face.glyph.bitmap_top ) max_tile_width = max( max_tile_width,bitmap.width) max_w=max(bitmap.width,max_w) max_h=max(bitmap.rows,max_h) x,y,w,h = self.atlas.get_region(bitmap.width+2, bitmap.rows+2) if x < 0: raise Exception("MonospaceFontAtlas.get_region failed for: {0}, requested area: {1}. Atlas Full!".format(charcode,(bitmap.width+2, bitmap.rows+2))) x,y = x+1, y+1 w,h = w-2, h-2 data = np.array(bitmap._FT_Bitmap.buffer[:(bitmap.rows*bitmap.width)],dtype=np.ubyte).reshape(h,w,1) self.atlas.set_region((x,y,w,h), data) self.charcode2glyph[charcode]=dict( offset=(face.glyph.bitmap_left, face.glyph.bitmap_top), size=(w,h), atlas_coords=(x,y,w,h), texcoords = [x, y, x + w, y + h], index=gindex, unichar=uchar ) charcode, gindex = face.get_next_char(charcode, gindex) self.max_ascender = max_ascender self.max_descender = max_descender self.max_tile_width = max_tile_width self.max_tile_height = max_ascender+max_descender self.max_bitmap_size=max_w,max_h # resize atlas height=nextPow2(self.atlas.max_y+1) self.atlas.resize(height) self.atlas.upload() self.createDisplayLists() self._face=None #print 'w_max_glyth info:',w_max_glyph #print 'h_max_glyth info:',h_max_glyph def createDisplayLists(self): glyph_count=len(self.charcode2unichr) max_tile_width,max_tile_height=self.max_tile_width,self.max_tile_height display_lists_for_chars={} base = glGenLists(glyph_count) for i,(charcode,glyph) in enumerate( self.charcode2glyph.iteritems()): dl_index=base+i uchar=self.charcode2unichr[charcode] # update tex coords to reflect earlier resize of atlas height. gx1,gy1,gx2,gy2=glyph['texcoords'] gx1=gx1/float(self.atlas.width) gy1=gy1/float(self.atlas.height) gx2=gx2/float(self.atlas.width) gy2=gy2/float(self.atlas.height) glyph['texcoords'] =[gx1,gy1,gx2,gy2] glNewList(dl_index, GL_COMPILE) if uchar not in [u'\t',u'\n']: glBegin( GL_QUADS ) x1 = glyph['offset'][0] x2 = x1+glyph['size'][0] y1=(self.max_ascender-glyph['offset'][1]) y2=y1+glyph['size'][1] glTexCoord2f( gx1, gy2 ), glVertex2f( x1,-y2 ) glTexCoord2f( gx1, gy1 ), glVertex2f( x1,-y1 ) glTexCoord2f( gx2, gy1 ), glVertex2f( x2,-y1 ) glTexCoord2f( gx2, gy2 ), glVertex2f( x2,-y2 ) glEnd( ) glTranslatef( max_tile_width,0,0) glEndList( ) display_lists_for_chars[charcode]=dl_index self.charcode2displaylist=display_lists_for_chars def saveGlyphBitmap(self,file_name=None): if file_name is None: import os #print 'CWD:',os.getcwd() file_name=os.path.join(os.getcwd(),self.getID().lower().replace(u' ',u'_')+'.png') from scipy import misc if self.atlas is None: self.loadAtlas() if self.atlas.depth==1: misc.imsave(file_name, self.atlas.data.reshape(self.atlas.data.shape[:2])) else: misc.imsave(file_name, self.atlas.data) def __del__(self): self._face=None if self.atlas.texid: glDeleteTextures(1, self.atlas.texid) self.atlas.texid=None self.atlas=None if self.charcode2displaylist: for dl in self.charcode2displaylist.values(): glDeleteLists(dl, 1) self.charcode2displaylist.clear() self.charcode2displaylist=None if self.charcode2glyph: self.charcode2glyph.clear() self.charcode2glyph=None if self.charcode2unichr: self.charcode2unichr.clear() self.charcode2unichr=None
class MonospaceFontAtlas(object): def __init__(self, font_info, size, dpi): self.font_info = font_info self.size = size self.dpi = dpi self.id = self.getIdFromArgs(font_info, size, dpi) self._face = Face(font_info.path) self._face.set_char_size(height=self.size * 64, vres=self.dpi) self.charcode2glyph = None self.charcode2unichr = None self.charcode2displaylist = None self.max_ascender = None self.max_descender = None self.max_tile_width = None self.max_tile_height = None self.max_bitmap_size = None self.total_bitmap_area = 0 self.atlas = None def getID(self): return self.id @staticmethod def getIdFromArgs(font_info, size, dpi): return "%s_%d_%d" % (font_info.getID(), size, dpi) def createFontAtlas(self): if self.atlas: self.atlas.free() self.atlas = None self.charcode2glyph = {} self.charcode2unichr = {} self.max_ascender = None self.max_descender = None self.max_tile_width = None self.max_tile_height = None self.max_bitmap_size = None self.total_bitmap_area = 0 # load font glyphs and calculate max. char size. # This is used when the altas is created to properly size the tex. # i.e. max glyph size * num glyphs # max_w, max_h = 0, 0 max_ascender, max_descender, max_tile_width = 0, 0, 0 face = self._face face.set_char_size(height=self.size * 64, vres=self.dpi) # Create texAtlas for glyph set. x_ppem = face.size.x_ppem y_ppem = face.size.x_ppem units_ppem = self.font_info.units_per_em est_max_width = (face.bbox.xMax - face.bbox.xMin) / float(units_ppem) * x_ppem est_max_height = face.size.ascender / float(units_ppem) * y_ppem target_atlas_area = int( est_max_width * est_max_height) * face.num_glyphs # make sure it is big enough. ;) # height is trimmed before sending to video ram anyhow. target_atlas_area = target_atlas_area * 3.0 pow2_area = nextPow2(target_atlas_area) atlas_width = 2048 atlas_height = pow2_area / atlas_width self.atlas = TextureAtlas(atlas_width, atlas_height * 2) charcode, gindex = face.get_first_char() while gindex: uchar = unichr(charcode) if ud.category(uchar) not in (u'Zl', u'Zp', u'Cc', u'Cf', u'Cs', u'Co', u'Cn'): self.charcode2unichr[charcode] = uchar face.load_char(uchar, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT) bitmap = face.glyph.bitmap self.total_bitmap_area += bitmap.width * bitmap.rows max_ascender = max(max_ascender, face.glyph.bitmap_top) max_descender = max(max_descender, bitmap.rows - face.glyph.bitmap_top) max_tile_width = max(max_tile_width, bitmap.width) max_w = max(bitmap.width, max_w) max_h = max(bitmap.rows, max_h) x, y, w, h = self.atlas.get_region(bitmap.width + 2, bitmap.rows + 2) if x < 0: raise Exception( "MonospaceFontAtlas.get_region failed for: {0}, requested area: {1}. Atlas Full!" .format(charcode, (bitmap.width + 2, bitmap.rows + 2))) x, y = x + 1, y + 1 w, h = w - 2, h - 2 data = np.array(bitmap._FT_Bitmap.buffer[:(bitmap.rows * bitmap.width)], dtype=np.ubyte).reshape(h, w, 1) self.atlas.set_region((x, y, w, h), data) self.charcode2glyph[charcode] = dict( offset=(face.glyph.bitmap_left, face.glyph.bitmap_top), size=(w, h), atlas_coords=(x, y, w, h), texcoords=[x, y, x + w, y + h], index=gindex, unichar=uchar) charcode, gindex = face.get_next_char(charcode, gindex) self.max_ascender = max_ascender self.max_descender = max_descender self.max_tile_width = max_tile_width self.max_tile_height = max_ascender + max_descender self.max_bitmap_size = max_w, max_h # resize atlas height = nextPow2(self.atlas.max_y + 1) self.atlas.resize(height) self.atlas.upload() self.createDisplayLists() self._face = None #print 'w_max_glyth info:',w_max_glyph #print 'h_max_glyth info:',h_max_glyph def createDisplayLists(self): glyph_count = len(self.charcode2unichr) max_tile_width, max_tile_height = self.max_tile_width, self.max_tile_height display_lists_for_chars = {} base = glGenLists(glyph_count) for i, (charcode, glyph) in enumerate(self.charcode2glyph.iteritems()): dl_index = base + i uchar = self.charcode2unichr[charcode] # update tex coords to reflect earlier resize of atlas height. gx1, gy1, gx2, gy2 = glyph['texcoords'] gx1 = gx1 / float(self.atlas.width) gy1 = gy1 / float(self.atlas.height) gx2 = gx2 / float(self.atlas.width) gy2 = gy2 / float(self.atlas.height) glyph['texcoords'] = [gx1, gy1, gx2, gy2] glNewList(dl_index, GL_COMPILE) if uchar not in [u'\t', u'\n']: glBegin(GL_QUADS) x1 = glyph['offset'][0] x2 = x1 + glyph['size'][0] y1 = (self.max_ascender - glyph['offset'][1]) y2 = y1 + glyph['size'][1] glTexCoord2f(gx1, gy2), glVertex2f(x1, -y2) glTexCoord2f(gx1, gy1), glVertex2f(x1, -y1) glTexCoord2f(gx2, gy1), glVertex2f(x2, -y1) glTexCoord2f(gx2, gy2), glVertex2f(x2, -y2) glEnd() glTranslatef(max_tile_width, 0, 0) glEndList() display_lists_for_chars[charcode] = dl_index self.charcode2displaylist = display_lists_for_chars def saveGlyphBitmap(self, file_name=None): if file_name is None: import os #print 'CWD:',os.getcwd() file_name = os.path.join( os.getcwd(), self.getID().lower().replace(u' ', u'_') + '.png') from scipy import misc if self.atlas is None: self.loadAtlas() if self.atlas.depth == 1: misc.imsave(file_name, self.atlas.data.reshape(self.atlas.data.shape[:2])) else: misc.imsave(file_name, self.atlas.data) def __del__(self): self._face = None if self.atlas.texid is not None: #glDeleteTextures(1, self.atlas.texid) self.atlas.texid = None self.atlas = None if self.charcode2displaylist is not None: #for dl in self.charcode2displaylist.values(): # glDeleteLists(dl, 1) self.charcode2displaylist.clear() self.charcode2displaylist = None if self.charcode2glyph is not None: self.charcode2glyph.clear() self.charcode2glyph = None if self.charcode2unichr is not None: self.charcode2unichr.clear() self.charcode2unichr = None
def createFontAtlas(self): if self.atlas: self.atlas.free() self.atlas = None self.charcode2glyph = {} self.charcode2unichr = {} self.max_ascender = None self.max_descender = None self.max_tile_width = None self.max_tile_height = None self.max_bitmap_size = None self.total_bitmap_area = 0 # load font glyphs and calculate max. char size. # This is used when the altas is created to properly size the tex. # i.e. max glyph size * num glyphs # max_w, max_h = 0, 0 max_ascender, max_descender, max_tile_width = 0, 0, 0 face = self._face face.set_char_size(height=self.size * 64, vres=self.dpi) # Create texAtlas for glyph set. x_ppem = face.size.x_ppem y_ppem = face.size.x_ppem units_ppem = self.font_info.units_per_em est_max_width = (face.bbox.xMax - face.bbox.xMin) / float(units_ppem) * x_ppem est_max_height = face.size.ascender / float(units_ppem) * y_ppem target_atlas_area = int( est_max_width * est_max_height) * face.num_glyphs # make sure it is big enough. ;) # height is trimmed before sending to video ram anyhow. target_atlas_area = target_atlas_area * 3.0 pow2_area = nextPow2(target_atlas_area) atlas_width = 2048 atlas_height = pow2_area / atlas_width self.atlas = TextureAtlas(atlas_width, atlas_height * 2) charcode, gindex = face.get_first_char() while gindex: uchar = unichr(charcode) if ud.category(uchar) not in (u'Zl', u'Zp', u'Cc', u'Cf', u'Cs', u'Co', u'Cn'): self.charcode2unichr[charcode] = uchar face.load_char(uchar, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT) bitmap = face.glyph.bitmap self.total_bitmap_area += bitmap.width * bitmap.rows max_ascender = max(max_ascender, face.glyph.bitmap_top) max_descender = max(max_descender, bitmap.rows - face.glyph.bitmap_top) max_tile_width = max(max_tile_width, bitmap.width) max_w = max(bitmap.width, max_w) max_h = max(bitmap.rows, max_h) x, y, w, h = self.atlas.get_region(bitmap.width + 2, bitmap.rows + 2) if x < 0: raise Exception( "MonospaceFontAtlas.get_region failed for: {0}, requested area: {1}. Atlas Full!" .format(charcode, (bitmap.width + 2, bitmap.rows + 2))) x, y = x + 1, y + 1 w, h = w - 2, h - 2 data = np.array(bitmap._FT_Bitmap.buffer[:(bitmap.rows * bitmap.width)], dtype=np.ubyte).reshape(h, w, 1) self.atlas.set_region((x, y, w, h), data) self.charcode2glyph[charcode] = dict( offset=(face.glyph.bitmap_left, face.glyph.bitmap_top), size=(w, h), atlas_coords=(x, y, w, h), texcoords=[x, y, x + w, y + h], index=gindex, unichar=uchar) charcode, gindex = face.get_next_char(charcode, gindex) self.max_ascender = max_ascender self.max_descender = max_descender self.max_tile_width = max_tile_width self.max_tile_height = max_ascender + max_descender self.max_bitmap_size = max_w, max_h # resize atlas height = nextPow2(self.atlas.max_y + 1) self.atlas.resize(height) self.atlas.upload() self.createDisplayLists() self._face = None
def createFontAtlas(self): t1=getTime() if self.atlas: self.atlas.free() self.atlas=None self.charcode2glyph={} self.charcode2unichr={} self.max_ascender = None self.max_descender = None self.max_tile_width = None self.max_tile_height = None self.max_bitmap_size = None self.total_bitmap_area=0 # load font glyphs and calculate max. char size. # This is used when the altas is created to properly size the tex. # i.e. max glyph size * num glyphs # max_w,max_h=0,0 max_ascender, max_descender, max_tile_width = 0, 0, 0 face=self._face face.set_char_size(height=self.size*64,vres=self.dpi) # Create texAtlas for glyph set. x_ppem=face.size.x_ppem y_ppem=face.size.x_ppem units_ppem=self.font_info.units_per_em est_max_width=(face.bbox.xMax-face.bbox.xMin)/float(units_ppem)*x_ppem est_max_height=face.size.ascender/float(units_ppem)*y_ppem target_atlas_area=int(est_max_width*est_max_height)*face.num_glyphs # make sure it is big enough. ;) # height is trimmed before sending to video ram anyhow. target_atlas_area=target_atlas_area*3.0 pow2_area=nextPow2(target_atlas_area) atlas_width=2048 atlas_height=pow2_area/atlas_width t2=getTime() self.atlas=TextureAtlas(atlas_width,atlas_height) t3=getTime() charcode, gindex=face.get_first_char() while gindex: uchar=self.charcode2unichr.setdefault(charcode,unichr(charcode)) face.load_char(uchar, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT ) bitmap = face.glyph.bitmap self.total_bitmap_area+=bitmap.width*bitmap.rows max_ascender = max( max_ascender, face.glyph.bitmap_top) max_descender = max( max_descender, bitmap.rows - face.glyph.bitmap_top ) max_tile_width = max( max_tile_width,bitmap.width) max_w=max(bitmap.width,max_w) max_h=max(bitmap.rows,max_h) x,y,w,h = self.atlas.get_region(bitmap.width+2, bitmap.rows+2) #glyphdata['atlas_region']=x,y,w,h if x < 0: raise Exception("MonospaceFontAtlas.get_region failed for: {0}, requested area: {1}. Atlas Full!".format(charcode,(bitmap.width+2, bitmap.rows+2))) x,y = x+1, y+1 w,h = w-2, h-2 #print 'bitmap.width,bitmap.rows,bitmap.pitch : h,w:',bitmap.width,bitmap.rows,bitmap.pitch,h,w data = np.array(bitmap._FT_Bitmap.buffer[:(bitmap.rows*bitmap.width)],dtype=np.ubyte).reshape(h,w,1) #gamma = 1.0 #Z = ((data/255.0)**(gamma)) #data = (Z*255).astype(np.ubyte) self.atlas.set_region((x,y,w,h), data) # u0 = (x + 0.0) # v0 = (y + 0.0) # u1 = (x + w - 0.0) # v1 = (y + h - 0.0) self.charcode2glyph[charcode]=dict( offset=(face.glyph.bitmap_left,face.glyph.bitmap_top), size=(w,h), atlas_coords=(x,y,w,h), texcoords = [x, y, x + w, y + h], index=gindex, unichar=uchar ) charcode, gindex = face.get_next_char(charcode, gindex) t4=getTime() self.max_ascender = max_ascender self.max_descender = max_descender self.max_tile_width = max_tile_width self.max_tile_height = max_ascender+max_descender self.max_bitmap_size=max_w,max_h # resize atlas height=nextPow2(self.atlas.max_y+1) self.atlas.resize(height) self.atlas.upload() t5=getTime() self.createDisplayLists() t6=getTime() # print "Creating Atlas Times:" # print "\tDetermine size",t2-t1 # print "\tCreating Atlas",t3-t2 # print "\tCreate bitmap glyphs",t4-t3 # print "\tResize+Upload",t5-t4 # print "\tMake DLs:",t6-t5 # print "\tTotal:",t6-t1 self._face=None