ECMAScript Embedded Bitmap Encoding

Search for a command to run...

No comments yet. Be the first to comment.
Hey hey people, I wrote a game recently for a certain coding competition, and thought I'd share the thought process behind it. Let's start with the Design King Thirteen is by far the most deliberately designed game I've made. It all began with a very...

An open mind is like a fortress with its gates unbarred and unguarded. This is the story of the Super Castle Game, a js13k game jam entry. Naturally, it begins with the theme of the 2023 edition of the compo: 13th Century. When it dropped, I was com...

An application talking to a language model API has control over the following parameters. Only the Vertex AI PaLM API allows setting Top-K and Top-P at the time of writing. Temperature The temperature (a floating-point number in the range 0.0–1.0) is...

So I was working on something very simple involving a CSV file: import csv with open('file.csv', 'r') as f: reader = csv.reader(f) lines = [ln for ln in reader] And as one would expect, the result of running this code was Error: field large...

Old computer fonts are fascinating. Making a consistent-looking font is a remarkable achievement in its own right, but designing a monospaced font that is readable on a very low-resolution screen, is aesthetically pleasing, and has a distinct persona...

I propose the following bitmap format, suitable for embedding small images in TypeScript or JavaScript source code:
// ECMAScript Embedded Bitmap Encoding (EEBE)
// Required fields:
export const lines = [
0b0001000,
0b0111000,
0b1101000,
0b1001000,
0b0001000,
0b0001110,
0b0001111,
0b0001111,
0b0000110,
]
export const width = 7
export const bpp = 1
// Optional fields:
export const palette = [
0x000,
0xfff,
]
Let's call it ECMAScript Embedded Bitmap Encoding (EEBE). EEBE is a format used to store bitmap images within ECMAScript code in an efficient manner. It is designed to be compact and easy to parse, suitable for scenarios with hard size constraints such as js13kGames, and isn't at all intended to be a general purpose image format.
An EEBE file is an ECMAScript module that exports the following fields:
lines: an array of integers, each representing a scanline of the image. Each integer is a bitfield of size width * bpp, with the least significant bit(s) representing the leftmost pixel of the scanline.
width: the width of the image in pixels.
bpp: the number of bits per pixel.
palette: an optional array of integers, each representing a color. The number of colors in the palette should equal 2 ** bpp. Nullish values are treated as transparent. If this field is omitted, the rendering is implementation-defined.
Any other fields, depending on the implementation.
Optimized for size, the above example is 116 bytes long (99 bytes gzipped) and produces the following image:
// This is the same example as above, written in a compact form.
export const lines=[8,56,104,72,8,14,15,15,6]
export const width=7
export const bpp=1
export const palette=[0,4095]
The footprint can be further reduced during build:
export statements.It's also possible to save bytes by using 12-bit color (#9d5 instead of #99dd55) and sharing the palette between multiple images.
An EEBE image can be decoded as follows:
function readBitmap(lines, width, bpp, readFunction) {
const shift = 1 << bpp
for (let y = 0; y < lines.length; ++y) {
for (let x = 0; x < width; ++x) {
const value = lines[y] / shift ** x & shift - 1
readFunction(x, y, value)
}
}
}
(This function is available in natlib.)
For each pixel in the image, the readFunction(x, y, value) is invoked. The pixel's value is an integer in the range [0, 2 ** bpp - 1] that can be used to retrieve the corresponding color from the palette.
You might be wondering why the readBitmap function uses the division operator instead of a << bit shift. It's because the bitwise operations in JS truncate their operands to 32 bits, whereas the Number type is a 64-bit floating point, allowing for integer values of up to 53 bits. So the tradeoff here is that we can either
<< bit shift operator, but only get 32 bits of stride.I've used this format in my js13kGames entries, including The Neatness, with good results.
It's clear that variations of this — storing bitmaps as int[] — have been in use since at least ZX Spectrum days. The motivation for writing this short spec and giving EEBE its name is to promote interoperability, not to claim originality.
Absolutely none of these questions have been asked.
You can include extra fields. For example, in The Neatness levels contain hotspots (entry and exit points) in addition to the level geometry represented by the bitmap.
It's in the planning phase.
Try [jebi].
To gather intelligence. It was a Chinese surveillance chicken.