Bitmap editor for black and white OLED-style images

Size: 128×64 Cursor: Byte addr: Bit: Pixel index: Set pixels: 0

Canvas & Toolbar

New creates a blank canvas at the selected preset size. Standard OLED sizes (128×64, 128×32) are included along with several others. ↻ 90° rotates the entire image clockwise, swapping width and height. ⇆ Flip X mirrors left-to-right. ⇅ Flip Y mirrors top-to-bottom. ⊝ Invert flips every pixel. Clear sets every pixel to black.

↩ Undo and ↪ Redo step through your edit history. Keyboard shortcuts are Ctrl+Z to undo and Ctrl+Y or Ctrl+Shift+Z to redo. Up to 50 steps are stored. All drawing operations, transforms, clear, and invert are undoable.

Tool selects the drawing mode. Draw sets pixels white on click or drag. Erase sets them black. Fill flood-fills the connected region of the same color starting from the clicked pixel. Line and Rect show a live preview while dragging and commit the shape when you release. Keyboard shortcuts: D draw, E erase, F fill, L line, R rect. Shortcuts are disabled when typing in a text box. A teal highlight box follows the cursor to show exactly which pixel you are hovering over.

Zoom scales the canvas for easier editing. The pixel grid appears at 4× and above. Drawing works with a mouse, stylus, or touch on supported devices.

Byte Layout

This is the most important setting when importing from or exporting to a specific display library. It controls how each byte in the C array maps to a group of pixels on screen. Getting this wrong causes the image to appear scrambled, striped, or mirrored. Changing the Byte Layout selector automatically updates the Export Format dropdown to match, and vice versa, so the two are always kept consistent.

If you import an image and it looks like noise or diagonal stripes, try a different Byte Layout and re-parse. For a 128×64 image that occupies 1024 bytes, both horizontal and vertical layouts are numerically valid — the layout selector is the only way to tell them apart.

LayoutHow bytes map to pixelsCommon libraries
Horizontal MSB Bytes run row by row, left to right. Bit 7 (MSB) is the leftmost pixel in each group of 8. Adafruit GFX drawBitmap(), LVGL, most general-purpose libraries
Horizontal LSB Same row-by-row order, but bit 0 (LSB) is the leftmost pixel. XBM format, u8g2 drawXBMP(), ThingPulse drawXbm()
Vertical LSB Bytes run column by column within 8-pixel tall horizontal pages. Bit 0 is the top pixel of each column in the page. Pages run top to bottom. SSD1306 direct / page mode, many bare-metal OLED drivers
Vertical MSB Same page-column layout as Vertical LSB, but bit 7 is the top pixel. Some custom firmware and lesser-used OLED libraries

Import

Click Browse or drop a file directly onto the canvas to load a .bmp, .bin, .pbm, .xbm, .h, .c, or .txt file. BMP files are decoded automatically in 1-bit, 8-bit, 24-bit, and 32-bit depth; color BMPs are converted to black and white using a brightness threshold. All other file types are read as text and passed through the same parser as the text box.

To import from source code, paste the array into the text box and click Parse text below. The parser accepts C/C++ arrays (uint8_t, unsigned char, etc.), XBM #define headers, PBM P1 ASCII, and raw space-separated hex bytes. Width and height are read from any width = N or height = N comments or defines found in the text. If none are found, common display sizes are matched by byte count. Adding a comment such as // width: 96 height: 48 forces those dimensions. The array-size bracket in declarations like img[1024] is stripped before parsing so the size number does not become a spurious byte.

Export

Select a format, click Export to generate the output, then Copy to copy to clipboard. Save BMP writes a standard 1-bit monochrome BMP file that can be opened in any image editor. The BMP uses bottom-up row order and horizontal MSB pixel order as required by the BMP specification, independent of the Byte Layout selector.

FormatDescription
C array — horizontal, MSBRow-major, bit 7 = leftmost pixel. Use with Adafruit GFX drawBitmap().
C array — horizontal, LSBRow-major, bit 0 = leftmost pixel. Use with u8g2 drawXBMP() or ThingPulse drawXbm().
C array — vertical / page, LSBPage-column, bit 0 = top of page. Standard SSD1306 direct mode and most bare-metal OLED drivers.
C array — vertical / page, MSBPage-column, bit 7 = top of page. Some custom firmware.
XBMX BitMap C header format. Horizontal LSB. Recognized by Linux tools, GIMP, and many embedded utilities.
PBM P1Portable Bitmap ASCII. One character per pixel. Human-readable and easy to diff.
Raw hexSpace-separated hex bytes, horizontal MSB. Useful for direct memory inspection or custom parsers.
Binary stringsOne row per line as 1s and 0s. Makes the bitmap structure immediately visible by eye.

Display Drivers

SSD1306

The most common OLED controller. Used in the ubiquitous 0.96" 128×64 and 0.91" 128×32 displays from virtually every supplier. Made by Solomon Systech. Supports I2C (address 0x3C or 0x3D) and SPI. The internal frame buffer is organized as 8 horizontal pages of 128 bytes each, which is the physical origin of the vertical LSB page format. At high level, any major Arduino library wraps this into either horizontal MSB (Adafruit GFX) or horizontal LSB (u8g2, ThingPulse) depending on what drawBitmap-type function you call.

SH1106

Very similar to the SSD1306 but has 132 columns of internal RAM instead of 128. The visible area is offset by 2 pixels, so libraries add a 2-column correction automatically — you do not need to account for this in your bitmap. Common in 1.3" 128×64 white OLED modules. Pinout and wiring are often identical to 0.96" SSD1306 modules, making them easy to swap. The same Adafruit, u8g2, and ThingPulse libraries support it; just change the display constructor or #define and the byte layout stays the same.

CH1116 & Others

CH1116 is found in some inexpensive white OLED modules and is largely register-compatible with the SSD1306. SH1107 drives 128×128 square OLEDs with a rotated page layout. SSD1309 is a higher-drive-current variant of the SSD1306, pin-compatible and software-compatible. For all of these, the correct byte layout depends entirely on which library you use, not the controller chip itself. u8g2 supports all of them and always uses horizontal LSB for drawXBMP(), making it a reliable cross-controller choice.

Example Code Downloads

Each button generates a ready-to-run file with your current canvas bitmap embedded in the correct byte format for that library or driver. The first group shows only the bitmap on a blank screen. The second group adds extra content so you can confirm text rendering, animation, or the full hardware driver all in one go. Arduino .ino files can be opened directly in the IDE; the bare-metal AVR file is a plain .c that compiles with avr-gcc targeting the new-style TWI0 peripheral (ATtiny816/ATmega4809 families).