← All articles · April 15, 2026 · pixel.hjlabs.in · Powered by image2cpp

SSD1306 OLED Bitmap Tutorial: Display Images on 128x64

The SSD1306 0.96-inch I2C OLED is the most common display in the maker world — cheap, crisp, and supported by every microcontroller. This tutorial walks you from a freshly-wired panel to a custom logo on screen, using the Adafruit_SSD1306 library and image2cpp.

Hardware: the four wires

Almost every SSD1306 module sold today is the I2C variant with a fixed address (0x3C or rarely 0x3D):

OLED PinArduino UnoESP32RP2040 Pico
VCC5V (or 3.3V)3V33V3 (pin 36)
GNDGNDGNDGND
SCLA5GPIO22GP5
SDAA4GPIO21GP4

If you bought the SPI version (7 pins instead of 4), the wiring is different and you must use the SPI constructor of Adafruit_SSD1306.

Software: install the libraries

In the Arduino IDE Library Manager install both:

For PlatformIO, add to platformio.ini:

lib_deps =
  adafruit/Adafruit SSD1306@^2.5.13
  adafruit/Adafruit GFX Library@^1.11.11

The "Hello, OLED" sketch

Verify your wiring works before going further:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup() {
  Serial.begin(115200);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 init failed"));
    for (;;);
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 16);
  display.println(F("Hello"));
  display.println(F("OLED"));
  display.display();
}
void loop() {}

If you see "Hello / OLED" the panel is alive. If not, the most common bugs are: wrong I2C address (try 0x3D), reversed SDA/SCL, or 5V on a 3.3V-only module.

Convert your image with image2cpp

Now the interesting part — replacing text with a custom bitmap:

  1. Open pixel.hjlabs.in/converter
  2. Drop in a PNG (we recommend a 128x64 black/white PNG with thick lines)
  3. Set Canvas size: 128 x 64
  4. Set Background: white, Brightness threshold: 128 (or enable Floyd–Steinberg dithering)
  5. Output format: "Arduino code, Horizontal, 1 bit per pixel"
  6. Click "Generate code", copy the array

You'll get something like a const unsigned char myBitmap [] PROGMEM declaration with 1024 bytes (128x64/8).

Display the bitmap

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(128, 64, &Wire, -1);

// Paste your image2cpp output here:
const unsigned char myLogo [] PROGMEM = {
  // 1024 bytes
};

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.drawBitmap(0, 0, myLogo, 128, 64, SSD1306_WHITE);
  display.display();
}

void loop() {}

Drawing only part of the screen

Sometimes you want a 32x32 icon at a specific position, with text alongside:

display.clearDisplay();
display.drawBitmap(0, 0, iconWifi, 32, 32, SSD1306_WHITE);  // 32x32 at top-left
display.setCursor(40, 10);
display.setTextSize(2);
display.print(F("Online"));
display.display();

The signature is drawBitmap(x, y, bitmap, w, h, color)w and h are pixel dimensions, not bytes.

Inverted bitmaps and XOR drawing

To invert a bitmap (white becomes black, useful for "selected" UI states), pass SSD1306_BLACK as color:

display.drawBitmap(0, 0, myLogo, 128, 64, SSD1306_BLACK);  // inverted

For XOR drawing (toggle pixels) the Adafruit library exposes display.drawBitmap(x, y, bitmap, w, h, fg, bg) — the 7-argument form forces both colors instead of leaving "off" pixels untouched.

Splash screen on boot

Show a logo for 2 seconds before the main UI takes over:

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.drawBitmap(0, 0, splashLogo, 128, 64, SSD1306_WHITE);
  display.display();
  delay(2000);
  // ... continue with main UI
}

Memory footprint

A 128x64 mono bitmap is 1024 bytes in flash. Add the Adafruit_SSD1306 buffer (1024 bytes in SRAM) and the GFX library code (~5KB). Total: ~7KB on a 32KB Uno — comfortable. On an ATtiny85 (8KB flash, 512B SRAM), Adafruit_SSD1306 won't fit; use U8g2 in page-buffer mode instead.

U8g2 alternative

If you need lower memory, use U8g2's page mode — it draws the screen in 8x128-pixel slices, using only 128 bytes of SRAM at a time. The image2cpp output format for U8g2 is XBM (Vertical, 1 bit per pixel, LSB). We covered the differences in drawBitmap vs drawXBitmap.

Common pitfalls

Bottom line

SSD1306 + Adafruit_GFX + image2cpp is the canonical Arduino OLED bitmap stack. Wire 4 pins, install 2 libraries, paste a 1024-byte array, call drawBitmap, done. Convert your first image now, or read our deeper Arduino OLED tutorial for advanced techniques.

If your project deserves a slick GitHub README, the favicon and OG image generator at og.hjlabs.in is the fastest way to ship social previews.

Try image2cpp now — free, in browser

Drop in a PNG, JPG or BMP. Get a paste-ready C++ array for Arduino, ESP32 or RP2040. 100% client-side. Learn more about image2cpp or jump straight to the tool.

Open the converter →

More from the blog