7.8.2. STBIMAGE-02 — Saving and Encoding Images

This tutorial covers saving images to files, encoding to in-memory byte arrays, loading from memory, and round-trip verification.

7.8.2.1. Saving to File

Image.save(path, quality) saves to file. The format is determined by the file extension (.png, .bmp, .tga, .jpg, .hdr). The quality parameter only matters for JPEG (1–100, default 90):

let (ok, error) = img.save("output.png")
let (ok2, _) = img.save("output.jpg", 75)  // JPEG quality 75

7.8.2.2. JPEG Quality

Lower quality values produce smaller files with more compression artifacts:

for (q in fixed_array(10, 50, 90)) {
    var buf : array<uint8>
    img.encode("jpg", buf, q)
    print("Quality {q}: {length(buf)} bytes\n")
}

7.8.2.3. Encoding to Memory

Image.encode(format, buf, quality) writes compressed image data into a byte array. The format is specified without a dot: "png", "bmp", "tga", "jpg":

var buf : array<uint8>
let (ok, error) = img.encode("png", buf)
print("Encoded {length(buf)} bytes\n")

7.8.2.4. Loading from Memory

Image.load_from_memory(buf) decodes an image from a byte array. Also available: load_hdr_from_memory(), load_16_from_memory():

var inscope img2 : Image
let (ok, error) = img2.load_from_memory(png_buf)

Format detection works from memory too:

print("HDR: {is_hdr_from_memory(buf)}\n")
print("16-bit: {is_16_bit_from_memory(buf)}\n")

7.8.2.5. Round-trip Verification

Lossless formats (PNG, BMP, TGA) preserve pixel values exactly through an encode/decode cycle:

var buf : array<uint8>
original.encode("png", buf)
var inscope decoded : Image
decoded.load_from_memory(buf)
// decoded pixels == original pixels