SVG in Fritzing

A Case Study

Table of Contents

Introduction to Fritzing
SVG in Fritzing
Sketches and Parts
Parts Editor
A tool problem
Part Generators
Gerber Export
Ground Plane Generation

Fritzing is an Open Source project to support designers and artists in taking the step from physical prototyping to actual product. We have created the Fritzing software in the spirit of Processing[W11] and Arduino[W12], producing a tool that allows the designer / artist / researcher / hobbyist to document their microcontroller-based prototype and to create Printed Circuit Board (PCB) layouts for manufacturing. The associated Fritzing website helps users share, remix and discuss designs and experiences.

Fritzing is essentially Electronic Design Automation (EDA) software with a low barrier to entry, suited to the needs of designers and artists. It uses the metaphor of the breadboard to facilitate the transfer between hardware sketches and software representation. From there, it is possible to create a specification for turning the circuit into a PCB. The PCBs can be fabricated using do-it-yourself (DIY) etching techniques[W13], or sent out to a manufacturer for professional production. Thus, the Fritzing process enables the designer to build a robust circuit which can be used in permanent installations or small-multiple batch production runs.[W1]

Fritzing runs on Windows, Mac and Linux platforms. It is implemented in C++ using the Qt framework[W2]. One of the factors that led us to choose Qt was its support for SVG rendering. In Fritzing, we use SVGs to represent the individual electronic parts in a circuit. The user manipulates these parts on a canvas.

In an earlier version of Fritzing,[1]parts were implemented as bitmaps (even SVGs were internally rendered into bitmaps), and the resulting performance was very slow, especially when zooming. In addition, scaling bitmaps produced aliasing artifacts, and a multi-resolution bitmap scheme was written in an attempt to work around these limitations. Thus we learned the hard way that the next Fritzing platform should use "native" vector graphics for fast rendering and scaling with no degradation.

Another advantage of SVG for Fritzing is the ability to be able locate elements precisely, using measurements that translate accurately to real world units. Tolerances for printed circuit boards are quite small, and if one were to design a PCB with only approximate measurements, the circuit created could contain short circuits from unintended cross-connections, not to mention potential power and signal noise issues. Two other important factors led us to use SVG: our intended user base is familiar with SVG editing tools, and its XML-basis makes it easy to parse and generate programmatically.

The part is the main user-manipulable unit in Fritzing, and it is SVG-based. In the process of creating a sketch, a user assembles multiple parts by dragging them from a parts bin, and connects them with graphical wires. Each part includes a set of connectors. Each connector has a particular location on a part, it has a gender (male or female) and other metadata, and it has a terminal point--the point at which wires (or, in the case of female connectors, other parts) may attach. The wiring can be made more readable by changing colors, using bend points or by using autorouting tools.

