About this tool
The array your display actually wants
A display driver does not take a PNG. It takes a run of bytes laid out exactly the way its controller reads them, and every part of that layout is a decision somebody has to make: one bit per pixel or sixteen, the leftmost pixel at bit 7 or at bit 0, rows one after another or eight-pixel-tall pages, red in the top five bits or the bottom five. Drop an image here, pick the format, and the bytes are packed to match — mono, gray2, gray4, gray8, the alpha1 to alpha8 masks LVGL wants, rgb565, rgb888 and argb8888. The preview beside the controls is not the source image scaled down; it is the packed array read back out again, so what you are looking at is what the panel will show.
One bit per pixel, and how to spend it
A 128x64 OLED gives you 8,192 pixels and one bit each, so the whole picture comes down to where the cut between black and white falls. For line art and icons a plain threshold is the right answer, and the slider moves it. A photograph needs the error spread around instead: Floyd–Steinberg diffuses it into the neighbouring pixels and gives the grainy newsprint look, while an ordered Bayer 4x4 matrix gives a regular cross-hatch that often reads more cleanly on a small panel. Brightness and contrast are applied before the cut, invert after it, and each of them redraws the preview as you drag — because the only way to know whether an icon survives one bit is to look at it at the size it will be shown.
Reading a framebuffer back into a picture
The other direction is the one nobody builds, and it answers the question you actually have: is this array right? Paste a C array — 0x bytes, plain decimal, \x escapes, a bare hex blob, with or without braces, comments and #define lines — or drop a raw .bin you pulled out of flash, and it is drawn as an image. Then drag the width slider. A framebuffer read at the wrong width shears into diagonal stripes, and the moment the width is right the picture snaps into place; that is the standard way to identify an unknown dump. It works just as well as a check on your own output: convert an icon, paste the array back, and if what comes out looks like your icon then the bit order and the row padding are right. A token that cannot be read is reported with its position rather than swallowed, so one typo in a pasted array costs one value and never the rest of the file.
Templates, byte order, and the one that bites
The same bytes are wrapped differently depending on what is going to compile them: a plain static const uint8_t array, an Adafruit GFX PROGMEM array with _WIDTH and _HEIGHT macros, a u8g2 XBM with #define dimensions, an lv_img_dsc_t for LVGL v8 or an lv_image_dsc_t for v9, a uint16_t array for TFT_eSPI's pushImage(), or a MicroPython bytes literal with the framebuf constructor written out beside it. TFT_eSPI is the one that catches people: it reads each 16-bit pixel high byte first, so RGB565 has to be packed big-endian for that template and little-endian for every other one. Pick the template and the byte order follows it, because an array that compiles cleanly and displays in the wrong colours is a bug nobody enjoys finding. All of it runs in a Web Worker in this tab: no upload, no account, and the artwork for the product you have not announced yet stays on your machine.