Bitmap Input & Settings

Drag & drop an image here
PNG, JPG, BMP, GIF (first frame), WEBP supported
128

Preview & OutputLive

Processed preview (128×128px)
Upload or load a sample to see the preview…
Adjust settings or upload an image to see the generated array…

Bitmap to Array Converter - Free Online Image to Byte Array Tool

Convert PNG, JPG, and BMP images to packed byte arrays for Arduino, ESP32, STM32, Rust embedded, and OLED/TFT/e-ink display projects. Supports C arrays, Arduino PROGMEM, Rust arrays, 1/2/4/8 bpp, and Floyd-Steinberg dithering. Free, offline, no upload required.

What is a Bitmap to Array Converter?

A bitmap to array converter is an essential developer utility that transforms image files - PNG, JPG, BMP, and similar formats - into packed byte arrays suitable for use in embedded systems firmware. When you need to display a logo, icon, sprite, or graphic on a microcontroller-driven screen, the display hardware cannot load image files directly from a file system. Instead, the image data must be compiled into the firmware itself as a C array, an Arduino PROGMEM array, or a Rust static byte slice.

This free online image to byte array converter handles the entire process in your browser. Upload any image, select the target bit depth, configure dithering and bit order, choose your output format, and instantly get ready-to-paste code for your embedded project. All processing happens locally - no image data is ever sent to a server.

Whether you are building an Arduino project with an SSD1306 OLED display, driving an ILI9341 TFT panel on an ESP32, rendering graphics on an STM32 with an ST7735 screen, populating a Waveshare e-ink display, or writing bare-metal Rust firmware for a microcontroller, this tool generates production-ready output in seconds.

How to Convert an Image to a Byte Array - Step-by-Step Guide

Follow these steps to convert any image into a packed byte array for your embedded or Arduino project:

  1. Upload Your Image: Drag and drop or click to upload a PNG, JPG, BMP, or GIF file. For best results with 1 bpp monochrome output, use high-contrast images. For OLED displays such as the SSD1306 or SH1106, a 128x64 or 128x32 pixel image works best. For Nokia 5110 / PCD8544 screens, target 84x48 pixels.
  2. Select Bits Per Pixel (bpp): Choose 1 bpp for monochrome displays (OLED, e-ink, e-paper, mono LCD), 2 bpp for 4-level grayscale, 4 bpp for 16-level grayscale, or 8 bpp for full 256-level grayscale output. Most Arduino OLED projects use 1 bpp.
  3. Configure Dithering: Select "None" for clean geometric shapes, icons, and logos. Enable Floyd-Steinberg dithering when converting photographs or gradient-heavy images to lower bit depths. Dithering simulates smooth tonal transitions by distributing quantization error to neighboring pixels.
  4. Set Bit Order (MSB / LSB): Choose MSB-first (Most Significant Bit) or LSB-first (Least Significant Bit) packing. The correct setting depends on your display driver. Adafruit GFX, U8g2, and most SSD1306 libraries expect MSB-first. Some ST7565 and custom drivers expect LSB-first. Check your library documentation if the output appears mirrored.
  5. Select Row Order: Choose top-to-bottom (normal) or bottom-to-top (BMP-style) row ordering. Most embedded display libraries expect top-to-bottom. Use bottom-to-top only when your driver explicitly requires it.
  6. Choose Output Format: Select from C array (const uint8_t), Arduino PROGMEM (const unsigned char PROGMEM), Rust static byte array (&[u8]), or raw hex string. See the full format descriptions in the next section.
  7. Preview and Download: The live preview updates in real-time as you change settings. Once satisfied, copy the generated code to your clipboard or download it as a .h header file for direct inclusion in your project, or as a .bin binary file for use with bootloaders and flashing tools.

Key Features of This Image to C Array Converter

Multiple Bit Depths (1, 2, 4, 8 bpp)

