What does it do?

ASCIIToSVG is a pretty simple PHP library for parsing ASCII art diagrams and
converting them to a pretty SVG output format.

But... why?

There are a few reasons, mostly to do with things I really like:

I like markdown a lot. If I could write everything in markdown, I
probably would.

I like ASCII art a lot. I've been playing around with drawing ASCII art
since I was both a wee lad and a BBS user.

I like pretty pictures. People say they're worth a thousand words.

So I thought, "What if I could combine all these things and start writing
markdown documents for my technical designs -- complete with ASCII art
diagrams -- that I could then prettify for presentation purposes?"

Aren't there already things that do this?

Well, yes. There is a project called ditaa that has this functionality.
Sort of. But it's written in Java and it generates PNG output. I needed
something that would generate scalable output, and would be a bit easier to
integrate into a wiki (like the one in mtrack, which we use at work).
We got it integrated, but I ran into a few bugs and rendering nits that I
didn't like. Additionally, it takes a long time to shell out the process
and JVM to generate the PNG. If you're doing inline edits on an image, you
can imagine that this gets to be a heavy load on both the client and
server, just from a data transfer perspective alone.

So I reimplemented it in PHP. There are some things it can do better, and
I'm aware of a few rendering bugs already, but so far it works better and
is more extensible than ditaa, and I'm enjoying it more.

Building ASCIIToSVG

What?! Building?!?! Isn't this PHP?

Well, yes. But some of it is tool-generated. If you check out the code, you
will get the latest generated code, don't worry! This information is more
for people who want to contribute and need to make changes to the SVG path
parser.

You will need JLexPHP and lemon-php to build the tokenizer and
parser for the SVG paths. (This parser was implemented from the SVG 1.1
paths BNF.) JLexPHP requires the JDK to build; lemon-php requires a C
compiler.

Simply running make should be enough to get all the autogenerated stuff
running. It will also update the logo. Please make sure to view the logo and
test files to make sure that you haven't broken any rendering.

Make clean will remove extraneous files that aren't necessary for running;
make distclean removes everything autogenerated.

Using ASCIIToSVG

Command Line

A command line utility exists to convert the ASCII file to SVG. You can put
this somewhere inside your $PATH and set its permissions to +x. Windows
users will have to make their own batch file to run this or remove the first
line. Usage:

Note that this uses PHP's getopt which handles short options stupidly. You
need to put the actual argument right next to the flag; no space. For
example: a2s -i- -oout.svg -s10,17 would be a valid command line
invocation for this utility.

Class API

There are plenty of comments explaining how everything works (and I'm sure
several bugs negating the truth of some of those explanations) in the source
file. Basic flow through the API is:

I'll put more detailed information in the wiki and this README as I
have time and inclination to do so.

How Do I Draw?

Enough yammering about the impetus, code, and functionality. I bet you want
to draw something. ASCIIToSVG supports a few different ways to do that. If
you have more questions, take a look at some of the files in the test
subdirectory. (If you have a particularly nice diagram you'd like to see
included for demo, feel free to send it my way!)

Basics: Boxes and Lines

