The "bmp" library is a library for the express purpose of reading and writing Windows BMP files and other Windows DIB headers. It is written with portability, memory-efficiency, and reusability as it's primary goals. With this in mind, it can be used as the backend for an ICO/CUR handling library, works with packed-DIB data, only requires the first 0x36 bytes of a .BMP to be present, and can be used on KittenOS NEO, OpenOS, and just about any place with a desktop Lua interpreter available for use. (That said, it's not 5.1-tested.) That said, it does not handle all the possible bitmap formats, restricting itself to support of BI_RGB where possible, and BI_BITFIELDS to a limited extent. Given this covers most bitmaps that you are likely to generate, do not underestimate the use of this. The library has 2 fields: headerMinSzBMP, headerMinSzDIB: The minimum data you must have available when calling connect for a given format. The library has 3 functions: connect(get, set, cMode, packed): "Connects" to a bitmap. A very real implication of this is that the data get/set accesses is where the actual bitmap is, and this merely provides a way to access it in a useful form (as pixels). Technically, all but 'get' are optional, but I feel it necessary to document them as if they are implicitly left nil by those users who omit them because of their functionality. Due to this section being a rather long length, the paragraph separation is per-argument here. get is best described by: function (a) return dt:byte(a) end set, which is optional unless you call any of the set* functions in the resulting bitmap, has a longer description: function (a, v) dt = dt:sub(1, a - 1) .. string.char(v) .. dt:sub(a + 1) end Notably, while these are the canonical implementations of these functions, they are by no means the only implementations, and it is the purpose of these callbacks to allow choice in how you write them. cMode exists for cursor and icon handling. These images are split via a very horrifying mechanism into an AND mask, and a XOR mask. The XOR mask typically contains what could be called the actual image - the AND mask then acts as a sort of alpha mask, blacking out the areas where the XOR mask is then projected onto. It can be one of three values. It can be nil, in which case this is an ordinary DIB, with no evil nonsense applied to it - It can be "colour", in which case the XOR mask (the actual image in most cases) is shown - And it can be "mask", in which case the AND mask is accessed instead. (Notably, bpp, paletteSize, and ignoresPalette changes to the 1bpp mask format in use here.) packed exists for the use of those bitmaps that don't have a BMP file header, the usual "BM". In this case, you can remove support for gap1 but allow yourself to avoid the BM header as a result. If not nil, it is how much to offset the indexes from 0-based offsets into a .BMP file to the final positions. The following table is useful for understanding this: 1: Standard 1-indexed BMP handling, but with no gap1 support (!) -13: Standard 1-indexed handling of a packed DIB (no BMP header), such as a BITMAP or ICON resource (set cMode if ICON) -9: Standard 1-indexed handling of a CURSOR resource, which has a 2-short hotspot header prepareDIB(w, h, p, bpp, paletteSize , topDown, cMode) -> hd, sz, dp: (See prepareBMP if you want a .BMP file, but this describes how to use the arguments and returns.) This prepares a packed DIB, and returns three values: 1. The header. (The palette, in the 4-byte-per-colour form, will follow immediately.) 2. The buffer size, including the header in 1. The bytes that are not specified can be initialized in any fashion, as they are part of the colour and later image data itself. 3. The pointer to the pixels for BM creation. w, h, p, and bpp are the usual - width, height, planes, pixel depth - but the paletteSize needs note. If the BPP is <= 8, then the size of the palette must not be 0. This is to avoid unintentionally triggering legacy features in the BMP format. topDown and cMode are essentially booleans that can safely be nil, where nil is interpreted as false. topDown indicates that the image is to be top-down rather than the standard upsidedown form of a BMP. This may look odd if streaming a BMP, so the option, while rather an odd one, has been included. cMode indicates that this image is intended for use in an ICON or CURSOR resource of some form, and should thus contain an AND mask. prepareBMP(...): This prepares a .BMP file. It has the same arguments and returns as prepareDIB, and indeed wraps it. Bitmap objects, while not read-only, do not particularly change if you write to them. Going out of bounds with a bitmap object will have hilarious results. ...Don't do it. Anyway, they have these fields: width, height, planes: The usuals. (NOTE: Due to lack of examples, it is assumed that planes are a dimension more major than height. If this isn't the case, someone do tell me, preferably with an example and a way to open it that does not involve this library, so I can test and correct all of the code involving them.) bpp: Bits per pixel. This specifies a limit on numbers passed to and from the bitmap object, of 1 << bpp (2 ^ bpp). A number may not be equal to or exceed this limit. ignoresPalette: Used to indicate the palette is worthless and does not affect image contents in any way at all. If one exists. paletteCol: The amount of colours in the palette. Multiply by 4 for a byte count. paletteAddress: Useful for caching, the palette starts at this get/set address. dataAddress: Useful for caching, the data starts at this get/set address. dataFull: The size of the data of the image, according to the image. dsSpan: This is a hint for the cache and cannot be relied upon to be correct, only >= 1: Scanline length in bytes. dsPlane: This is a hint for the cache and cannot be relied upon to be correct, only >= 1: Plane length in bytes. getPalette(i): Gets the XRGB value of colour i as an integer. Do not go out of range of I. setPalette(i, v): Sets the XRGB value of colour i as an integer. Do not go out of range of I or V. getPixel(x, y, p): Returns the pixel value at X, Y, P. Do not go out of the range of X, Y or P. setPixel(x, y, p, v): Sets the pixel value at X, Y, P to V. Do not go out of the range of X, Y, P, or V. ...in other words, about as much usability as a BufferedImage with getGraphics and createGraphics taken out of it for some crazy reason. The primary use of this library is because people like to use formats they happen to have actually heard of before, and everything but BMP is too complicated for low-memory OSes to stream from disk. -- This is released into the public domain. -- No warranty is provided, implied or otherwise.