Ripper is a web-based application for extracting sprite sheets, tilesets, fonts, screen memory, and other graphics from data files, executables, or disk images. This first release targets the Atari and Commodore computers from the 16-bit era.
Ripper reads a stream of arbitrary binary data and decodes it as if were an image, rendering the result to a canvas. Ripper will read any file or disk/ROM image dump you give it. However, due to the storage restrictions of disks and ROMs, graphics are often stored in a compressed format, so you may not be able to extract the data you're interested in when working directly with these files.
Ripper works best when given a decompressed emulator save state, as these usually contain a complete dump of the machine memory at the point of save. If you can see the graphics on screen when you saved, you should be able to extract them with Ripper.
Planar graphics overview
In order to locate and extract graphics data, it’s important to know it’s stored. Let’s cover that now.
Ripper’s target platforms store their graphics in planar form, meaning images are stored as multiple layers of bits — or bitplanes — rather than the more common "chunky" format represented by interfaces like ImageData
where R, G, B and A channel values are stored as concurrent bytes of data.
Planar works a little like the screen printing process, where colour images are made up in layers by pushing ink through different stencils, except in the case where one ink would cover another, video hardware can replace it with a new, third colour.
To render a planar image, the video hardware reads a single bit from each of the individual bitplanes that make up an image. Each of these bits is merged together, creating a colour index, which is used to select a colour from a palette. The resulting colour is then drawn to the screen as a pixel. This process is repeated for each pixel on the screen.
The interactive demo below shows how this works. Try toggling different planes on and off to see the output:
The total number of colours stored in an image is determined by the number of planes (specifically, 2 ^ numberOfPlanes
). Therefore, a single plane image contains 2 colours. A two-plane image contains 4 colours, three planes contain 8 and so on, up to a maximum of eight planes holding 256 colours.
Ripper can be configured to decode between 1 and 8 bitplanes. It’s very common for files to contain graphics data that uses a mix of planes, so make sure you experiment with this setting.
NOTE: Setting planes to 1
is a useful way to find graphics data when you can’t determine which encoding method was used.
Decoding image data
The planar graphics principles hold true regardless of the hardware rendering the image. However, there are different ways to encode the layers of bits in planar data. The most common encoding methods are Word, Line, and Contiguous. Ripper can be configured to use any these encodings.
Typically, Word encoding is used by the Atari ST hardware, and Line/Contiguous are used by the Commodore Amiga. That said, developers tend to store their graphics in the format that best fits their drawing routines, so there are no concrete rules about which encoding method(s) you may end up using when extracting graphics.
Sprites and tilesets are often saved as a blob of raw data with no header describing the width, height, or plane count. This is usually because the application responsible for rendering the graphics already knows the format of the data it will be displaying. For this reason, Ripper has a Line Width setting, which will control when the decoder will start processing a new line.
Colour palettes
As mentioned above, during the decoding process, planar image bitplanes are combined to generate a palette index for each pixel. This palette is stored separately from the image data. Usually, you can find the colour palette data at a nearby memory address.
As with the image data, colour palettes can be stored in various different formats. However, these are closely tied to the hardware of the machine the graphics are intended to be displayed on. If you know which machine the data is for, you can configure Ripper to use the memory buffer for extracting palettes.
To aid palette discovery, Ripper has a search feature that uses simple hueristics to determine if a stream of bytes looks like a palette or not. You can use this to quickly find potential palette candidates.
The technical stuff
Ripper is a PWA built using AppKit, a toolkit I created for rapidly building web apps. It provides UI via Web Components and services for dealing with data binding, file system operations and notifications. AppKit also contains it’s own tooling, including rollup plugins to handle generating supporting files, such as the service worker and manifests.
Of the application code, the majority of the complexity is in the image processing. Reading and decoding the buffer is handled off the main thread using a web worker, with the resulting image rendered to an OffscreenCanvas
. Internally, the worker uses my open source imagedata-planar package to handle the planar decoding.
Note: An accompanying imagedata package can be used to do this processing outside a web browser.