.ino file, or C Array for a .h header you can paste into any project.Top toolbar - Undo/Redo, Brush size, Transform operations, Export buttons, Canvas resolution picker, Zoom controls.
Left sidebar - All drawing and shape tools. Hover any tool icon to see its name and keyboard shortcut.
Canvas area - The pixel grid. Each cell represents one pixel on your OLED display. White = ON (lit), dark grey = OFF.
Selection toolbar - Appears automatically below the main toolbar when you have an active selection. Contains copy, cut, paste, transform and crop actions scoped to the selection.
Status bar - Shows current tool, cursor position, brush size, canvas dimensions, selection info, lit pixel count, and zoom level.
Click to toggle pixels. Drag to paint a continuous line. Clicking an ON pixel switches to erase mode for that stroke - so one drag toggles consistently.
Always turns pixels OFF. Drag to erase in a line. Brush size applies - a 3px eraser clears a 3px circular area per point.
Flood-fills a contiguous region of same-state pixels. Click an OFF pixel to fill the connected area ON, or click ON to erase it. Does not respect brush size.
Applies to Pencil, Eraser, and all Shape tools. The 3 dot presets set 1/2/3px. Type any value 1 - 64 in the custom box. Shapes are drawn at 1px then dilated to match brush size.
The Invert, ↔ H, ↕ V, ↻ 90° buttons in the toolbar are selection-aware. If a selection is active they operate only on the selected pixels; otherwise they transform the whole canvas.
Swaps every pixel: ON→OFF and OFF→ON. Useful for white-on-black to black-on-white.
Mirrors the image horizontally or vertically. Both work on selection or full canvas.
Rotates clockwise 90°. On a selection, the selection box resizes (W↔H swap) and recentres. On the full canvas the pixel grid is rotated.
Erases the entire canvas. Undoable with Ctrl+Z.
All shape tools work the same way: click to set the start point, drag to the end point, release to commit. A green live preview tracks your drag. An orange dot marks the anchor (start) point. Brush size thickens all outlines.
Draws a straight line between two points using Bresenham's algorithm. Supports brush size for thick lines.
Drag to draw a hollow rectangle outline. Use Filled Rect below it for a solid filled box.
Rectangle with rounded corners. Corner radius scales automatically with the box size (max 6px).
Free-form ellipse from corner to corner of the bounding box. Hold Shift during drag for a perfect circle.
Always draws a perfect circle. Drag from the top-left corner - the radius is the smaller of horizontal/vertical distance.
Isosceles triangle - apex at the top-centre, base at the bottom. Filled variant available below it.
Draws a 4-point diamond (rotated square) inside the drag bounding box. Filled variant available.
Draws a 5-point star outline inside the bounding box. Inner radius is 40% of the outer radius.
Line with an arrowhead at the end point. Head length is ~28% of the shaft length.
Draws a plus-sign cross. Arm thickness scales to ~15% of the bounding box size.
Press S or click the dashed-rectangle icon at the bottom of the sidebar to activate the selection tool.
Click and drag inside the selection box to move it. Selected pixels are lifted off the canvas (shown semi-transparent while floating) and stamped down when you release. Hold Alt while starting a drag to duplicate instead of move. Use arrow keys to nudge 1px, Shift+Arrow to jump 8px.
Eight blue square handles appear at the corners and edge midpoints of the active selection. Drag any handle to resize the selection content. The pixels inside are scaled using nearest-neighbour to fit the new size - exactly like MS Paint. The original pixels are removed from the canvas as soon as you start dragging a handle.
Copies selection pixels to internal clipboard. Does not modify the canvas.
Copies to clipboard and erases selection pixels from the canvas.
Pastes clipboard as a floating selection at position (2,2). Drag to reposition before it stamps down.
Erases all pixels outside the selection. The selection itself is cleared afterwards.
Erases all pixels inside the selection. Undoable.
Invert, Flip H/V, and Rotate 90° in the selection toolbar apply only to the selected area.
Exports the canvas as a 1:1 monochrome PNG at the native pixel resolution (e.g. 128×64 px). White pixels = ON, black = OFF. Use for previewing or sharing your design.
Exports a text file where each row is a canvas row and each value is 0 (OFF) or 1 (ON). Use this to save your work and re-import it later for continued editing.
Exports a const uint8_t bitmap[] PROGMEM array. Paste into any Arduino / ESP32 sketch. Each byte packs 8 horizontal pixels, MSB first - compatible with Adafruit GFX drawBitmap().
Exports a complete, ready-to-flash Arduino sketch pre-configured for the Adafruit SSD1306 library. Includes all #includes, display init, and drawBitmap() call. Default wiring: SDA=D2, SCL=D1 (ESP8266/ESP32 NodeMCU).
.csv file. If the file dimensions differ from the current canvas, the canvas will automatically resize to match and the history will be cleared.After exporting C Array, open the downloaded oled_bitmap.h and copy the array declaration into your sketch, or #include it. Then call:
display.drawBitmap(x, y, bitmap, WIDTH, HEIGHT, SSD1306_WHITE);
Replace x, y with your desired screen position. WIDTH and HEIGHT match your canvas resolution.
Use the Canvas dropdown to change resolution. 16 presets cover all common OLED sizes:
SSD1306: 128×64, 128×32 | SH1106: 128×64 | SSD1327: 128×128 | SSD1309: 128×64 | Tiny OLEDs: 96×16, 72×40, 64×32, 50×16
Choose Custom… to enter any width × height up to 1024×1024. Changing resolution when the canvas has content will ask for confirmation and clear the artwork.
Wire.begin() so it works on standard board defaults (Uno, Nano, ESP32, ESP8266 default mapping). If your board requires custom I²C pins, change it to Wire.begin(SDA, SCL).| Key | Action |
|---|---|
| P | Pencil tool |
| E | Eraser tool |
| F | Flood Fill tool |
| L | Line tool |
| R | Rectangle tool |
| C | Perfect Circle tool |
| T | Triangle tool |
| D | Diamond tool |
| S | Selection tool |
| Key | Action |
|---|---|
| CtrlZ | Undo (up to 80 steps) |
| CtrlY or CtrlShiftZ | Redo |
| CtrlC | Copy selection |
| CtrlX | Cut selection |
| CtrlV | Paste |
| Del / Backspace | Delete selection pixels |
| Esc | Cancel / deselect |
| Key | Action |
|---|---|
| ↑ ↓ ← → | Nudge selection 1px |
| Shift + Arrow | Jump selection 8px |
| Key / Action | Result |
|---|---|
| Scroll wheel | Zoom in / out centred on cursor |
| Pinch (touch) | Zoom in / out (mobile/tablet) |
| Middle-click + drag | Pan the canvas |
| Ctrl + left-drag | Pan the canvas |
| Shift + drag (Ellipse) | Constrain to perfect circle |
| Alt + drag selection | Duplicate instead of move |
SCREEN_ADDRESS (0x3C or 0x3D) matches your specific OLED module - some modules use 0x3D.| Module / Controller | Default Address | Notes |
|---|---|---|
| SSD1306 128×64 (most) | 0x3C | SA0 pin low (default) |
| SSD1306 128×64 (alt) | 0x3D | SA0 pin high |
| SSD1306 128×32 | 0x3C | - |
| SH1106 128×64 | 0x3C | Use Adafruit_SH110X lib |
| SSD1327 128×128 | 0x3C | Greyscale - use with GFX |
About this tool
Small monochrome OLED screens, like the 0.96-inch SSD1306 found in many Arduino and ESP32 kits, show a grid of pixels that are either on or off. This editor lets you draw on exactly that grid - one pixel at a time or with shapes - and then gives you the bytes to put in your program, or a complete Arduino sketch that shows your drawing on the screen.
Everything happens in your browser, and your canvas is saved in this browser as you work. Open the sections below to learn the tools, how the export works, and how the picture is stored in memory.
.ino
file, or C Array for just the bytes to paste into your own code.Changing the resolution clears the canvas (the editor asks first). Pick the size before you start drawing.
| Key | Tool | What it does |
|---|---|---|
| P | Pencil | Turns pixels on, at the chosen brush size |
| E | Eraser | Turns pixels off |
| F | Flood fill | Fills a closed area, like a paint bucket |
| L | Line | A straight line between two points |
| R | Rectangle | Outline or filled box |
| C | Circle | Ellipse; hold Shift for a perfect circle |
| T | Triangle | Filled or outline triangle |
| D | Diamond | Filled or outline diamond |
| S | Select | Pick a rectangle to move, copy, cut, crop or transform |
| Shortcut | Action |
|---|---|
| Ctrl + Z | Undo (up to 80 steps) |
| Ctrl + Y or Ctrl + Shift + Z | Redo |
| Ctrl + C / X / V | Copy, cut and paste a selection |
| Delete or Backspace | Clear the selected pixels |
| Arrow keys | Nudge a selection 1 pixel; with Shift, 8 pixels |
| Esc | Cancel or deselect |
| Scroll wheel | Zoom in and out around the pointer |
| Middle-drag, or Ctrl + drag | Move around the canvas |
| Pinch | Zoom on a phone or tablet |
The toolbar also flips, rotates and inverts either the selection or, with nothing selected, the whole canvas.
| Export | Use it when |
|---|---|
Arduino Sketch (.ino) | You want a complete program that shows the picture on an SSD1306 |
C Array (.h) | You already have a program and only need the picture's bytes |
| PNG | You want an image for a document, a slide or a web page |
| CSV | You want to save your work and open it again later, or process the pixels yourself |
GND to ground, VCC to the supply your module
is rated for, SDA to the board's SDA pin and SCL to its SCL pin. On an Uno
those are A4 and A5..ino file and upload it.These are the key lines of the sketch it writes for a 128×64 canvas; ... stands for your picture's bytes:
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const unsigned char myBitmap[] PROGMEM = {
...
};
display.drawBitmap(0, 0, myBitmap, 128, 64, SSD1306_WHITE);
The first four lines describe the screen. display is the object that talks to it over
I2C (&Wire). myBitmap holds your picture, and drawBitmap()
copies it to the top-left corner, (0, 0).
If the screen stays blank, the address is the usual suspect. Most 128×64 modules answer at
0x3C; some are set to 0x3D. Change SCREEN_ADDRESS and upload
again. Modules with an SH1106 controller need the Adafruit SH110X library instead.
Each pixel is one bit: 1 for on, 0 for off. The export packs eight pixels into each byte, row by row from the top, and within a byte the leftmost pixel is the highest bit.
So a row that starts on, off, on, on, off, off, off, off - 10110000 - becomes the byte
0xB0. A row of eight lit pixels is 0xFF. This is the order the Adafruit
GFX drawBitmap() function expects.
Some libraries read bits the other way round. U8g2's drawXBM() uses the XBM format, in
which the leftmost pixel is the lowest bit, so the same eight pixels would have to be
0x0D. If you use a different library, check which order it wants before you blame the
drawing.
Each row takes a whole number of bytes, so the size of a picture is (width ÷ 8, rounded up) × height:
| Display | Bytes per row | Bytes per picture |
|---|---|---|
| 128 × 64 | 16 | 1024 |
| 128 × 32 | 16 | 512 |
| 64 × 48 | 8 | 384 |
| 72 × 40 | 9 | 360 |
| 96 × 16 | 12 | 192 |
| 100 × 16 | 13 | 208 (the last 4 bits of each row are unused) |
An Arduino Uno has 32,256 bytes of flash for your program and only 2,048 bytes of RAM. That RAM is already busy: the Adafruit SSD1306 library keeps a copy of the whole screen in it, and for a 128×64 display that copy alone is 1024 bytes - half of the Uno's RAM. A 128×32 display needs 512 bytes.
That is why the exported array is marked PROGMEM. It tells the compiler to leave the
picture in flash, where there is far more room, instead of copying it into RAM at start-up.
drawBitmap() knows to read it from there.
Flash still runs out if you store many pictures. If you set aside 20 KB (20,480 bytes) for graphics, that holds 20 full 128×64 pictures, or 40 at 128×32. Boards like the ESP32 have megabytes of flash, so this limit mostly matters on the small AVR boards.
The canvas is autosaved in this browser, so it is still there if you reload the page. It does not follow you to another computer; export a CSV to keep a copy you can open anywhere.
Yes. Use the Image to Pixels converter, then send the best result to this editor to tidy it up.
Draw a frame, add it to the animation with the stage button, change the drawing, and stage again. The Animation Studio then puts the frames in order and exports them together.
1024 × 1024 pixels, using the Custom option. There are also presets for common displays.
Learn the C behind the exported bytes in Embedded C from Zero: bit manipulation explains the packing, and the memory map explains flash and RAM.