Full support for 1 bpp monochrome, 2 bpp 4-level grayscale, 4 bpp 16-level grayscale, and 8 bpp 256-level grayscale. Covers the complete range of display types used in embedded projects, from monochrome OLEDs and e-paper to grayscale LCD modules.

Floyd-Steinberg Dithering Algorithm

The Floyd-Steinberg error-diffusion dithering algorithm produces significantly better results than threshold-only quantization when converting photographs or gradient images to 1 bpp or 2 bpp. It distributes quantization error to adjacent pixels, creating the visual illusion of smoother tones on monochrome displays.

Real-Time Live Preview

Every change to settings - bit depth, dithering, bit order, row order - is reflected instantly in the live preview canvas. Verify your output exactly as it will appear on the target OLED, TFT, or e-ink display before copying or downloading any code.

Multiple Output Formats

Generates C arrays, Arduino PROGMEM arrays, Rust static byte slices, and raw hex strings. Covers the output formats needed for every major embedded platform and language.

MSB and LSB Bit Order Control

Select MSB-first or LSB-first pixel packing within each byte. This controls which pixel occupies the most significant bit position. Critical for correct rendering on display controllers that pack pixels differently, such as the difference between SSD1306 (MSB-first) and certain ST7565 implementations.

Top-to-Bottom and Bottom-to-Top Row Ordering

Supports normal top-to-bottom row ordering (used by most microcontroller display libraries) and inverted bottom-to-top ordering (used by some BMP file formats and certain older display drivers).

Fully Offline, In-Browser Processing

All image conversion runs entirely in your browser using JavaScript. No image data is transmitted to any server. This makes the tool safe for proprietary, confidential, or sensitive assets such as product logos and UI graphics in commercial firmware.

Persistent Settings with LocalStorage

Your last-used bit depth, dithering mode, bit order, row order, and output format are automatically saved to browser LocalStorage and restored on your next visit, eliminating repetitive reconfiguration across sessions.

Supported Output Formats Explained

This tool generates four distinct output formats to match every major embedded development workflow. Each format is explained below with example output and usage context.

C Array - const uint8_t

The standard C array format produces a const uint8_t declaration suitable for any C or C++ project targeting microcontrollers including AVR (Arduino Uno, Nano, Mega), ARM Cortex-M (STM32, nRF52, RP2040), RISC-V, and PIC. This format works with any display library that accepts a raw byte pointer. The array is placed in RAM by default; move it to flash using your toolchain's specific flash-placement attribute if RAM is limited.

const uint8_t my_image[] = {
  0xFF, 0x81, 0x81, 0x81, 0xFF, ...
};
const uint16_t my_image_width  = 128;
const uint16_t my_image_height = 64;

Arduino PROGMEM - Flash Memory Storage

The Arduino PROGMEM format stores the array in flash (program memory) instead of SRAM. On AVR-based boards - Arduino Uno, Nano, Mega, Leonardo - SRAM is extremely limited (2 KB on the Uno). A 128x64 bitmap at 1 bpp occupies 1,024 bytes, which would consume half the Uno's entire RAM. Using PROGMEM keeps it in flash, preserving SRAM for runtime variables. This format is also commonly used with Adafruit GFX, U8g2, and Adafruit SSD1306 libraries. ESP32 and ESP8266 boards support PROGMEM for compatibility, though they have far more RAM available.

const unsigned char my_image[] PROGMEM = {
  0xFF, 0x81, 0x81, 0x81, 0xFF, ...
};
// Usage with Adafruit SSD1306:
display.drawBitmap(0, 0, my_image, 128, 64, WHITE);

Rust Static Byte Array - Embedded Rust

The Rust output format generates a static byte slice suitable for embedded Rust projects using the embedded-hal ecosystem,embassy, rtic, or bare-metal no_stdenvironments. The array is placed in flash memory at link time. This format works with Rust display drivers such as embedded-graphics,ssd1306, ili9341, st7735-lcd, andepd-waveshare crates.