A single part is defined by multiple files: an XML-based metadata file (.fzp), which refers to multiple SVG files: one for each of the three views, plus one more for an icon. The metadata file also lists a part's connectors, and associates each of them with an svgId attribute. This attribute matches the id attribute of one element in each of the SVG files. So the metadata about each connector is found in the fzp file, but the shape and the location of the connector on the part are found in the SVG files. Similarly, a connector's terminal point has a terminalId attribute in the fzp file which matches the id attribute of one element in each of the SVG files. (Note: connectors and terminal points don't necessarily have to appear in all views).

One advantage of this structure, in which a metadata file points to SVG files, is the possibility to reuse SVG files both within and between parts. This is especially helpful for PCB graphics (footprints) as these generally conform to specific industry standard package geometries. This means that once a standard footprint SVG is defined, it can be reused by many parts and the part author will only have to make slight changes to the images for the Breadboard and Schematic views. (Going up a level from parts to sketches, a sketch file is yet a different metadata file, which refers to the parts contained in the sketch as external files.)

Parts can also have multiple layers which are specific to a particular view. In any given view, a user can easily change which layers are visible. For example, in PCB view, a part might have Copper0 and Silkscreen layers, and a user might not want to see the Silkscreen layer when he is wrestling with the details of routing connections on the Copper0 layer. As with the previous id-correspondence schemes, a layer is identified in the metadata file using a layerId attribute, which corresponds to an element id in its associated view SVG file. One difference from the other schemes however, is that while connectors and terminal points tend to be fairly simple elements, layers can be quite complex hierarchies of elements. For example, all connector elements are usually found inside a single layer element.

Qt provides SVG rendering support via the QSvgRenderer class. This class implements a superset of SVG 1.2 Tiny. However, it is not possible to selectively hide/show individual SVG elements using Qt's implementation. So our approach to the problem is to split a single view SVG file into multiple SVG files, one for each layer, at the time the part is loaded. To generate each SVG file, the header from the original SVG file is copied, and then the element identified by the layer's id attribute is extracted from the original file and pasted into the new layer SVG file.

We considered having separate SVG files for each layer, but we planned for users to create their own parts using standard vector drawing tools like Inkscape[W8] and Adobe Illustrator[W9], and we concluded that large collections of files would unnecessarily complicate the process. In addition, working with a single image file for each view makes it easier to preserve the spatial correspondence between layers in that view. We also considered keeping everything, metadata and all the view SVGs, in a single SVG file, but we concluded that this would make part creation more difficult and would complicate image reuse.

While we provide a set of common and useful core parts it is quite impossible to maintain a library that could even begin to hold every part that any user could possibly want to use. Therefore, we encourage users to create their own parts and we provide a Parts Editor for that purpose. As many of our users are artists and designers, we know that they have both the capacity and motivation to create part images for the different views. Furthermore, most of them are familiar with vector graphics tools, such as Illustrator or Inkscape. The parts editor allows them to integrate these images into a part definition, define connectors for each view, and add metadata for the part and each individual connector.

In the Parts Editor, the user imports an SVG for each view, and the software allows the user to attach connectors by representing them as on-screen manipulable rectangles. The user can then move and resize the connectors. The Parts Editor ensures that the correspondence between SVG element ids and their metadata references are consistent. Since these SVGs can come from any source, it is often convenient to recycle images from existing similar parts. If an SVG already has connectors defined, they are represented on-screen and if the user should delete any of them, the connector references are removed from the SVG file as it is saved. While maintaining this consistency has been a little painful for the programmers, it has proved to be a popular feature with our users.

As Fritzing is intended for "non-technical" users, one of our goals is to avoid forcing the user to hand-edit markup files. As a result, we have come to be highly dependent on Inkscape and Illustrator, and this has exposed us to a number of bugs and idiosyncrasies in their respective SVG implementations.

In general, our userbase is most familiar with Illustrator. From our point of view, as mentioned above, its main flaw is that it converts all units into px, but doesn't bother to convert stroke-width values. And for those who are willing to work with mark-up, losing their original units can be very frustrating. Another issue with Illustrator is its treatment of transparency and gradients, which are part of SVG 1.2 Tiny. Unfortunately, Illustrator doesn't seem to agree. And if you don't save to 1.2 Tiny, then the transparency is saved in rasterized form.

Our main trouble with Inkscape is that most users don't remember to save their SVGs using the "Save As... Plain SVG" option, and aside from the extra verbosity of the many sodipodi namespace attributes in the "Inkscape" SVG, the mirroring of sodipodi attributes with regular SVG attributes sometimes confuses Qt's XML parsing (at least we think that is what is happening). For example, we will see a circle element with both cx attributes and sodipodi:cx attributes. Our second trouble with Inkscape is it tends to pack many name-value pairs inside a single CSS-like style attribute rather than saving these as individual XML attributes, which rather defeats the point of an XML-based markup. Third, when an element is moved inside Inkscape, rather than having its coordinates directly updated, the item is given a transform. This and the style idiosyncrasy makes Fritzing's SVG parsing job just a little harder.

In general, all the tools, Illustrator, Inkscape, and Qt's SVG renderer, seem to have slightly different ideas about what an implementation of SVG 1.2 Tiny really is (for example, though gradients are in the spec, Qt's renderer rasterizes them). It would be very nice if every SVG renderer and editor would run their software against the SVG Test Suite[W6] and publish the results. And though we would like to validate the SVGs that we load, we have not found an easy way to integrate a Relax-NG validator into our codebase (and if it were integrated, and a validation fails, how exactly can we or our users fix the problem?).

