Glyphs forum.schriftgestaltung.de Forum / Glyphs /

FontForge and Glyphs

 
typovar
Forums Member
#1 Posted: 15 Sep 2009 09:14
Reply 
UFO is not the only human-readable font-format. FontForge stores its fonts in the SFD format. In RoboFab there is a script by EvB to work with this format (RoboFab/robofab/objects/objectsFF.py).
Any chance to im-/export (read/write) SFD directly into Glyphs?
And perhaps im-/export (read/write) Glyphs-files directly into FontForge?
Georg Seifert
Admin
#2 Posted: 15 Sep 2009 15:07
Reply 
The chance for SFD support in Glyphs is very high as it should be easy to write a plugin. If someone is interested in implementing it, I could assist.

G
typovar
Forums Member
#3 Posted: 6 Dec 2009 10:14
Reply 
Any further developement on this?
Maybe someone from the FontForge-team would be interested to do this?
typovar
Forums Member
#4 Posted: 6 Dec 2009 10:39
Reply 
form the FontForge sources: ufo.c

Matbe useful create an im-/export-plugin to read/write *.sfd fontfiles from Glyphs.

/* Copyright (C) 2003-2009 by George Williams */
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.

* The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.

* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#ifndef _NO_PYTHON
# include "Python.h"
# include "structmember.h"
#else
# include <utype.h>
#endif

#include "fontforgevw.h"
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <locale.h>
#include <chardata.h>
#include <gfile.h>
#include <ustring.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#ifndef _NO_PYTHON
# include "ffpython.h"
#endif

/* The UFO (Unified Font Object) format, http://unifiedfontobject.org/ */
/* Obsolete: http://just.letterror.com/ltrwiki/UnifiedFontObject */
/* is a directory containing a bunch of (mac style) property lists and another*/
/* directory containing glif files (and contents.plist). */

/* Property lists contain one <dict> element which contains <key> elements */
/* each followed by an <integer>, <real>, <true/>, <false/> or <string> element, */
/* or another <dict> */

/* UFO format 2.0 includes an adobe feature file "feature.fea" and slightly */
/* different/more tags in fontinfo.plist */

static char *buildname(char *basedir,char *sub) {
char *fname = galloc(strlen(basedir)+strlen(sub)+2);

strcpy(fname, basedir);
if ( fname[strlen(fname)-1]!='/' )
strcat(fname,"/");
strcat(fname,sub);
return( fname );
}

/* ************************************************************************** */
/* ************************* Python lib Output ************************* */
/* ************************************************************************** */
#ifndef _NO_PYTHON
static int PyObjDumpable(PyObject *value);
static void DumpPyObject( FILE *file, PyObject *value );
#endif