pub static MY_IMAGE: &[u8] = &[
    0xFF, 0x81, 0x81, 0x81, 0xFF,
    // ...
];
pub const MY_IMAGE_WIDTH: u32 = 128;
pub const MY_IMAGE_HEIGHT: u32 = 64;

Hex String - Raw Hexadecimal Output

The hex string format outputs the raw image data as a continuous hexadecimal string without any language-specific wrapper. This is useful for custom parsing scripts, Python tools, MicroPython firmware, or when feeding data into a proprietary build system, binary patching tool, or memory flashing utility that ingests raw hex input.

Platform and Display Compatibility

This image to array converter has been designed to generate output compatible with all major embedded platforms and display modules used in maker, hobbyist, and professional firmware development.

Supported Microcontroller Platforms

  • Arduino Uno, Nano, Mega, Leonardo (AVR ATmega)
  • Arduino Due (ARM Cortex-M3)
  • ESP32 and ESP32-S2, ESP32-S3, ESP32-C3
  • ESP8266 (NodeMCU, Wemos D1 Mini)
  • STM32 (all series: F0, F1, F4, L0, L4, H7, etc.)
  • Raspberry Pi Pico and Pico W (RP2040)
  • nRF52840, nRF52832 (Nordic Semiconductor)
  • PIC (Microchip) with XC8 / XC16 / XC32
  • AVR ATtiny (ATtiny85, ATtiny2313)
  • RISC-V microcontrollers (CH32V, GD32V)
  • Rust embedded (no_std, cortex-m, embassy, rtic)
  • MicroPython and CircuitPython boards

Supported Display Controllers

  • SSD1306 - 128x64 and 128x32 OLED displays
  • SSD1309, SSD1325, SSD1327, SSD1331
  • SH1106, SH1107 - 128x64 OLED variants
  • ILI9341 - 320x240 TFT color display
  • ILI9163, ILI9486, ILI9488
  • ST7735 - 128x128 / 160x128 TFT display
  • ST7789 - 240x240 TFT display
  • PCD8544 - Nokia 5110 / 3310 84x48 LCD
  • KS0108 - 128x64 GLCD (KSEG controller)
  • UC1701, UC1608 - monochrome LCD controllers
  • Waveshare e-Paper / e-ink (all sizes)
  • LVGL-based displays (via C array import)
  • Custom parallel and SPI monochrome LCDs

Compatible Arduino and Embedded Libraries

  • Adafruit GFX Library (drawBitmap)
  • Adafruit SSD1306
  • U8g2 / U8glib (drawXBMP, drawBitmap)
  • TFT_eSPI (pushImage, drawBitmap)
  • LVGL embedded GUI framework
  • GxEPD / GxEPD2 (Waveshare e-ink)
  • Ucglib
  • TFT_HX8357
  • embedded-graphics (Rust crate)
  • ssd1306 crate (Rust)
  • epd-waveshare crate (Rust)

Accepted Input Image Formats

  • PNG (recommended - lossless, supports transparency)
  • JPG / JPEG
  • BMP (Windows bitmap)
  • GIF (first frame used)
  • WebP
  • Any format supported by the browser's canvas API

For monochrome (1 bpp) output, black-and-white or high-contrast source images produce the cleanest results. PNG is the preferred input format as it is lossless and does not introduce JPEG compression artifacts that degrade 1 bpp conversion quality.

How Bitmap to Byte Array Conversion Works - Technical Reference

Understanding the conversion process helps you choose the correct settings for your specific display and library. Here is a complete technical breakdown of how image pixels are converted to packed byte arrays.

Grayscale Reduction

All input images - regardless of whether they are RGB, RGBA, or already grayscale - are first converted to a grayscale luminance map. The standard luminance formula (0.299R + 0.587G + 0.114B) weights the green channel more heavily because human vision is most sensitive to green wavelengths. The resulting per-pixel values range from 0 (black) to 255 (white).