These issues have led us to question our strategy of using external tools to produce SVGs for Fritzing. And in terms of how they are used for Fritzing, both Inkscape and Illustrator are more powerful than most users will ever need. So we have been fantasizing lately about offering our own simplified standards-compliant SVG editor, and giving it a very nice UI. But this is really not in the main line of Fritzing development, and so will probably remain a fantasy.

The electronics industry has produced an astounding number and variation of components. Even with Open Source crowdsourcing techniques, mirroring this diversity by hand-producing Fritzing parts is a futile task. But thanks to powerful templating tools for XML we were able to create a set of scripts that enable us to quickly generate sets of similar SVG images, such as resistors, capacitors, and ICs. Templates can be created using standard SVG tools and then modified to turn out parts with various combinations of colors, sizes, and numbers of pins.

While Fritzing itself is written in C++, our website and many of our development utilities are coded in Python. We chose to use Cheetah's powerful templating system[W5] for our parts generators as it integrates nicely with Python. A typical script will iterate over a range or set of variables and create the unique SVGs and XML metadata files for each part. This process was extremely useful in the early stages of development when the file format was frequently changing.

Finally, we have integrated these scripts into our web site so that users can simply fill out a web form to create custom parts to their specification [W10]. These parts can be modified using the Parts Editor and SVG authoring tools, just as with parts made from scratch. Our hope is that given a sufficient collection of these scripts, the majority of special parts could be generated and only the most exotic parts would need to be created by hand.

Once a user has finished creating a sketch (i.e. laying out a circuit), for purposes of production or documentation it must be converted to other formats. Fritzing provides a number of different export options, depending on the end production technology. PDF and PostScript outputs are provided by Qt, and once we figured out that Qt stores images internally at 90 dpi, we were able to ensure that parts would be printed at their true real-world sizes. PNG and JPEG outputs are also provided by Qt, so we simply had to set the right image resolution to output images at the proper size.

However, exporting to SVG proved a little more complicated. Qt does not provide a method to take a sketch composed of separately rendered parts and wires, and convert that to a single SVG file, so we had to devise our own approach:

  • The first step is to take all of the individual part SVGs and normalize them. That is, we set up the target SVG with width , height , and viewBox attributes so that coordinates are expressed in 1000 dpi units. Then we go through each part, converting its coordinates and other scale-relative attribute values ( radius , stroke-width , etc) to 1000 dpi units.

  • During this step we also translate the part coordinates to absolute coordinates within the full sketch-- this makes subsequent parsing easier.

  • Depending on the purpose of the export, we may change the value of an element's stroke and fill attributes. For example, if you are exporting a PCB for DIY etching, which needs a solid black image, we will set the stroke and fill attributes to black .

  • Next, we convert all the wires in the sketch to line elements.

  • Again, depending on the purpose of the export, only certain layers of a given part will be visible, so elements belonging to the non-visible layers are ignored.

We originally picked 1/1000 inch resolution because it is the most common standard unit in professional PCB manufacturing. However, we found that many of our users import the Fritzing-exported SVGs into Adobe Illustrator, which converts everything internally to 72 dpi. This would not be a problem if Illustrator also converted the stroke-width attribute, but Illustrator does not, so user sketches showed up in Illustrator rendered dramatically incorrect. So we now export our SVGs at 72dpi as a workaround.

While exporting a printable graphic image is very useful and effective for home or small lab production, almost all professional PCB production houses expect files in the Gerber RS-274-X format[W7]. This format, often simply called Gerber, was created in the 1970s by the Gerber Systems Corp (now owned by Mania Technologie AG) to drive photoplotting machines. The file describes the movement of a photoplotter head with a series of commands: move, light-on, light-off, aperture size change and shape change. The action of exposing a photo-sensitive film to light creates a resist which is used to define the areas of the circuit board which will be etched. While most modern photoplotters are actually raster based, the legacy standard lives on.

