centerglyph.py 4.81 KB
#!/usr/bin/python
# vim:ts=8:sw=4:expandtab:encoding=utf-8
'''Center glyphs.
Copyright <hashao2@gmail.com> 2008

#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 3 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

Put the file in $(PREFIX)/share/fontforge/python or ~/.FontForge/python, invoke
from "Tools->Metrics->Center in Glyph" after selected some glyphs.

'''
__version__ = '0.1'

import sys
import fontforge
import psMat

def center_glyph(glyph, vcenter=0, lbearing=15, rbearing=None):
    '''Center a glyph.'''
    # Shift width
    if not rbearing:
        rbearing = lbearing
    bounding = glyph.boundingBox() # xmin,ymin,xmax,ymax
    width = (bounding[2] - bounding[0])
    width_new = width+(lbearing+rbearing)
    glyph.width = width_new
    glyph.left_side_bearing = lbearing
    glyph.right_side_bearing = rbearing

    # Shift Height
    center_glyph_height(glyph, vcenter, bounding)

def center_glyph_height(glyph, vcenter, abound=None):
    bounding = abound or glyph.boundingBox() # xmin,ymin,xmax,ymax
    glyphcenter = (bounding[3] - bounding[1])/2+bounding[1]
    deltay = vcenter - glyphcenter

    matrix = psMat.translate(0, deltay)
    glyph.transform(matrix)
    
def CenterGlyph(junk, afont):
    '''Main function.'''
    center = (afont.ascent - afont.descent)/2

    # total 5% margin
    em = afont.ascent + afont.descent
    lbearing = int(em*0.05/2)

    for glyph in afont.selection.byGlyphs:
        center_glyph(glyph, center, lbearing)

def CenterHeight(junk, afont):
    '''Main function.'''
    center = (afont.ascent - afont.descent)/2

    for glyph in afont.selection.byGlyphs:
        center_glyph_height(glyph, center)

def fit_glyph(glyph, em, percent=0.95):
    '''Scale a glyph horizontally to fit the width.'''
    bounding = glyph.boundingBox() # xmin, ymin, xmax, ymax
    gwidth = (bounding[2] - bounding[0])
    gheight = (bounding[3] - bounding[1])
    if not gwidth or not gheight:
        return
    rate = em*percent/gwidth
    #print gwidth, rate, em
    # Don't excess the height 
    if rate*gheight > em:
        rate = em*percent/gheight
    matrix = psMat.scale(rate)
    glyph.transform(matrix)

def ScaleToEm(percent, afont):
    '''Scale a font to fit 5% less than the em.'''
    em = afont.ascent + afont.descent
    center = (afont.ascent - afont.descent)/2
    lbearing = int(em*0.05/2)
    if not percent:
        ret = fontforge.askString('Scale Percent?',
                'Percent of Line Height (em)?', '90' )
        if not ret:
            return
        try:
            percent = float(ret)/100
            if percent <= 0 or percent > 1:
                raise ValueError
        except ValueError:
            fontforge.postError('Wrong Percent!', "Need a value <= 100.")
            return
    for glyph in afont.selection.byGlyphs:
        fit_glyph(glyph, em, percent)
        #center_glyph(glyph, center, lbearing) # Maybe not move glyph?
        center_glyph_height(glyph, center) 

def get_max_size(afont):
    '''Get the max size of the selected glyphs.'''
    wmax = 0
    hmax = 0
    for glyph in afont.selection.byGlyphs:
        bbox = glyph.boundingBox()
        wmax = max(wmax, bbox[2] - bbox[0])
        hmax = max(hmax, bbox[3] - bbox[1])
    em = afont.ascent + afont.descent
    wpct = wmax and em/wmax*100
    hpct = hmax and em/hmax*100
    return wmax, hmax, wpct, hpct

def GetSelectedBound(junk, afont):
    '''Show max height and width of the selected glyphs.'''
    wmax, hmax, wpct, hpct = get_max_size(afont)
    msg = ('The max width and height of the selected glyphs are:\n'
            'Points:\t%d\t%d\nScale Factor to 100%%:\t%.3f\t  %.3f%%')
    msg = msg % (wmax, hmax, wpct, hpct)
    fontforge.postError('Max Demension', msg)

if fontforge.hasUserInterface():
    fontforge.registerMenuItem(GetSelectedBound, None, None, "Font", None,
            "Metrics", "Max Selected Size");
    fontforge.registerMenuItem(CenterHeight, None, None, "Font", None, "Metrics", 
            "Center in Height");
    fontforge.registerMenuItem(CenterGlyph, None, None, "Font", None, "Metrics", 
            "Center in Glyph");
    fontforge.registerMenuItem(ScaleToEm, None, None, "Font", None, "Transform", 
            "Scale to Em");