Quantization and Thresholding

Each grayscale pixel is then quantized to the target bit depth. For 1 bpp, pixels at or above the threshold (typically 128) become white (1) and those below become black (0). For 2 bpp, the 0–255 range is divided into four equal bands mapped to values 0–3. For 4 bpp, it is divided into 16 bands (0–15). For 8 bpp, the 8-bit grayscale value is used directly.

Floyd-Steinberg Error Diffusion

When dithering is enabled, quantization error (the difference between the original pixel value and the quantized output value) is distributed to neighboring pixels using the Floyd-Steinberg weights: 7/16 to the right, 3/16 to the lower-left, 5/16 directly below, and 1/16 to the lower-right. This creates a natural-looking dithered pattern that preserves the perceived tonal range of the original image on low bit-depth displays. It is strongly recommended for photographic source images being converted to 1 bpp for OLED or e-ink output.

Pixel Packing into Bytes

After quantization, pixels are packed into bytes. For 1 bpp, eight horizontally adjacent pixels share a single byte. With MSB-first packing, the leftmost pixel occupies bit 7 (the most significant bit) and the rightmost pixel occupies bit 0. With LSB-first packing, the order is reversed. Row padding is applied as needed to align each row to a byte boundary. For 2 bpp, four pixels share a byte; for 4 bpp, two pixels share a byte; for 8 bpp, each pixel occupies a full byte.

Array Size Calculation

The number of bytes in the output array can be calculated as:bytes = ceil(width / (8 / bpp)) * height. For example, a 128x64 image at 1 bpp producesceil(128 / 8) * 64 = 16 * 64 = 1,024 bytes. At 8 bpp, the same image produces 128 * 64 = 8,192 bytes. Always verify that the output array size fits within your target microcontroller's available flash and RAM constraints before integrating it into your project.

Common Use Cases for Image to Array Conversion

Displaying Logos and Splash Screens

Embed a startup logo or product splash screen on an OLED or TFT display. Convert your logo PNG to a 1 bpp PROGMEM array and calldisplay.drawBitmap() from Adafruit GFX or the equivalent function in U8g2 during yoursetup() routine.

Custom Icons for IoT Dashboards

Design custom icons in any image editor at 16x16, 32x32, or 64x64 pixels and convert them to C arrays. Store multiple icons in a single header file and select the correct icon at runtime based on sensor data, WiFi status, or user input on your ESP32 or Arduino dashboard display.

E-Ink and E-Paper Display Graphics

Waveshare and Good Display e-paper modules require 1 bpp packed arrays for black-and-white content and separate arrays for red or yellow planes on 3-color displays. Convert images with Floyd-Steinberg dithering for the best photographic output on e-ink panels given their binary black/white rendering capability.

Sprite Sheets and Animation Frames

Convert individual animation frames to separate arrays and cycle through them using a timer interrupt or FreeRTOS task to create smooth animation sequences on any microcontroller display without needing an SD card or external flash memory.

Rust Embedded Graphics Projects

Use the Rust output format to generate static byte slices compatible with the embedded-graphics crate'sImageRaw type or custom display drivers. No more manual conversion from Python scripts - paste directly into your src/images.rs module.

GLCD and Nokia 5110 LCD Graphics

Create bitmap graphics for PCD8544-based Nokia 5110 / 3310 LCD modules at 84x48 resolution, or for KS0108 and compatible 128x64 GLCD displays commonly used with PIC microcontrollers and the mikroC Pro compiler's built-in GLCD library.

How This Tool Compares to image2cpp, LCD Image Converter, and LCDAssistant

Several bitmap-to-array tools exist in the embedded development community. Here is how this converter addresses common limitations found in popular alternatives:

vs. image2cpp (javl.github.io)