To export to Gerber format, we first go through the SVG export process (using 1000dpi), then walk through the SVG element tree, where there is a more-or-less one-to-one correspondence between Gerber elements and SVG elements. Gerber has some limitations, however. The only curves supported in Gerber are complete circles or circular arc segments, so currently there are no footprints in Fritzing with bezier curves. While it has not yet been implemented, we have considered several algorithms to convert SVG curves to poly-lines or arc segments. In addition there is no support in Gerber for fonts or generic text. One possible solution is to map SVG path-based font tables to straight lines and circular arc segments.

There is one further manipulation to perform when Fritzing exports for etching (or to Gerber format): when part footprints and traces are exported, it leaves large areas of the PCB unfilled, and removing all the copper from these areas is time consuming; wasteful of etchant chemicals; and depending on the production process, less environmentally sound. Furthermore, some or all of these unfilled areas can be connected to ground, which makes routing the PCB much easier. Finally, using a ground plane in printed circuits can reduce signal noise.

Our first idea for how to implement a ground plane was once again to generate a single sketch SVG but increase each element's stroke-width attribute by some percent, and then subtract this modified sketch shape from the shape of the board. However, we couldn't find an easy way to perform subtraction directly in SVG space. So our next idea was to render the fattened sketch into a bitmap, then find some way to vectorize that back into an SVG. It is unnecessary to work with such a bitmap at a high resolution: it is much more important to set the stroke-width on all parts and wires wide enough to avoid any short circuits. We looked at using Potrace[W4] for doing the vectorization, but as that seemed to be more than we needed, and as perhaps there would be some difficulty integrating it into our codebase across all three platforms (and because it was an interesting problem to work on), we developed our own solution.

The first version simply went through the bitmap line-by-line and generated a horizontal line element for each set of contiguous horizontal empty pixels. Our second version was a little more clever and used the endpoints of all those horizontal empty lines to create a set of filled polygon elements (i.e. a polygon for each empty "island" in the bitmap). There is still room for optimization by removing redundant endpoints in the polygons, but our ground plane implementation is working. Similar techniques could be used to create a more flexible solder mask layer.

Our original motivation for choosing vector graphics for Fritzing arose from our experience with an earlier raster-based version. The switch to SVG gave us much faster rendering and smooth scaling—previously our users had complained about the sluggishness of the program in these two regards. But as we began to work more deeply with SVG, we were able to take advantage of some of its other features. For example, it is very important that the true sizes of parts and connectors are preserved between Fritzing and various export formats (including the printed page), and the width, height, viewBox coordinate scheme greatly facilitates that. Furthermore, as an XML-based standard, SVG makes it straightforward to programmatically manipulate SVG images, and we have taken advantage of this for exporting sketches to various formats, as well as generating and editing parts.

Due to our unique requirements, in which a single part is visualized differently between views, we decided that SVG alone wasn't sufficient to represent a part, so we adopted a multi-file format in which a metadata file points to a set of SVG files. Splitting up the files this way gave us the advantage that individual SVG files could easily be reused both within and between parts.

The one less-than-positive note we strike is one which arises from our intended workflow, in which SVGs move back and forth between Fritzing and external tools (particularly Inkscape and Illustrator). Because each of these tools, as well as the Qt renderer, take a slightly different tack with regard to SVG creation and rendering, we have found ourselves attempting to provide an extra insulating layer of code in Fritzing to smooth the transition from program to program (note: going from Inkscape to Illustrator, or vice versa, is another frustrating exercise). It would be nice if SVG editors would all seriously conform to the SVG Test Suite[W6] to help guarantee interoperability. It would also be nice to find a C++ reference library for SVG manipulation.

In the end, we can confidently assert that SVG has made our application easier to develop, and has enabled many important features in Fritzing. Despite the difficulties we have mentioned, we are able to take advantage of powerful external tools for editing and creating SVG images. Overall, SVG makes Fritzing more user-friendly, more powerful, faster and generally more pleasant to develop and use.

Thanks to Reto and André for initiating the Fritzing project; and to Dirk, Lionel, Omer, Stefan and all the others who have struggled with our ever-evolving parts creation process. We gratefully thank the Brandenburg Ministry of Science, Research, and Culture (MWFK) for funding.

[1] The earlier version of Fritzing was written in Java on top of GEF[W3] and other Eclipse frameworks