🎉 NEW: Added support for Micropython & CircuitPython (bytearray)! Also new Brightness, Contrast adjustments and design improvements.

image2cpp - Image to C Array Converter (Mono and Color)

image2cpp (LCD Assistant) is a free online tool that turns an image into a C array or byte array, and turns an existing array back into an image. It covers both kinds of display used in Arduino, ESP32 and Raspberry Pi projects: 1 bit monochrome for SSD1306 / SH1106 OLEDs and the Nokia 5110, and RGB565 or RGB888 color for ST7735, ST7789, ILI9341 and ILI9488 TFT panels. Output as Adafruit GFX, U8g2, plain bytes or MicroPython / CircuitPython.

1. Select image

All operations are performed locally in your browser; your photos are not uploaded or stored anywhere online.

or

1. Paste plain byte array


x px
Read images appear at step 3 below

2. Image Settings

    Only images file type are allowed
    No files selected
    100%
    100%
    0 - 255; if the brightness of a pixel is above the given level the pixel becomes white, otherwise they become black. When using alpha, opaque and transparent are used instead.
    Centering the image only works when using a canvas larger than the original image.

    3. Preview

    No files selected

    4. Output

    Generates output in bytearray format for Micropython and CircuitPython.
    This oled_example adds some extra Arduino code around the output to easily copy and paste it. If multiple images are uploaded, it creates a byte array for each one and adds a counter to the identifier.
    Adds some extra Arduino code around the output for easy copy-paste. If multiple images are loaded, generates a single byte array.
    Creates a GFXbitmapFont formatted output. Used by a modified version of the Adafruit GFX library. GitHub project and example bitmap-font
    First ASCII character value is used only if a glyph identifier of length equal to 1 is not provided for each image. The value itself will be incremented by 1 for each glyph.

    If your image looks all messed up on your display, like the image below, try using a different mode.

    info image
    Useful when working with the u8g2 library.

    Which output format should I use?

    The draw mode decides how pixels are packed into bytes. Pick it by display controller, not by taste, or the picture will come out sliced or mirrored.

    Draw modeBytes / pixelTypical displaysDraw call
    Mono, horizontal1 bitSSD1306, SH1106, SSD1309 OLEDdrawBitmap() / drawXBM()
    Mono, vertical1 bitNokia 5110 (PCD8544), SSD1306 page moderaw buffer write
    Color RGB5652 bytesST7735, ST7789, ILI9341, ILI9488, GC9A01drawRGBBitmap() / pushImage()
    Alpha mask1 bitany, as a transparency mask beside a color bitmapmasked blit
    Color RGB8883 bytes24 bit framebuffers, ESP32 RGB LCD panelspanel driver
    Color HSV3 bytesLED matrices, effects that shift hue at runtimecustom

    Using the array in your sketch

    Monochrome OLED, Adafruit SSD1306:

    #include <Adafruit_SSD1306.h>
    Adafruit_SSD1306 display(128, 64, &Wire, -1);
    
    // paste the array from the Output box above
    const unsigned char myBitmap [] PROGMEM = { /* ... */ };
    
    void setup() {
      display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
      display.clearDisplay();
      display.drawBitmap(0, 0, myBitmap, 128, 64, SSD1306_WHITE);
      display.display();
    }

    Monochrome with U8g2 (XBM byte order):

    u8g2.firstPage();
    do {
      u8g2.drawXBMP(0, 0, 128, 64, myBitmap);
    } while (u8g2.nextPage());

    Color RGB565 on an ST7735 / ILI9341, Adafruit GFX:

    #include <Adafruit_ILI9341.h>
    
    // RGB565 output: 2 bytes per pixel, so uint16_t not unsigned char
    const uint16_t myImage [] PROGMEM = { /* ... */ };
    
    tft.drawRGBBitmap(0, 0, myImage, 160, 128);

    Color RGB565 with TFT_eSPI (faster, ESP32 friendly):

    #include <TFT_eSPI.h>
    TFT_eSPI tft = TFT_eSPI();
    
    tft.setSwapBytes(true);            // drop this line if colors look inverted
    tft.pushImage(0, 0, 160, 128, myImage);

    How much memory will it cost?

    A 1 bit bitmap needs width / 8 * height bytes. An RGB565 bitmap needs width * height * 2. That gap decides which board you can use:

    • 128x64 monochrome OLED: 1,024 bytes. Fits in an Arduino Uno's flash without thinking about it.
    • 160x128 RGB565 (ST7735): 40,960 bytes. Already larger than the Uno's entire 32 KB flash. Use an ESP32, an RP2040, or stream it from an SD card.
    • 320x240 RGB565 (ILI9341): 153,600 bytes. ESP32 or SD card only.

    If a color image will not fit, convert it to 1 bit with Floyd-Steinberg dithering instead. On a small panel the dithered version usually reads better than a heavily downscaled color one.

    Frequently asked questions

    Does image2cpp support color images?

    Yes. Besides the classic 1 bit per pixel monochrome mode, this converter exports RGB565 (2 bytes per pixel), RGB888 (3 bytes per pixel) and HSV arrays. Choose the draw mode Color RGB565 - 2 bytes per pixel to get an array you can push straight to an ST7735, ST7789, ILI9341 or ILI9488 TFT.

    What is RGB565 and why 2 bytes per pixel?

    RGB565 packs a color into 16 bits: 5 bits red, 6 bits green, 5 bits blue. Green gets the extra bit because the eye is most sensitive to it. That is 65,536 colors in half the memory of 24 bit RGB888, which is why nearly every small TFT driver and framebuffer on Arduino and ESP32 uses it.

    How do I display the array on an SSD1306 128x64 OLED?

    Set the canvas to 128x64, choose the mono horizontal draw mode and the Adafruit GFX output format, then call display.drawBitmap(0, 0, myBitmap, 128, 64, SSD1306_WHITE) followed by display.display().

    Horizontal or vertical byte order?

    Horizontal for Adafruit GFX drawBitmap and U8g2 drawXBM, which covers most SSD1306 and SH1106 code. Vertical for page addressed drivers such as the Nokia 5110 (PCD8544) and raw SSD1306 page buffers. If the image comes out cut into horizontal stripes, you picked the wrong one.

    Why does my bitmap look scrambled or skewed?

    Almost always a width mismatch. The array width has to match the width you pass to drawBitmap, and for 1 bit modes it should be a multiple of 8, otherwise every row is padded and the picture shears diagonally. Check byte order second, and setSwapBytes() third if you are on RGB565 and the colors look wrong rather than the shape.

    Adafruit GFX or U8g2 output, what is the difference?

    Adafruit GFX expects a PROGMEM byte array drawn with drawBitmap, where a 1 bit means an on pixel. U8g2 uses XBM ordering with drawXBM, where the bits inside each byte are reversed. Picking the wrong one mirrors every group of 8 pixels.

    Can I turn a C array back into an image?

    Yes. Paste an existing byte array into the Paste plain byte array box, set the right width, height and draw mode, and the preview renders it back as a picture. Handy for checking a bitmap you inherited from someone else's sketch.

    Can I convert an animated GIF?

    Not here. This converter reads a single still frame, because it draws the file into an HTML canvas and a canvas holds one frame at a time. Hand it an animated GIF and you get frame one only. For animations use the GIF to OLED animation converter, which parses the GIF format directly and returns every frame as its own array plus a ready sketch that loops through them.

    What image size should I use?

    Match the display: 128x64 or 128x32 for common SSD1306 OLEDs, 84x48 for Nokia 5110, 160x128 for ST7735, 240x240 for GC9A01 round panels, 320x240 for ILI9341.

    Related tools