Thursday, March 28, 2013

FontForge: Rolling Type Design with No Save Using Collab

FontForge has some support for collaborative type design. It's early days, but things are moving along in the right direction. In order to test things I've been looking at the python scripting support with an eye to moving control points around etc, or doing design and modification from the script and having the collab server keeping up with things. This way I can "save" the type that is being designed at certain points and compare the saved font with that I would expect the result of multiple collaborators (the previous python scripts) should be. Automated testing for the win!

So, No Save is only for the "doing" scripts. I of course want to save the current type at my leisure :)

You might be wondering what a script that creates a glyph might look like. I had to do a bit of trial and error to figure out how to use the scripting API myself. With that in mind, I might roll some of my scripts into the mainline FontForge git repo so others can enjoy the little snippits to base their own scripts on.

Anyway, the following script will load a font and create a new capital "C" glyph. The core of this that wasn't that intuitive to me is that you have to set g.layers[] to the layer you got earlier from g.layers[] or the new contour will not show up in the /tmp/out.sfd file. See the MUST comment for the needed line.

import fontforge

f=fontforge.open("test.sfd")       
fontforge.logWarning( "font name: " + f.fullname )

g = f.createChar(-1,'C')
l = g.layers[g.activeLayer]
c = fontforge.contour()
c.moveTo(100,100)   
c.lineTo(100,700)   
c.lineTo(800,700)   
c.lineTo(800,600)   
c.lineTo(200,600)   
c.lineTo(200,200)   
c.lineTo(800,200)   
c.lineTo(800,100)   
c.lineTo(100,100)   
l += c
g.layers[g.activeLayer] = l  #### MUST do this for changes to show up

f.save("/tmp/new.sfd")

At first blush I was expecting to do something like
c = layer.createContour()
c.moveTo()
...
c.lineTo()
and then not have to do anything special. At that stage calling f.save() should know about the new contour etc and save. But without setting the g.layers[active] to the layer that contains the contour you will not see it.

Digging into the C code in python.c I see that point, contour etc are all basically abstractions for python use only. When you assign to a layer in the "g.layers[] = l" call, the C function PyFF_LayerArrayIndexAssign() calls PyFF_Glyph_set_a_layer() which uses something like SSFromLayer() to convert the python only data structure (contour or what have you) into a native "c" SplineSet object.

The good news is that with all this mining into python.c I now have some collab sprinkles in there. So when you do "g.layers[] = l" the FontForge in script mode will send updates to the layer off to the server as a collab update message.

The test is quite easy to run. As three consecutive scripts, start the collab server process (collab server remains running, script ends). Next attach to the collab server and update the C glyph, and finally attach to the collab server and grab all its data and save a out.sfd file.

fontforge -script collab-sessionstart.py
fontforge -script collab-sessionjoin-and-change-c.py
fontforge -script collab-sessionjoin-and-save-to-out.sfd.py

The middle script connects to the collab server and makes its changes with the python API and then exits. No Save. To know if the changes made it to the collab server, the last script grabs all the updates etc and builds the "current" font to save into /tmp/out.sfd.

It took a bit of hacking in the python code, but now the little changes to the contour (path) of the C glyph are sent to the server as one would expect.

The python scripts are still out of repo. Since they are interesting in and of themselves I'll likely put them into my fontforge fork as a prestage to having them mainline.

Now to move on to the next thing that needs to be send to the collab server and updated in all clients.

Monday, March 4, 2013

FontForge Design: Two is a party!

FontForge can now allow multiple people to collaborate on designing a font in real time. This is all still rather alpha level code, and in fact the pull request including this code was only pushed over the fence in the last hour ;) If real time collaboration sounds interesting to you, or something in this post seems of interest, then you might like to attend an upcoming Interactivos Workshop which is right after the Libre Graphics Meeting in Madrid (10-27 April).

At interactivos I will be expanding on the current collab code and discussing future directions and possible cross tool network specifications to allow different font tools to talk to each other. Even if you are not convinced that you want anyone else joining your collab session, you might like something like a Web sink watching your work and updating a page on your tablet as you modify the font so you can see in near real time if changes are going to work well on a target device and design or not. Why burden your workflow having to have your local fontforge export to an OTF and slow you down when a server can do all that for you in the background. There is no reason that the processes in the collab session can't all be running on your behalf.


If you are running osx then I have a binary drop for you which bundles all the needed stuff for collab at:
http://fuuko.libferris.com/osx/packages/201303/05_1630/


To start a server select the menu item Collaborate/Start Session... a dialog will show you the IP address the server will run on so you can start fontforge on another computer (+other OS) and connect to that address using Collaborate/Connect to Session...

Things are in very early days and focus has been only on the glyph view. It seems that there is some fluff holding the undo system from working on the metrics view (thus on kerning etc).

The design uses FontForge's undo/redo system to know what the changes are in the font, and since those changes can be serialized to an SFD format that code is reused to send and receive the undo information across a zeromq broadcast server.

The design is inline with the MCT (Merge Enabled Change Tracking) for ODF that is up on the OASIS lists. In FontForge's case, s baseline full SFD snapshot and sequential fragments thereafter describing updates.

If you are compiling from sources then you'll need czmq and zeromq version3 development stuff installed. Then grab master from github and enjoy.
https://github.com/fontforge/fontforge