stb_image
| Language | C (usable from C++) |
|---|---|
| License | public domain or MIT, your choice |
| Repository | github.com/nothings/stb |
| Documentation | comments at the top of stb_image.h and stb_image_write.h |
| Depends on | nothing |
| Read / write | yes, uncompressed 1, 4, 8, 16, 24 and 32-bit, bit fields; no RLE / yes, 24-bit, or 32-bit with alpha |
stb_image.h loads BMP, PNG, JPEG, TGA, GIF, PSD, HDR, PIC and PNM files into a plain pixel buffer; stb_image_write.h writes BMP, PNG, TGA, JPEG and HDR. Each is one header file with no dependencies, which makes them popular for games, graphics demos and tools.
For BMP, the loader converts palette, 16-bit and BGR data to tightly packed RGB or RGBA, top row first, so you don’t deal with row padding or bottom-up order. It reads the 12, 40, 56, 108 and 124-byte headers, but not RLE4 and RLE8 compression or the 64-byte OS/2 2.x header. The writer produces 24-bit files with a 40-byte header, or 32-bit files with a V4 header and alpha mask when you pass 4 channels. Don’t use the loader on untrusted files in security-sensitive code.
Installation#
Copy stb_image.h (and stb_image_write.h to save) into your project. In exactly one .c or .cpp file, define the implementation macros before the includes:
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
Other files include the headers without the macros. It’s also available as vcpkg install stb.
Basic usage: load and save a BMP#
#include "stb_image.h"
#include "stb_image_write.h"
#include <stdio.h>
int main(void) {
int w, h, channels;
// last argument 3: always return RGB; 0 keeps the file's channel count
unsigned char *pixels = stbi_load("in.bmp", &w, &h, &channels, 3);
if (!pixels) {
printf("load failed: %s\n", stbi_failure_reason());
return 1;
}
printf("%d x %d, %d channels in file\n", w, h, channels);
// invert colors
for (int i = 0; i < w * h * 3; i++) {
pixels[i] = 255 - pixels[i];
}
if (!stbi_write_bmp("out.bmp", w, h, 3, pixels)) {
printf("write failed\n");
}
stbi_image_free(pixels);
return 0;
}
How to get BMP width and height without decoding#
int w, h, channels;
if (stbi_info("in.bmp", &w, &h, &channels)) {
printf("%d x %d, %d channels\n", w, h, channels);
}
How to write a 32-bit BMP with alpha#
Pass 4 channels (RGBA). stb_image_write stores them as a 32-bit BI_BITFIELDS BMP with a V4 header and an alpha mask:
// rgba: w * h * 4 bytes, top row first
stbi_write_bmp("alpha.bmp", w, h, 4, rgba);
Many programs ignore alpha in BMP files. Use PNG if transparency matters.
How to convert BMP to PNG#
int w, h, n;
unsigned char *pixels = stbi_load("in.bmp", &w, &h, &n, 0);
if (pixels) {
stbi_write_png("out.png", w, h, n, pixels, w * n); // stride: bytes per row
stbi_image_free(pixels);
}
How to write a BMP to memory#
stbi_write_bmp_to_func calls your function with chunks of the encoded file:
#include <stdlib.h>
#include <string.h>
typedef struct { unsigned char *data; size_t size; } Buffer;
static void append(void *context, void *data, int size) {
Buffer *b = context;
b->data = realloc(b->data, b->size + size);
memcpy(b->data + b->size, data, size);
b->size += size;
}
Buffer buf = {0};
stbi_write_bmp_to_func(append, &buf, w, h, 3, pixels);
// buf.data holds buf.size bytes of BMP file
free(buf.data);
Tips#
- Define
STBI_ONLY_BMPbefore the implementation include to compile only the BMP decoder. - For OpenGL textures, which expect the bottom row first, call
stbi_set_flip_vertically_on_load(1). stbi_write_bmpignores row stride: pass a tightly packed buffer.