7.8.4. STBIMAGE-04 — Pixel Access and Format Conversion
This tutorial covers reading and modifying pixel data, row-level access, and converting between channel counts and bit depths.
7.8.4.1. Reading Pixels
with_pixels() gives a temporary mutable array view of pixel data.
Since there are three overloads (uint8, float, uint16), you must specify
the block parameter type explicitly:
img |> with_pixels() <| $(var pixels : array<uint8>#) {
let r = int(pixels[0])
let g = int(pixels[1])
print("R={r} G={g}\n")
}
For float and 16-bit access, use with_pixels_f() and
with_pixels_16() — these require the image to have the matching
bpc (4 for float, 2 for uint16).
7.8.4.2. Row-level Access
with_row(y, block) gives access to a single row — more efficient
when you only need one row at a time:
img |> with_row(4) <| $(var row : array<uint8>#) {
print("Row 4 has {length(row)} bytes\n")
}
with_row_f() provides float access (requires bpc=4).
with_row_16() provides uint16 access (requires bpc=2).
7.8.4.3. Modifying Pixels
The pixel arrays are mutable — changes are written directly back to the image data:
img |> with_pixels() <| $(var pixels : array<uint8>#) {
for (i in range(width * height)) {
pixels[i * 4 + 0] = uint8(255 - int(pixels[i * 4 + 0]))
}
}
7.8.4.4. Channel Conversion
Image.to_channels(n) returns a new image with the specified number
of channels:
From |
To |
Behavior |
|---|---|---|
4 (RGBA) |
3 (RGB) |
Drop alpha |
3 (RGB) |
4 (RGBA) |
Add alpha = 255 |
3 or 4 |
1 (grey) |
ITU-R BT.601 luminance |
1 (grey) |
3 or 4 |
Grey replicated to RGB(A) |
1 or 4 |
2 (grey+A) |
Add/keep alpha |
2 (grey+A) |
1 or 4 |
Extract/expand |
var inscope rgb <- rgba_img.to_channels(3) // drop alpha
var inscope grey <- rgb.to_channels(1) // to greyscale
var inscope back <- grey.to_channels(4) // grey → RGBA
7.8.4.5. BPC Conversion
Image.to_bpc(n) converts bytes-per-component:
bpc |
Type |
Range |
|---|---|---|
1 |
uint8 |
0–255 |
2 |
uint16 |
0–65535 |
4 |
float |
0.0–1.0 |
Conversions preserve visual values: uint8(255) → uint16(65535) →
float(1.0):
var inscope hdr <- img.to_bpc(4) // uint8 → float
var inscope img16 <- hdr.to_bpc(2) // float → uint16
var inscope back <- img16.to_bpc(1) // uint16 → uint8
7.8.4.6. Combined Conversions
Channel and BPC conversions can be chained. Convert BPC first for higher precision, then channels:
// RGBA uint8 → RGB float (HDR pipeline input)
var inscope hdr_rgb <- img.to_bpc(4).to_channels(3)
// Greyscale uint16 (scientific imaging)
var inscope grey16 <- img.to_channels(1).to_bpc(2)
See also
Full source: tutorials/dasStbImage/04_pixel_access_and_conversion.das
Next tutorial: STBIMAGE-05 — Drawing and Alpha Blending