Simple reading and writing of SDR & HDR image files.
|
|
||
|---|---|---|
| avif | Excelsior! | |
| exr | Excelsior! | |
| stb | Excelsior! | |
| .gitignore | Excelsior! | |
| CMakeLists.txt | Excelsior! | |
| lab_texture.cpp | Excelsior! | |
| lab_texture.h | Excelsior! | |
| LabTextureConfig.cmake.in | Excelsior! | |
| README.md | Excelsior! | |
LabTexture
A minimal image loading and saving library with a single C header and a LabTexture struct that supports 8-bit, 16-bit float, and 32-bit float pixel formats.
Supported Formats
Reading
| Format | Extensions | Backend | Output Format |
|---|---|---|---|
| OpenEXR | .exr |
OpenEXRCore | F16 |
| AVIF | .avif |
libavif + aom | F16 (RGBA) |
| PFM | .pfm |
custom | F32 |
| PNG | .png |
stb_image | U8 (RGBA) |
| JPEG | .jpg |
stb_image | U8 (RGBA) |
| TGA | .tga |
stb_image | U8 (RGBA) |
| BMP | .bmp |
stb_image | U8 (RGBA) |
| HDR | .hdr |
stb_image | U8 (RGBA) |
| PSD | .psd |
stb_image | U8 (RGBA) |
| GIF | .gif |
stb_image | U8 (RGBA) |
| PIC | .pic |
stb_image | U8 (RGBA) |
| PNM | .ppm |
stb_image | U8 (RGBA) |
All formats loaded via stb_image are decoded as 8-bit RGBA. EXR, AVIF, and PFM
preserve their native floating-point data.
Writing
| Format | Extensions | Backend | Input Format | Notes |
|---|---|---|---|---|
| OpenEXR | .exr |
OpenEXRCore (nanoexr) | U8, F16, F32 | No conversion; native EXR type |
| PNG | .png |
stb_image_write | U8 | Lossless, up to 4 channels |
| JPEG | .jpg |
stb_image_write | U8 | 85% quality default |
| TGA | .tga |
stb_image_write | U8 | With RLE compression |
| BMP | .bmp |
stb_image_write | U8 | Uncompressed |
| HDR | .hdr |
stb_image_write | F32 | Radiance RGBE format |
Pixel format conversion on write:
- EXR passes the source format through natively (
U8→UINT,F16→HALF,F32→FLOAT) with no allocation. - HDR converts
U8/F16toF32in a temporary buffer. - PNG / JPEG / TGA / BMP convert
F16/F32toU8(clamped 0–255) in a temporary buffer.
Usage
#include "LabTexture/lab_texture.h"// Load an image
LabTexture texture;
LabTextureResult result = lt_LoadImage("texture.png", &texture);
if (result != LabTextureOk) {
// handle result codes here
// ...
}
// Use the texture data (e.g., texture.pixels_i8, texture.width, etc.)
// ...
// Save to a different format
result = lt_SaveImage("texture.exr", &texture);
// Release allocated memory
lt_ReleaseImage(&texture);
Passing NULL as the LabTexture* argument to lt_LoadImage tests whether the
file is loadable at the same cost as actually loading it.
Result Codes
| Code | Meaning |
|---|---|
LabTextureOk |
Success |
LabTextureInvalidParam |
NULL pointer or degenerate image |
LabTextureFileNotFound |
Path exists but file not found |
LabTextureFileNotRead |
Generic read/write failure |
LabTextureFileInvalid |
File header or dimensions are odd |
LabTextureWriteFormatNotSupported |
Extension not recognized by the writer |
LabTextureWriteFormatNotCompatible |
Source format incompatible with target |
Build & Install
cmake -B build
cmake --build build
cmake --install build --prefix /usr/local
Consumers use it via find_package:
find_package(LabTexture REQUIRED)target_link_libraries(my_app LabTexture::LabTexture)LICENSE
The OpenEXR code:
// SPDX-License-Identifier: BSD-3-Clause
The AVIF library:
// SPDX-License-Identifier: BSD-2-Clause
stb_image / stb_image_write:
/* public domain — no warranty implied; use at your own risk */
All other code in this library not otherwise marked is
// Copyright 2026 Nick Porcino
// SPDX-License-Identifier: BSD-2-Clause