10 releases
0.3.1 | Nov 29, 2021 |
---|---|
0.2.0 | Nov 27, 2021 |
0.1.7 | Nov 27, 2021 |
#93 in Multimedia
1.5MB
2.5K
SLoC
Collagen -- from “collage” and “generate” (and because
collagen is the protein that holds your
body together; s/protein/tool/;s/body/images/
) -- is a program that takes as input
a folder containing zero or more image files (.jpeg, .png, etc.) and a JSON manifest
file describing the layout of these images along with SVG components such as shapes
and text, and produces as output a single SVG file with all assets embedded. It is
designed to allow the coexistence of vector graphics and different kinds of raster
graphics in a single file without the problems that normally arise when attempting to
combine images with other images of a different format and/or vector graphics, and in
a format that is supported by most browsers.
Roughly speaking, a manifest file merely describes the components of the resulting SVG in a way that is simple for humans to read and write. It is up to Collagen to turn this manifest into an SVG.
Quick Start
This doc has several examples that can serve as a
good starting point. More examples are available as test cases in tests/examples
.
Rationale
There are several widely used image formats, perhaps the three best known of which are JPEG, PNG, and SVG. JPEG and PNG are raster formats, which means they correspond to a rectangular grid of pixels. On the other hand, SVG is a vector format, which means it describes perfectly precise curves that can be displayed with arbitrarily high precision. These three formats are each optimized for a different use case:
- JPEG uses lossy compression that preserves visual quality on most "real-life" images -- images that contain smoothly-varying gradients -- but which produces visible artifacts when used on other kinds of images, especially ones containing hard edges and/or text.
- PNG uses lossless compression that handles images with few distinct colors well, but requires an inordinate amount of space for storing images with many colors.
- SVG is a vector graphics format which can nevertheless contain embedded raster images; however, doing so requires base64 encoding the raster image.
Because each of these image formats is optimized for only a single use case, they cannot be easily combined. For instance, overlaying text on a JPEG image will introduce compression artifacts that were not present in the original text, while overlaying a JPEG image on a PNG will cause the file size to balloon.
SVG was chosen as the resulting file type for the following reasons:
- SVGs can indeed store vector graphics and raster images alongside each other
- SVGs are widely compatible, as most browsers can display them correctly
- SVGs are "just" a tree of nodes with some attributes, so they're simple to implement
- SVGs are written in XML, which is simple to write
Definitions
- Collagen: The name of this project.
clgn
: The executable that does the conversion to SVG.- Skeleton: A folder that is the input to
clgn
. It must contain acollagen.json
file and any assets specified bycollagen.json
. For instance, if skeletonmy_skeleton
'scollagen.json
contains{ "image_path": "path/to/image" }
, thenmy_skeleton/path/to/image
must exist. - Manifest: The
collagen.json
file residing at the top level inside a skeleton.
Using Collagen
The input to Collagen is a folder containing, at the bare minimum, a manifest file
named collagen.json
. Such a folder will be referred to as a skeleton. A manifest
file is more or less a JSON-ified version of an SVG (which is itself XML), with some
facilities to make common operations, such as including an image by path, more
ergonomic. For instance, without Collagen, in order to embed an image of yours in an
SVG, you would have to base64-encode it and construct that image tag manually, which
would look something like this:
<image href="data:image/png;base64,iVBORw0KGgoAAAA...(many, many bytes omitted)..."></image>
In contrast, including an image in a Collagen manifest is as simple as including the following JSON object as a descendent of the root tag:
{ "image_path": "path/to/image" }
Collagen handles base64-encoding the image and constructing the <image>
tag with the
correct attributes.
As mentioned in the Quick Start section, examples are available in this
doc and in tests/examples
.
Basic Schema
In order to produce an SVG from JSON, Collagen must know how to convert an object
representing a tag into an actual SVG tag, including performing any additional work
(such as base64-encoding an image). Collagen identifies the type of an object it
deserializes simply by the keys it contains. For instance, the presence of the
"image_path"
property alone tells Collagen that this tag is an <image>
tag with an
associated image file to embed. To avoid ambiguities, it is an error for an object to
contain unexpected keys.
All recognized tags are listed in [crate::fibroblast::tags
]. Each tag there documents
its schema.
Portability Concerns
- In general, filesystem paths are not necessarily valid UTF-8 strings. Furthermore,
Windows and *nix systems use different path separators. How, then, does Collagen
handle paths to files on disk in a platform-agnostic way?
All paths consumed by Collagen must be valid UTF-8 strings using forward slashes (/
) as the path separator. Forward slashes are replaced with the system path separator before resolving the path. Sopath/to/image
remains unchanged on *nix systems, but becomespath\to\image
on Windows. This means that in order to be portable, path components should not contain the path separator of any system, even if it is legal on the system on which the skeleton is authored. For instance, filenames with backslashes\
are legal on Linux, but would pose a problem when decoding on Windows. Generally speaking, if you restrict your file and folder names to use word characters, hyphens, whitespace, and a limited set of punctuation, you should be fine.
Naturally you are also limited by the inherent system limitations on path names. For instance, even thoughCON
is a valid filename on Linux, it is forbidden by Windows. Collagen makes no effort to do filename validation on behalf of systems on which it may be used; it is up to the author of a skeleton to ensure that it can be decoded on a target device. (Again, as long as you don’t do anything too crazy, you should be fine.)
Organization / Where to Find Things
TODO
FAQ
-
Wait, so all this does is base64 encode assets and put them in an SVG with other SVG elements?
It adds some additional features, such as nesting of skeletons and the use of tag-wide variables and interpolation of these variables in attributes. But yes, for the most part, all this project does is allow raster images to coexist with each other and with vector graphics. If you need to embed fonts in an SVG, Collagen lets you do that, too. -
Couldn't I just do the base64 encoding and create the SVG myself?
Yes. All Collagen does it automate this. -
I want to put some text on a JPEG. What's so bad about just opening an image editor, adding the text, and pressing save?
The text will look bad because:- It will no be longer an infinitely zoomable vector entity, but instead will have been rasterized, i.e., rendered onto a fixed pixel grid that is only finitely zoomable.
- JPEG in particular is not optimized for text, so artifacts will be visible (see here or the Drake meme above).
-
I'm ok with text being rasterized. This means I can convert my JPEG to PNG and avoid #2 above, right?
Yes and no. While the text will look sort of ok (when not zoomed in), you now have the problem that your JPEG is being stored as a PNG. Chances are that this will cause the resulting file size to explode because PNG is simply not meant to store the kind of images that JPEG is meant to store. For instance, the JPEG below (source) is 57KB, whereas the PNG is 434KB.
This JPEG weighs in at 57KB
The equivalent PNG weighs in at 434KB
-
But surely just placing black text on top of an all-white PNG is fine? Because it's stored losslessly?
Sure, if you don't mind your text being rasterized, i.e., not perfectly precise and infinitely zoomable. The image below is black text on a white background.
You don't have to zoom in very far to see the text get fuzzy. And if this image undergoes additional rounds of editing and compression, this problem will only get worse. In contrast, the text in the smiley-face image above (and, naturally, the text on this webpage) is perfectly precise and will retain all of its detail at arbitrary magnification.
Dependencies
~7MB
~137K SLoC