Going to share this here as I've seen a few people ask in various threads, and honestly I've had to implement this a few times.
The bitmap data of an image or the display's frame buffer is encoded as 1 pixel per bit, in 32 bit values. It can be a bit tricky to work with and basically puts every bitwise operator to work.
Here are the ways you can get the data from an image:
LCDBitmap* bitmap = ...; uint8_t* bitmap_data = NULL; int bitmap_rowbytes = 0; playdate->graphics->getBitmapData(bitmap, NULL, NULL, &bitmap_rowbytes, NULL, &bitmap_data);
Or use the display's frame buffer:
uint8_t* bitmap_data = playdate->graphics->getFrame(); int display_rowbytes = LCD_ROWSIZE
Now here are the macros:
// Determine pixel at x, y is black or white. #define samplepixel(data, x, y, rowbytes) (((data[(y)*rowbytes+(x)/8] & (1 << (uint8_t)(7 - ((x) % 8)))) != 0) ? kColorWhite : kColorBlack) // Set the pixel at x, y to black. #define setpixel(data, x, y, rowbytes) (data[(y)*rowbytes+(x)/8] &= ~(1 << (uint8_t)(7 - ((x) % 8)))) // Set the pixel at x, y to white. #define clearpixel(data, x, y, rowbytes) (data[(y)*rowbytes+(x)/8] |= (1 << (uint8_t)(7 - ((x) % 8)))) // Set the pixel at x, y to the specified color. #define drawpixel(data, x, y, rowbytes, color) (((color) == kColorBlack) ? setpixel((data), (x), (y), (rowbytes)) : clearpixel((data), (x), (y), (rowbytes)))
That's it, just pass the appropriate bitmap_data and bitmap_rowbytes into these macros with the x, y you want to modify.
Keep in mind that these macros do not do bounds checking, so make sure the x, y is within bounds of the bitmap before using.