Project

tessel

0.0
The project is in a healthy, maintained state
A dependency-light PNG reader/writer and shared RGBA8 pixel surface.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

Tessel

Dependency-light image I/O and mutable RGBA8 image surfaces for Ruby graphics.

Gem Version Downloads Ruby Version License

Features · Installation · Quick Start


Tessel is the shared pixel layer for the rbgfx ecosystem. It reads and writes common image formats and gives drawing code a small, predictable RGBA8 surface.

Features

  • PNG decoding and encoding, including filters, Adam7 interlace, palettes, and text metadata.
  • PPM (P3/P6) and BMP (24/32-bit) input and output.
  • Straight-alpha RGBA8 pixels with row-major, top-down storage.
  • Clipped rectangles, horizontal spans, alpha blits, masks, crop, and resize.
  • Median-cut palettes, fixed palettes, nearest-color mapping, and ordered or Floyd–Steinberg dithering for indexed image output.
  • Explicit decode, unsupported-format, and pixel-limit errors.
  • Optional RBGL framebuffer conversion.

Installation

Add Tessel to your Gemfile:

gem "tessel"

Then run:

bundle install

Or install the released gem directly:

gem install tessel

Requirements

  • Ruby 3.1 or newer.
  • No runtime gems beyond Ruby's standard library are required.

Quick Start

require "tessel"

image = Tessel::Image.new(320, 180, fill: "#101827")
image.fill_rect(20, 20, 80, 40, "#e85d75")
image.write("out.png", filter: :adaptive)

copy = Tessel.read("out.png")
puts [copy.width, copy.height, copy[20, 20]].inspect

palette = Tessel::Quantize.palette_for([image, copy], colors: 32)
indices, palette = Tessel::Quantize.quantize(image, palette: palette, dither: :floyd_steinberg)
puts "#{indices.bytesize} indexed pixels, #{palette.length} colors"

Use fill_rect, hspan, blit, and blit_mask for drawing. Image operations clip to the surface boundaries.

Tessel::Quantize.palette_for(images, colors:) samples visible pixels from one image or an array of images and builds a deterministic median-cut RGB palette. Quantize.quantize(image, palette:, dither:) returns a binary string with one palette index per pixel and the palette used. Supported dithering modes are :none, :ordered, and :floyd_steinberg. Transparent pixels do not affect palette generation. fixed_palette returns the 6×6×6 color cube plus 40 gray levels; web_safe_palette returns the 216 web-safe colors.

Development

bundle install
bundle exec rake verify

Performance scripts are available for local, workload-specific checks:

ruby bench/decode_bench.rb
ruby bench/encode_bench.rb
ruby bench/raster_bench.rb

Contributing

Bug reports and pull requests are welcome at rbgfx/tessel.

License

MIT