Hello everyone,
for a little project I'm using nimPNG to manipulate the pixels of a PNG image. Loading a pixel with loadPNG24 makes the pixels accessible as seq[char], where the RGB-triplets are stored consecutively. Now I want to pack an RGB-triplet into an uint using the following scheme:
[Padding with 0s][R-byte][G-byte][B-byte]
^ ^
HSB LSB
Using shifting works good so far:
for i in countup(0, len(image.data)-1, 3):
packed = image[i].uint shl 16 or image[i+1].uint shl 8 or image[i+2].uint
result.add(packed)
However, the image.data[i..i+2] already stores the bits in right order without the padding from the aforementioned scheme. Is it therefore possible to cast such a slice directly into an uint8 by knowing that three chars will always fit?
Sure is. But you have to handle endianness, as x86_64 is a little endian architecture and data returned by nimPNG is stored in big endian order.
import strutils
let pixels = @[uint8 0, 0, 255, 0, 255, 255, 255, 0, 0]
var arrayPixel: array[4, uint8]
copyMem(arrayPixel[1].addr, pixels[0].unsafeAddr, 3 * sizeof(pixels[0]))
var u32Pixel = cast[ptr uint32](arrayPixel[0].addr)[]
echo u32Pixel.toHex # → FF000000 - wrong result! we need to handle endianness
import endians
var u32PixelLE: uint32
# convert big endian → native endian
bigEndian32(u32PixelLE.addr, u32Pixel.addr)
echo u32PixelLE.toHex