2013-01-27

How to Insert Images into Twine Without Linking


UPDATE: Twine 1.4 makes this process much easier. Go to the "Story" menu and select "Import Image". The techniques in this article are still valid too.


Twine has enjoyed some recent popularity and it is great to see the diverse and wonderful things people do. Inserting images into Twine is something that has become popular but having to transport the image as a file separate to the Twine output .html introduces some additional complications. I like the single output file nature of Twine.

Look at this Twine demo:
http://eturnerx.com/files/twinehowto/ImageDataURI.html (source .tws)
There is an image stored in the .html file itself using a Data URI (RFC 2397). That image is not a separate linked file. You can check it yourself, I'll wait.

Data URIs contains the data for the image in an encoded string that is embedded into the html <img> element. This works fine in most recent browsers (IE 8+) but is only suitable for smallish files. For IE8 the limit is not much bigger than 20 kilobytes but other browsers (including IE9) work just fine with much larger file sizes.

It is surprising how much image can fit within 20 kilobytes just by playing with filetype, compression settings and reducing pixel dimensions. Most flat line drawings in a few colours will generally compress well as PNG or GIF. Scanned line drawings should have the contrast boosted and/or posterized to flatten the colours in the image. Photographs or scanned images generally work better as JPEGs.

Once you have a small image file then it will need converting to a Data URL. I like to use:
http://websemantics.co.uk/online_tools/image_to_data_uri_convertor/
They also have links to online tools that can further compress your image.

Here is the code that goes into your Twine passage:

<html><img width="11" height="14" src="data:image/gif;base64,R0lGOD
lhCwAOAMQfAP////7+/vj4+Hh4eHd3d/v7+/Dw8HV1dfLy8ubm5vX19e3t7fr
6+nl5edra2nZ2dnx8fMHBwYODg/b29np6eujo6JGRkeHh4eTk5LCwsN3d3dfX
13Jycp2dnevr6////yH5BAEAAB8ALAAAAAALAA4AAAVq4NFw1DNAX/o9imAsB
tKpxKRd1+YEWUoIiUoiEWEAApIDMLGoRCyWiKThenkwDgeGMiggDLEXQkDoTh
CKNLpQDgjeAsY7MHgECgx8YR8oHwNHfwADBACGh4EDA4iGAYAEBAcQIg0Dk
gcEIQA7" alt="File Icon"></html>

(data URI example from: http://dataurl.net/#about)

The <html>...</html> tells Twine to treat the code inside as raw HTML. The <img ...> is the HTML code for placing an image. The width="11" and height="14" code give the width and height of the image - you should change these to suit your image. The alt="..." code improves the accessibility of your file by giving a text alternative to your image. Most likely the code will work without a width, height or alt specified but it is considered good practise to include them if you can. The real magic happens inside src="...". That src is an abbreviation for "source" and normally that would link to an external file. Here we give it the data URI instead.

TIP: These data URIs can produce large walls of text that are annoying for you as an author to scroll past. What I suggest is to put all the image code into a different passage then use the <<display>> macro to.... ummm... yeah... display the image. This makes the image reusable anywhere in your story and keeps your text passages nice and tidy. Consider this abbreviated example... (:: Double colon is the passage title)

::Start
<<display "Image:Document Icon">>
This is my text and there is an image above.

::Image:Document Icon
<html><img ...></html>

Your Twine story can use both data URI images and normal "linked" images. And data URIs work just fine in CSS too; great for setting background patterns. (The thing in square brackets [] is a tag applied underneath the passage title).

::Stylesheet1 [stylesheet]
body {
  background-image:url(data:image/gif;base64,R0lGOD... etc );
}

You have the tool, go make something cool.