Convert a picture into a C byte array ready for an embedded display. Pick the screen size, choose monochrome with threshold and dithering, grayscale, RGB565 or RGB888, and see exactly what the display will show before you copy the code.
Last updated:
Converted preview
Advertisement
Advertisement
How to use the Image to C Array
Drop an image, choose one, or paste it with Ctrl+V. A sample is loaded so you can try the settings first.
Pick the display size from the presets or type a custom width and height, then choose how the image is scaled.
Choose the color format your driver expects: monochrome for most OLEDs, RGB565 for color TFTs.
Tune the result with the threshold, dithering, invert and byte layout while watching the preview.
Copy the array or download the .h file and draw it with your display library.
Color formats and memory use
Format
Bits per pixel
128 × 64
240 × 240
Typical displays
Monochrome 1-bit
1
1,024 B
7,200 B
SSD1306, SH1106, PCD8544 (Nokia 5110), e-paper
Grayscale 4-bit
4
4,096 B
28,800 B
SSD1322, SSD1327 grayscale OLEDs
Grayscale 8-bit / RGB332
8
8,192 B
57,600 B
Sprites with 8-bit palettes, LVGL L8
RGB565
16
16,384 B
115,200 B
ILI9341, ST7735, ST7789, GC9A01, SSD1351
RGB888
24
24,576 B
172,800 B
Desktop frame buffers, LED matrices, image processing
An Arduino Uno has 32 KB of flash, so a full-screen 128 × 64 monochrome image fits easily but a 240 × 240 RGB565 image (112.5 KB) needs a board such as an ESP32 or RP2040.
Drawing the array
// Adafruit SSD1306 / GFX: horizontal, MSB first
display.drawBitmap(0, 0, image, IMAGE_WIDTH, IMAGE_HEIGHT, SSD1306_WHITE);
display.display();
// u8g2: horizontal, LSB first (XBM)
u8g2.drawXBMP(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, image);
// TFT_eSPI: RGB565 as uint16_t words
tft.pushImage(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, image);
Tips for crisp results
Design at the final size. Scaling a large photo down to 128 × 64 loses detail; text and icons drawn at the display's exact resolution stay sharp.
Check the preview at zoom: it shows exactly the pixels that will be lit, including dithering patterns and the padding added when the width is not a multiple of 8.
Transparent PNGs are placed on black or white first; choose the one that matches your screen's background.
Colors look wrong on a TFT? If red and blue are swapped, the panel is in BGR mode; if colors look noisy, try the byte-swapped (big-endian) RGB565 option or your library's setSwapBytes().
Frequently asked questions
Which byte layout does my OLED library need?
Adafruit GFX drawBitmap() expects horizontal rows, most significant bit first, each row padded to a whole byte. u8g2 drawXBM() expects horizontal rows with the least significant bit first (XBM format). Writing straight into an SSD1306 or SH1106 frame buffer needs vertical pages: each byte is a column of 8 pixels with bit 0 at the top.
What is RGB565?
RGB565 packs a color into 16 bits: 5 bits of red, 6 of green and 5 of blue, computed as ((R & 0xF8) << 8) | ((G & 0xFC) << 3) | (B >> 3). It is the native format of most SPI TFT controllers such as the ILI9341, ST7735 and ST7789. Libraries like TFT_eSPI and Adafruit GFX's drawRGBBitmap() take uint16_t arrays; some DMA routines need the two bytes swapped (big-endian).
How big will the array be?
A monochrome image needs width × height ÷ 8 bytes, so a 128 × 64 OLED screen is 1,024 bytes. 4-bit grayscale needs half a byte per pixel, RGB332 and 8-bit grayscale one byte, RGB565 two bytes and RGB888 three bytes per pixel, so a 240 × 240 RGB565 image is 115,200 bytes.
When should I use dithering?
Use dithering for photos, gradients and shaded logos on 1-bit screens: it simulates gray levels with patterns of dots. Floyd–Steinberg gives the smoothest result, Atkinson keeps more contrast, and ordered (Bayer) dithering gives a regular pattern that looks good on small displays. For text, icons and line art, plain thresholding is sharper.
What does the threshold do?
Each pixel's brightness is calculated as 0.299 R + 0.587 G + 0.114 B (0 to 255). Pixels at or above the threshold become 1 (lit) and darker pixels become 0. Lower the threshold to light up more pixels, raise it for fewer, or tick Invert to swap them.
Do I need PROGMEM?
On AVR boards such as the Arduino Uno or Nano, yes: without PROGMEM a constant array is copied into the 2 KB of RAM at startup. Libraries like Adafruit GFX read PROGMEM bitmaps with pgm_read_byte(). On ESP32, ESP8266, RP2040 and ARM boards const data stays in flash anyway, and PROGMEM is defined as empty for compatibility.
Is my image uploaded?
No. The image is decoded, scaled and converted with the canvas API in your browser, and the code is generated on your device.
Are all the tools on FreeToolCabin tested for quality and accuracy?
Yes! Every tool on our site undergoes automated Q/A testing in real browser environments to ensure high precision, correct output, and zero errors. If you happen to spot a bug or have a suggestion, please contact us at [email protected] and our team will review it right away.