image2cpp is a widely used browser-based tool focused primarily on Arduino PROGMEM and Adafruit GFX output. This converter adds dedicated Rust array output, explicit 2 bpp and 4 bpp support for grayscale displays, and a persistent settings system that remembers your preferences across sessions.

vs. LCD Image Converter (sourceforge.net)

LCD Image Converter is a powerful desktop application for Windows that supports color formats including RGB565. However, it requires download and installation and is not available on macOS or Linux without Wine. This online tool requires no installation, runs on any OS including Linux, macOS, Windows, and ChromeOS, and works on mobile browsers.

vs. LCDAssistant

LCDAssistant is a classic Windows-only desktop tool for 1 bpp monochrome conversion. It lacks support for multi-bit grayscale, dithering, Rust output, and modern browser-based workflow. This online converter modernizes the same core capability with a fully web-native, cross-platform experience.

vs. Manytools Image to Byte Array

Manytools offers basic 1 bpp monochrome conversion with C++ array output. This tool extends that with multiple bit depths, Floyd-Steinberg dithering, configurable bit and row order, Rust support, and downloadable .h and .bin file output - all without commercial use restrictions on the generated output.

Tips and Best Practices for Embedded Display Graphics

Resize Your Image Before Converting

Always resize your source image to match your display's resolution before uploading. For a 128x64 OLED, resize to exactly 128x64 pixels in an image editor such as GIMP, Photoshop, or Inkscape. Scaling inside the converter may not apply the optimal interpolation algorithm for your use case.

Use PNG for Monochrome Source Images

JPEG compression introduces block artifacts and noise that degrade 1 bpp conversion quality significantly. Always use PNG (lossless) for monochrome icons, logos, and geometric shapes. If your source is a JPEG photograph, enabling Floyd-Steinberg dithering will produce better results than simple thresholding.

Check MSB vs LSB if Your Image Appears Mirrored

If the output on your physical display appears horizontally scrambled or mirrored - with correct overall shape but pixels shifted or reversed within each byte - toggle the bit order setting between MSB-first and LSB-first. This is the most common source of display rendering errors when integrating new display controllers.

Calculate Flash Usage Before Integrating

An Arduino Uno (ATmega328P) has 32 KB of flash. A 128x64 image at 1 bpp occupies 1 KB. Ten such images occupy 10 KB - nearly a third of the available flash. For image-heavy projects, consider using an Arduino Mega (256 KB flash), ESP32 (4 MB flash), or storing images on an external SPI flash or SD card.

Invert Colors for OLED Displays

Most OLED displays (SSD1306, SH1106) default to a black background with white pixels. If your source image has a white background with black content, invert the image in your editor before converting, or use the invert function in your display library. This avoids driving the full OLED panel white, which consumes maximum current and reduces OLED lifespan.

Organize Multiple Images in a Single Header File

For projects using several bitmap assets, place all converted arrays in a single images.h file with include guards. Use a consistent naming convention such as img_wifi_icon_16x16 to encode the asset name and dimensions, making it easy to locate and update individual assets as the project evolves.

Frequently Asked Questions

What bit depth should I use for my display?

Use 1 bpp for monochrome displays: SSD1306 OLEDs, SH1106 OLEDs, Waveshare e-ink, Nokia 5110 LCD, KS0108 GLCD. Use 2 bppfor 4-gray-level displays such as the SSD1325. Use 4 bppfor 16-level grayscale controllers. Use 8 bpp for displays or frame buffers that support 256-level grayscale. For full RGB color displays (ILI9341, ST7789), you need a 16-bit RGB565 converter rather than this grayscale bit-packed converter.

Why does my image look wrong on the display?

The four most common causes are: (1) incorrect bit order - toggle between MSB and LSB; (2) incorrect row order - toggle between top-to-bottom and bottom-to-top; (3) the image dimensions do not match what was passed to the draw function - double-check width and height constants; (4) the image data is placed in SRAM but your draw call reads from PROGMEM or vice versa. Most Adafruit libraries have separate versions of draw functions for RAM and PROGMEM buffers.