static void DumpPythonLib(FILE *file,void *python_persistent,SplineChar *sc) {
StemInfo *h;
int has_hints = (sc!=NULL && (sc->hstem!=NULL || sc->vstem!=NULL ));

#ifdef _NO_PYTHON
if ( has_hints ) {
/* Not officially part of the UFO/glif spec, but used by robofab */
fprintf( file, " <lib>\n" );
fprintf( file, " <dict>\n" );
#else
PyObject *dict = python_persistent, *items, *key, *value;
int i, len;
char *str;

if ( has_hints || (dict!=NULL && PyMapping_Check(dict)) ) {
if ( sc!=NULL ) {
fprintf( file, " <lib>\n" );
fprintf( file, " <dict>\n" );
}
if ( has_hints ) {
#endif
fprintf( file, " <key>com.fontlab.hintData</key>\n" );
fprintf( file, " <dict>\n" );
if ( sc->hstem!=NULL ) {
fprintf( file, "\t<key>hhints</key>\n" );
fprintf( file, "\t<array>\n" );
for ( h = sc->hstem; h!=NULL; h=h->next ) {
fprintf( file, "\t <dict>\n" );
fprintf( file, "\t <key>position</key>" );
fprintf( file, "\t <integer>%d</integer>\n", (int) rint(h->start));
fprintf( file, "\t <key>width</key>" );
fprintf( file, "\t <integer>%d</integer>\n", (int) rint(h->width));
fprintf( file, "\t </dict>\n" );
}
fprintf( file, "\t</array>\n" );
}
if ( sc->vstem!=NULL ) {
fprintf( file, "\t<key>vhints</key>\n" );
fprintf( file, "\t<array>\n" );
for ( h = sc->vstem; h!=NULL; h=h->next ) {
fprintf( file, "\t <dict>\n" );
fprintf( file, "\t <key>position</key>\n" );
fprintf( file, "\t <integer>%d</integer>\n", (int) rint(h->start));
fprintf( file, "\t <key>width</key>\n" );
fprintf( file, "\t <integer>%d</integer>\n", (int) rint(h->width));
fprintf( file, "\t </dict>\n" );
}
fprintf( file, "\t</array>\n" );
}
fprintf( file, " </dict>\n" );
#ifndef _NO_PYTHON
}
/* Ok, look at the persistent data and output it (all except for a */
/* hint entry -- we've already handled that with the real hints, */
/* no point in retaining out of date hints too */
if ( dict != NULL ) {
items = PyMapping_Items(dict);
len = PySequence_Size(items);
for ( i=0; i<len; ++i ) {
PyObject *item = PySequence_GetItem(items,i);
key = PyTuple_GetItem(item,0);
if ( !PyBytes_Check(key)) /* Keys need not be strings */
continue;
str = PyBytes_AsString(key);
if ( strcmp(str,"com.fontlab.hintData")==0 && sc!=NULL ) /* Already done */
continue;
value = PyTuple_GetItem(item,1);
if ( !PyObjDumpable(value))
continue;
fprintf( file, " <key>%s</key>\n", str );
DumpPyObject( file, value );
}
}
#endif
if ( sc!=NULL ) {
fprintf( file, " </dict>\n" );
fprintf( file, " </lib>\n" );
}
}
}

#ifndef _NO_PYTHON
static int PyObjDumpable(PyObject *value) {
if ( PyInt_Check(value))
return( true );
if ( PyFloat_Check(value))
return( true );
if ( PySequence_Check(value)) /* Catches strings and tuples */
return( true );
if ( PyMapping_Check(value))
return( true );
if ( PyBool_Check(value))
return( true );
if ( value == Py_None )
return( true );

return( false );
}

static void DumpPyObject( FILE *file, PyObject *value ) {
if ( PyMapping_Check(value))
DumpPythonLib(file,value,NULL);
else if ( PyBytes_Check(value)) { /* Must precede the sequence check */
char *str = PyBytes_AsString(value);
fprintf( file, " <string>%s</string>\n", str );
} else if ( value==Py_True )
fprintf( file, " <true/>\n" );
else if ( value==Py_False )
fprintf( file, " <false/>\n" );
else if ( value==Py_None )
fprintf( file, " <none/>\n" );
else if (PyInt_Check(value))
fprintf( file, " <integer>%ld</integer>\n", PyInt_AsLong(value) );
else if (PyInt_Check(value))
fprintf( file, " <real>%g</real>\n", PyFloat_AsDouble(value) );
else if (PySequence_Check(value)) {
int i, len = PySequence_Size(value);

fprintf( file, " <array>\n" );
for ( i=0; i<len; ++i ) {
PyObject *obj = PySequence_GetItem(value,i);
if ( PyObjDumpable(obj)) {
fprintf( file, " ");
DumpPyObject(file,obj);
}
}
fprintf( file, " </array>\n" );
}
}
#endif

/* ************************************************************************** */
/* **************************** GLIF Output **************************** */
/* ************************************************************************** */
static int _GlifDump(FILE *glif,SplineChar *sc,int layer) {
struct altuni *altuni;
int isquad = sc->layers[layer].order2;
SplineSet *spl;
SplinePoint *sp;
RefChar *ref;
int err;

if ( glif==NULL )
return( false );

fprintf( glif, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
/* No DTD for these guys??? */
fprintf( glif, "<glyph name=\"%s\" format=\"1\">\n", sc->name );
if ( sc->parent->hasvmetrics )
fprintf( glif, " <advance width=\"%d\" height=\"%d\"/>\n", sc->width, sc->vwidth );
else
fprintf( glif, " <advance width=\"%d\"/>\n", sc->width );
if ( sc->unicodeenc!=-1 )
fprintf( glif, " <unicode hex=\"%04x\"/>\n", sc->unicodeenc );
for ( altuni = sc->altuni; altuni!=NULL; altuni = altuni->next )
if ( altuni->vs==-1 && altuni->fid==0 )
fprintf( glif, " <unicode hex=\"%04x\"/>\n", altuni->unienc );

if ( sc->layers[layer].refs!=NULL || sc->layers[layer].splines!=NULL ) {
fprintf( glif, " <outline>\n" );
for ( ref = sc->layers[layer].refs; ref!=NULL; ref=ref->next ) if ( SCWorthOutputting(ref->sc)) {
fprintf( glif, " <component base=\"%s\"", ref->sc->name );
if ( ref->transform[0]!=1 )
fprintf( glif, " xScale=\"%g\"", (double) ref->transform[0] );
if ( ref->transform[3]!=1 )
fprintf( glif, " yScale=\"%g\"", (double) ref->transform[3] );
if ( ref->transform[1]!=0 )
fprintf( glif, " xyScale=\"%g\"", (double) ref->transform[1] );
if ( ref->transform[2]!=0 )
fprintf( glif, " yxScale=\"%g\"", (double) ref->transform[2] );
if ( ref->transform[4]!=0 )
fprintf( glif, " xOffset=\"%g\"", (double) ref->transform[4] );
if ( ref->transform[5]!=0 )
fprintf( glif, " yOffset=\"%g\"", (double) ref->transform[5] );
fprintf( glif, "/>\n" );
}
for ( spl=sc->layers[layer].splines; spl!=NULL; spl=spl->next ) {
fprintf( glif, " <contour>\n" );
for ( sp=spl->first; sp!=NULL; ) {
/* Undocumented fact: If a contour contains a series of off-curve points with no on-curve then treat as quadratic even if no qcurve */
if ( !isquad || /*sp==spl->first ||*/ !SPInterpolate(sp) )
fprintf( glif,
 
Bold Style Italic Style Image Link URL Link

 

Forums are powered by miniBB®