Skip to content

Image to C Array for Arduino and ESP32 ​

Abstract orange geometry resolving into pixels and packed rows of image data

To convert an image to a C array, resize it to the dimensions you need on the display, choose a pixel format your drawing library accepts, and export the pixel data with its draw call. For a monochrome OLED that usually means a 1-bit bitmap. For a color TFT, RGB565 is a common choice.

The array's file extension tells you very little. Two headers can both contain hexadecimal numbers and still need completely different drawing functions.

Choose the drawing library before converting ​

Start with the library already running on your board. A PNG to C array conversion for U8g2 should not produce the same output as one for LVGL.

Firmware targetAsset to prepareIntegration detail
U8g2XBM bitmapWidth and height accompany the byte array
TFT_eSPIRGB565 pixels or a monochrome bitmapUse the matching drawing function
Adafruit GFXRGB565 pixels or a monochrome bitmapMatch the bitmap's packing to the API
LVGL 9Image descriptor and pixel dataA bare pixel array is not the complete image object

Lopaka's platform reference lists the output formats. Select the platform first so the editor exports the appropriate asset.

Convert a PNG or BMP in Lopaka ​

  1. Open Lopaka and choose the target platform and screen dimensions.
  2. Open the Image tool and upload the source graphic.
  3. Resize or crop to the size the image will occupy on the device. A 24-pixel status icon does not need a full-screen source bitmap.
  4. Choose monochrome or RGB when the platform offers both. For line art, inspect the result with dithering disabled; for a photograph, compare the available dithering modes.
  5. Place the asset on the screen, then copy the generated data and drawing code together.

The image import guide covers the controls. If you only need monochrome OLED conversion, follow the shorter U8g2 image converter walkthrough.

How large will the array be? ​

For an uncompressed, row-packed 1-bit bitmap, round each row up to a whole byte:

text
row bytes = (width + 7) / 8, using integer division
bitmap bytes = row bytes * height

RGB565 bytes = width * height * 2

These calculations describe pixel payloads. They exclude descriptors, alignment, palettes, and any extra runtime buffers.

DimensionsRow-packed 1-bitRGB565
24 × 2472 bytes1,152 bytes
48 × 48288 bytes4,608 bytes
128 × 641,024 bytes16,384 bytes
240 × 2407,200 bytes115,200 bytes
320 × 2409,600 bytes153,600 bytes

For a 13 × 8 monochrome icon, each row takes two bytes. The payload is 16 bytes, even though dividing the total pixel count by eight gives 13. That difference matters when diagnosing a shifted image.

13 by 8 monochrome pattern with two stored bytes per row

Test pattern, 13 × 8: two stored bytes per row, 16 bytes in total. Download the matching XBM file.

The size of the generated source file is different again. Text such as 0xF8, 0x00 takes more disk space than the two bytes it describes. Check the compiled firmware size when budgeting flash.

If you are choosing a conversion tool, the image2cpp alternative comparison explains where a standalone converter ends and a screen editor becomes useful.

Why a converted array can look wrong ​

If the outline is correct but the colors are wrong, inspect the color format and byte order. RGB565 allocates five bits to red, six to green, and five to blue; Adafruit explains the encoding in its graphics reference.

If a monochrome image repeats or slopes sideways, check its width, row padding, and bit order. A display controller's internal screen buffer is not necessarily laid out like the bitmap accepted by your drawing function.

Follow the matching troubleshooting guide if the converted bytes look wrong on a TFT or monochrome OLED: fix RGB565 colors and byte order in TFT_eSPI, or fix drawXBMP bitmaps on an SSD1306.

Keep the converter output and its generated draw call as a pair. Copying only the array into an unrelated example removes the information that makes the bytes meaningful.

PNG files and raw pixels are different things ​

Renaming logo.png to logo.h does not decode the image. A PNG contains compressed image data and metadata. A drawing function that expects raw RGB565 pixels cannot interpret that file directly.

For a fixed logo, conversion before compilation can keep the firmware path simple. For replaceable photographs on storage, a decoder may be the better fit. Choose based on how the asset will be updated, not just which filename is easiest to paste into the sketch.

Common questions ​

Can the same C array work on an OLED and a TFT? ​

Only when both drawing paths accept the same representation. A 1-bit icon can be useful on either, but a color array cannot become a monochrome bitmap without conversion.

Does converting a PNG preserve transparency? ​

That depends on the output format. Plain RGB565 contains no alpha channel. Check whether the export flattens transparency against a background or uses a separate transparency mechanism.

Where should I start for a full screen? ​

Use the Arduino GUI builder guide to combine text, shapes, and images. Keeping a temperature value as text lets firmware update it without replacing the whole screen bitmap.