Is this tool free for commercial use?

Yes. The generated array output - C code, PROGMEM declarations, Rust code, hex strings - is yours to use in any project, whether personal, open-source, or commercial. There are no licensing restrictions on the tool's output.

Is my image data private? Does it get uploaded?

All processing happens entirely in your browser using JavaScript. Your images are never uploaded to any server. The tool works fully offline once the page has loaded. This makes it safe to use with proprietary product logos, confidential UI assets, and sensitive firmware graphics.

How do I use the generated array with Adafruit GFX?

Select the "Arduino PROGMEM" output format and copy the generated code into a .h header file. Include that file in your sketch. Then call display.drawBitmap(x, y, myArray, width, height, WHITE)from the Adafruit SSD1306 or Adafruit GFX library. Make sure the width and height arguments match the actual dimensions of your converted image.

How do I use the output with U8g2?

U8g2 uses the u8g2.drawXBM() or u8g2.drawBitmap()functions depending on the byte layout. For the horizontal byte layout (which this tool produces), use drawBitmap(). If usingdrawXBM(), note that XBM format uses LSB-first bit ordering, so select LSB-first in this converter to match.

Can I convert a 128x64 image for an SSD1306 OLED?

Yes. Resize your image to exactly 128x64 pixels in an image editor, upload it here, select 1 bpp, choose MSB-first bit order, enable Floyd-Steinberg dithering if it is a photograph, select Arduino PROGMEM format, and copy the output. The result will be a 1,024-byte PROGMEM array ready for use with any SSD1306 Arduino library.

What is the difference between MSB-first and LSB-first?

In MSB-first packing, the leftmost pixel in a row is placed in bit 7 of the first byte. In LSB-first packing, the leftmost pixel is placed in bit 0. Adafruit GFX, most SSD1306 libraries, and U8g2 drawBitmap use MSB-first. XBM format and some ST7565 implementations use LSB-first. If pixels in your rendered image appear scrambled within groups of 8, toggle this setting.

Does this tool support color images for TFT displays?

This converter specializes in grayscale packed-pixel formats (1/2/4/8 bpp) suited for monochrome and grayscale displays. For RGB565 color output needed by ILI9341, ST7789, or ST7735 TFT displays with libraries like TFT_eSPI, a 16-bit RGB converter is more appropriate. The 8 bpp output from this tool can be used as a grayscale layer for some TFT rendering pipelines.

Can I use this to generate images for Waveshare e-ink displays?

Yes. Waveshare e-paper libraries (both Arduino and Raspberry Pi variants) accept 1 bpp packed byte arrays. Convert your image with 1 bpp, MSB-first, top-to-bottom row order, and download the .h header. Include it in your project and pass the array pointer to theEPD_Display() or equivalent function. For 3-color (black/white/red or black/white/yellow) panels, you need two separate arrays - one for black pixels and one for the color layer.

Related Developer Tools

Working on embedded display projects often requires a suite of companion tools alongside a bitmap converter. The following tools complement this converter in a typical embedded graphics workflow:

Array to Image Visualizer

Paste an existing byte array and render it as a visual image to verify or debug display data already present in firmware source code. Essential for reverse-engineering unknown byte arrays found in legacy projects.

Hex to Binary Converter

Convert between hexadecimal strings and binary representations of byte values. Useful when working with display controllers that accept raw binary data over SPI or I2C.

Base64 Encoder / Decoder

Encode binary image data as Base64 for embedding in OTA firmware update payloads, JSON configuration files, or web-based IoT device management interfaces used with ESP32 or ESP8266 projects.

Bitwise Calculator

Perform AND, OR, XOR, NOT, and bit-shift operations on hexadecimal or binary values. Helpful for manually constructing display command bytes when configuring display controller initialization sequences.