Boxes can be polygons of almost any shape (don't try anything too wacky
just yet; I haven't). Horizontal, vertical, and diagonal lines are all
supported, giving ASCIIToSVG basically complete support for output from
App::Asciio. Edges of boxes and lines can be drawn by using the
following characters:

- or =: Horizontal lines (dash, equals)

| or :: Vertical line (pipe, colon)

*: Line of ambiguous direction (asterisk)

\ or /: Diagonal line (backward slash, forward slash)

+: Edge of line passing through a box or line corner (plus)

The existence of a : or = edge on a line causes that line to be
rendered as a dashed line.

To draw a box or turn a line, you need to specify corners. The following
characters are valid corner characters:

' and .: Quadratic Bézier corners (apostrophe, period)

#: Boxed, angular, 90 degree corners for boxes (hash)

+: Boxed, angular, 90 degree corners for lines (plus)

The + token is a control point for lines. It denotes an area where a line
intersects another line or traverses a box boundary.

A simple box with 3 rounded corners and a line pointing at it:

#----------.
| | <---------
'----------'

A Quick Note on Diagonals

Diagonal lines cannot be made to form a closed box. If you would like to
make diagrams using parallelograms / diamonds (perhaps for flow charts), it
is recommended that you annotate regular boxes and use custom objects (see
below) instead. Diagonal lines also may not use ' or . smoothed corners.

Basics: Markers

Markers can be attached at the end of a line to give it a nice arrow by
using one of the following characters:

<: Left marker (less than)

>: Right marker (greater than)

^: Up marker (carat)

v: Down marker (letter v)

Basics: Text

Text can be inserted at almost any point in the image. Text is rendered in
a monospaced font. There aren't many restrictions, but obviously anything
you type that looks like it's actually a line or a box is going to be a good
candidate for turning into some pretty SVG path. Here is a box with some
plain black text in it:

.-------------------------------------.
| Hello here and there and everywhere |
'-------------------------------------'

Basics: Formatting

It's possible to change the format of any boxes / polygons you create. This
is done (true to markdown form) by providing a reference on the top left
edge of the object, and defining that reference at the bottom of the input.
Let me reiterate that the references must be defined at the bottom of
the input. An example:

Text appearing within a stylized box automatically tries to fix the color
contrast if the black text would be too dark on the background. The
reference commands can take any valid SVG properties / settings for a
path element. The commands are specified in JSON form, one per line.
Reference commands do not accept nested JSON objects -- don't try to
place additional curly braces inside!

The text of a reference is left in the polygon, making it useful as an
object title. You can have the reference removed by adding an option
a2s:delref to the options JSON object. Any value will suffice to have
the reference fully removed from the polygon. You can also replace the
text in the label by specifying a2s:label.

This method is (in my opinion) much nicer than the one provided by ditaa:

It eats up less space.

It fits in smaller boxes.

It allows more customization.

It's easier to see what formatting changes happened in diffs.

It's easier to read any text nested in the box itself.

But that's just me. If you have thoughts on how to do this for lines,
please do let me know.

Special References

It is possible to reference an object by its starting row and column. The
rows and columns start at (0, 0) in the top left of the diagram. Such
references should only be made for stable diagrams, and only if you really
need to style text or a line in some particular way. Such references are
marked by starting the line with [R,C] where R is the numeric row and
C is the numeric column.

Note that boxes start from their top left corner. Text starts from the first
non-whitespace character on a line (and only traverses a single space in
between text points). Lines start from the left-most point on the line that
is not adjoined to any other objects.

Basics: Special Objects

There was some pretty nifty functionality in ditaa for special box types.
The ones I was most interested in were the storage and document box,
though I recently learned there are more than are advertised on the website.
To do this, one adds an a2s:type option to the box and specifies one of
the supported object types:

storage: The standard "storage" cylinder.

document: The standard document box with a wavy bottom.

cloud: A network cloud.

computer: Something that looks kind of like an iMac.

Creating Special Objects

Although a tutorial on SVG is out of the scope of this document, it is
possible to create your own custom objects for your own graphs! Fire up your
favorite vector editor that is capable of producing SVG output (if you don't
have one, Inkscape will work fine). Draw to your heart's content and
save your drawing as an SVG image (you will need to use the path tool; any
premade shapes aren't supported). Open the image and extract all the path
tags; put them in a file called object.path. Place this file in the
objects directory. Any time you reference "a2s:type":"object", your new
object will take the place of the box you created.

There are a few caveats to this approach:

You must specify the width and height of the original canvas in every
path, although there are no minimum or maximum values, nor is there any
required aspect ratio.

The path (or any group it is in) of the original SVG file must not be
transformed in any way. (Inkscape will do this if you change your
document size after you start drawing, for instance.)