zenpixels · pixel format explorer

One pixel,
every byte

A color on screen is just a few numbers in memory. Which numbers depends on the pixel format. Pick one and watch the same color change shape. All you need to start is knowing what a web hex code is.

Pick a format
Web hex codes are sRGB, so they can't name colors outside sRGB. Typing stored numbers into the channel cards can.
Fine-tune the format

A program that ignores the format

Each card is one channel: its stored number, what it means, and its bytes. Type a new number to change the color from the inside.
01

Where the bytes go

Byte order shown
02

Why these numbers

The math zenpixels-convert does, one step at a time. Anything the crate leaves to you is marked as an illustration.

    03

    Same color, other formats

    One color, many byte patterns. Select a row to switch.

    04

    From a hex code to everything else

    A hex code like #FF7A1A is already a pixel format with every choice fixed. Each idea below loosens one choice. "Show me" sets up the explorer to demonstrate it.

      05

      Words you will meet

      Channel and sample
      A channel is one ingredient of a pixel (red, alpha, cyan, lightness). A sample is one channel's number in one pixel.
      Channel type
      How each sample is stored: U8 (0–255), U16 (0–65535), floating-point F16/F32, or native types such as I16 and U64. The descriptor determines what those numbers mean.
      Transfer function
      The curve between stored number and amount of light. sRGB spends more codes on darks, the way eyes do. Linear stores light itself.
      Primaries
      Which exact red, green and blue the numbers mix. Wide gamuts can reach colors outside sRGB. Converting primaries adjusts the numbers to preserve the represented color where possible.
      White point
      The color equal R, G and B make. The known primaries in this demo use D65 (x 0.3127, y 0.3290).
      Gamut
      Every color a set of primaries reaches with values 0 to 1. Outside it you need values below 0 or above 1, which only floats can hold.
      Signal range
      Full uses every code. Narrow (TV) puts black at 16 and white at 235 in 8 bits; 4096 and 60160 in 16 bits.
      Alpha
      Straight: color and opacity apart. Premultiplied: color already times opacity. Opaque: always full. Undefined: a padding byte that means nothing.
      Channel order
      BGRA stores blue first. Still RGB color, just a different order in memory; zenpixels records it in the layout.
      Stride and subimages
      Bytes from one row start to the next. A PixelSlice can borrow a cropped rectangle and keep its parent's stride. Padding needs sample alignment, not a whole number of pixels; row(y) returns only the view's active pixels.
      Endianness
      Which byte of a multi-byte number comes first. zenpixels uses the CPU's own order; 16-bit PNG files are big-endian, so decoders swap.
      Descriptor
      PixelDescriptor = PixelFormat (type and layout) plus curve, primaries, alpha and range. Same bytes, different descriptor: a different color.
      Native samples
      I16, F64 and friends use PixelFormat::Generic. Identity carriage preserves their bits. General numerical conversion refuses. Integer code interpretation is available separately through SampleEncoding; see the plane examples below.
      CMYK and ICC
      Printer ink amounts. Turning them into screen color needs that printer's ICC profile and a color management system.
      Oklab
      Perceptual color: L is lightness, a runs green to red, b runs blue to yellow. Edits in Oklab look even.
      PQ and HLG
      HDR curves. PQ codes absolute brightness up to 10,000 nits; conversion from relative light needs a white anchor. Mapping HLG into display light needs explicit rendering conditions.
      06

      In Rust

      This example allocates zero-filled storage with the selected format and row layout. The borrowed view can cover the whole image or a crop. See a cropped view in the guide.

      
        
      07

      Converter simulator

      Convert the current stored pixels with the real zenpixels-convert WASM build. Source controls are above; destination controls are below. Alpha discard and depth reduction are allowed; the selected luma weights apply. Unsupported routes return the crate's error.

      Explicit HLG display rendering

      Checking the box explicitly selects the displayed conditions. Gamma includes the caller’s surround assumption. HLG ICC synthesis remains unavailable.

      WASM uses native little-endian samples. The source's displayed byte order is a viewing choice. PQ conversion requires an explicit white anchor. This row converter also needs source and target peaks for tone mapping; whole-buffer conversion can measure the source peak. HLG rendering requires explicit display peak, black, effective gamma and SDR white; supported endpoints use full-range BT.2020 RGB/RGBA. Enable it below. The model uses the PQ anchor selected above. CMYK needs an ICC profile, which this simulator does not supply. General signed/wide numerical conversions are refused; exact code reading is shown in the storage examples.

      Loading optional WASM converter…

      WASM output: all active rows, packed

      
          

      JavaScript model: first output pixel

      
          
      Conversion plan and steps
      08

      Planes, interleaved components and native codes

      PlaneRole::CbCr and CrCb already describe interleaved chroma. CodePlane::component selects one component from interleaved storage, with its own SampleEncoding. Interleaving and RGB10 + alpha1 do not by themselves require a new view type.

      Live examples require the WASM assets.

      
          

      Stored bytes (including row and sample padding)

      
          

      Existing typed plane → component readers

      
          
          

      Rows here omit trailing padding after the final active row. Each code list is one position, in the displayed component order. These are extracted codes, not normalized intensities or rendered colors.

      Scope and remaining limits

      Use ordinary typed planes and component readers for interleaved chroma and RGB10 + alpha1. Each reader retains the relevant sample encoding.

      CodePlane reads U8/U16 codes. SampleEncoding can describe signed/wide payloads, but this does not add signed/wide code readers or arithmetic. Native PixelFormat::Generic identity carriage remains separate.

      Typed multi-byte samples require sample alignment. For RGB565, three CodePlane::new views select different bitfields of the same U16 words. codes::to_canonical can unpack and widen them directly into ordinary RGB pixels.