Module: Libpng

Defined in:
lib/libpng.rb,
lib/libpng/error.rb,
lib/libpng/recipe.rb,
lib/libpng/binding.rb,
lib/libpng/version.rb,
lib/libpng/text_writer.rb,
lib/libpng/chunk_walker.rb,
lib/libpng/decoded_image.rb,
lib/libpng/bytes_per_pixel.rb,
lib/libpng/metadata_writer.rb,
lib/libpng/standard_decoder.rb,
lib/libpng/standard_encoder.rb,
lib/libpng/simplified_decoder.rb,
lib/libpng/simplified_encoder.rb

Overview

Libpng is a Ruby binding for libpng (the official PNG reference library) via FFI. The native library is pre-compiled for each target platform and shipped inside the gem, so no C compiler is required at install time.

Public API:

Libpng.encode(width, height, rgba_bytes, pixel_format: "RGBA")
Libpng.encode_standard(width, height, rgba_bytes, pixel_format: "RGBA", ...)
Libpng.decode(png_bytes, pixel_format: "RGBA")

All encode/decode state is per-call. Each call constructs a dedicated encoder or decoder instance, runs it, and discards it. Calls from different Ractors do not share state. The FFI function table (Libpng::Binding) loads lazily on first use and is shareable across Ractors.

Defined Under Namespace

Modules: Binding, BytesPerPixel, MetadataWriter, TextWriter Classes: ChunkWalker, DecodedImage, Error, Recipe, SimplifiedDecoder, SimplifiedEncoder, StandardDecoder, StandardEncoder, TextEntry

Constant Summary collapse

FORMAT_FLAG_ALPHA =

PNG_IMAGE_FORMAT_* bit flags (png.h). Used by the simplified API.

0x01
FORMAT_FLAG_COLOR =
0x02
FORMAT_FLAG_LINEAR =
0x04
FORMAT_FLAG_COLORMAP =
0x08
FORMAT_FLAG_BGR =
0x10
FORMAT_FLAG_AFIRST =
0x20
FORMAT_FLAG_ASSOCIATED_ALPHA =
0x40
FORMAT_GRAY =
0
FORMAT_GA =
FORMAT_FLAG_ALPHA
FORMAT_AG =
FORMAT_FLAG_ALPHA | FORMAT_FLAG_AFIRST
FORMAT_RGB =
FORMAT_FLAG_COLOR
FORMAT_BGR =
FORMAT_FLAG_COLOR | FORMAT_FLAG_BGR
FORMAT_RGBA =
FORMAT_FLAG_COLOR | FORMAT_FLAG_ALPHA
FORMAT_ARGB =
FORMAT_FLAG_COLOR | FORMAT_FLAG_ALPHA | FORMAT_FLAG_AFIRST
FORMAT_BGRA =
FORMAT_FLAG_COLOR | FORMAT_FLAG_ALPHA | FORMAT_FLAG_BGR
FORMAT_ABGR =
FORMAT_FLAG_COLOR | FORMAT_FLAG_ALPHA | FORMAT_FLAG_AFIRST | FORMAT_FLAG_BGR
FORMAT_BY_NAME =
{
  'GRAY' => FORMAT_GRAY,
  'GRAYSCALE' => FORMAT_GRAY,
  'GA' => FORMAT_GA,
  'AG' => FORMAT_AG,
  'RGB' => FORMAT_RGB,
  'BGR' => FORMAT_BGR,
  'RGBA' => FORMAT_RGBA,
  'ARGB' => FORMAT_ARGB,
  'BGRA' => FORMAT_BGRA,
  'ABGR' => FORMAT_ABGR
}.freeze
COLOR_MASK_PALETTE =

Standard-API color types (png.h).

0x01
COLOR_MASK_COLOR =
0x02
COLOR_MASK_ALPHA =
0x04
COLOR_TYPE_GRAY =
0
COLOR_TYPE_PALETTE =
COLOR_MASK_COLOR | COLOR_MASK_PALETTE
COLOR_TYPE_RGB =
COLOR_MASK_COLOR
COLOR_TYPE_RGB_ALPHA =
COLOR_MASK_COLOR | COLOR_MASK_ALPHA
COLOR_TYPE_GRAY_ALPHA =
COLOR_MASK_ALPHA
FORMAT_TO_COLOR_TYPE =
{
  gray: COLOR_TYPE_GRAY,
  ga: COLOR_TYPE_GRAY_ALPHA,
  ag: COLOR_TYPE_GRAY_ALPHA,
  rgb: COLOR_TYPE_RGB,
  rgba: COLOR_TYPE_RGB_ALPHA,
  palette: COLOR_TYPE_PALETTE
}.freeze
INTERLACE_NONE =

png_set_IHDR pass-through constants (png.h).

0
INTERLACE_ADAM7 =
1
COMPRESSION_TYPE_DEFAULT =
0
FILTER_TYPE_DEFAULT =
0
TRANSFORM_IDENTITY =
0x0000
INTERLACE_BY_NAME =
{
  none: INTERLACE_NONE,
  adam7: INTERLACE_ADAM7
}.freeze
FILTER_HEURISTIC_DEFAULT =

png_set_filter bitmask (PNG_FILTER_*).

0
FILTER_NONE =
0x08
FILTER_SUB =
0x10
FILTER_UP =
0x20
FILTER_AVG =
0x40
FILTER_PAETH =
0x80
FILTER_ALL =
FILTER_NONE | FILTER_SUB | FILTER_UP | FILTER_AVG | FILTER_PAETH
FILTER_MASK_BY_NAME =
{
  default: nil,
  adaptive: FILTER_ALL,
  none: FILTER_NONE,
  sub: FILTER_SUB,
  up: FILTER_UP,
  avg: FILTER_AVG,
  paeth: FILTER_PAETH,
  all: FILTER_ALL
}.freeze
TEXT_COMPRESSION_NONE =

PNG_TEXT_COMP_* (compression field of png_text struct). Used by the write path to choose tEXt / zTXt / iTXt output. libpng's own constants are PNG_TEXT_COMPRESSION_NONE,zTXt,iTXt_KEY; we use SCREAMING_SNAKE_CASE per Ruby convention.

-1 # tEXt
TEXT_COMPRESSION_ZTXT_KEY =

tEXt

0
TEXT_COMPRESSION_ITXT_KEY =

zTXt (zlib)

1
TEXT_COMPRESSION_LAST =

iTXt (no compression by default)

2
TEXT_COMPRESSION_BY_NAME =

marker; not used as a real value

{
  text: TEXT_COMPRESSION_NONE,
  ztxt: TEXT_COMPRESSION_ZTXT_KEY,
  itxt: TEXT_COMPRESSION_ITXT_KEY
}.freeze
SRGB_INTENT_PERCEPTUAL =

sRGB rendering intents (png.h).

0
SRGB_INTENT_RELATIVE_COLORIMETRIC =
1
SRGB_INTENT_SATURATION =
2
SRGB_INTENT_ABSOLUTE =
3
PHYS_TYPE_UNKNOWN =

pHYs unit types (png.h).

0
PHYS_TYPE_METER =
1
INCH_PER_METER =

Meters-per-inch (1 inch = 0.0254 m). Used to convert pHYs pixels-per-meter to DPI: dpi = ppm * 0.0254.

0.0254
PNG_INFO_IHDR =

PNG_INFO_* bit flags (png.h). Returned by png_get_valid to test which chunks are present in an info_ptr. Renamed to SCREAMING_SNAKE to match Ruby convention; libpng uses mixed case (PNG_INFO_tRNS, PNG_INFO_bKGD, etc.) which doesn't pass Ruby style checks.

0x0001
PNG_INFO_PLTE =
0x0002
PNG_INFO_TRNS =
0x0004
PNG_INFO_BKGD =
0x0008
PNG_INFO_HIST =
0x0010
PNG_INFO_PHYS =
0x0020
PNG_INFO_OFFS =
0x0040
PNG_INFO_TIME =
0x0080
PNG_INFO_PCAL =
0x0100
PNG_INFO_SRGB =
0x0200
PNG_INFO_ICCP =
0x0400
PNG_INFO_SBIT =
0x0800
PNG_INFO_SPLT =
0x1000
PNG_INFO_IDAT =
0x2000
PNG_INFO_ACTL =
0x4000
PNG_INFO_EXIF =
0x8000
PNG_INFO_GAMA =
0x10000
PNG_INFO_CHRM =
0x20000
RGB_TO_GRAY_DEFAULT =

png_set_rgb_to_gray error_action values.

1
RGB_TO_GRAY_WARN =

silent

2
RGB_TO_GRAY_ERR =

warn on error

3
FILLER_BEFORE =

png_set_filler / png_set_add_alpha filler_position values. Matches png.h: PNG_FILLER_BEFORE = 0, PNG_FILLER_AFTER = 1.

0
FILLER_AFTER =
1
LIBPNG_VER_STRING_C =

PNG_LIBPNG_VER_STRING. The C string passed as user_png_ver to png_create_write_struct. libpng checks this against its compiled-in version; mismatches return NULL. Must match the libpng16 binary we ship, which is 1.6.58.

LIBPNG_VERSION
PNG_IMAGE_VERSION =

png_image struct field offsets (bytes). Used by SimplifiedEncoder / SimplifiedDecoder to allocate the png_image struct via a raw FFI::MemoryPointer (rather than FFI::Struct, which has class-level state that isn't shareable across non-main Ractors).

1
PNG_IMAGE_MESSAGE_BYTES =
64
PNG_IMAGE_SIZE =
FFI.type_size(:pointer) + (7 * 4) + PNG_IMAGE_MESSAGE_BYTES
PNG_IMAGE_OFF_OPAQUE =
0
PNG_IMAGE_OFF_VERSION =
FFI.type_size(:pointer)
PNG_IMAGE_OFF_WIDTH =
PNG_IMAGE_OFF_VERSION + 4
PNG_IMAGE_OFF_HEIGHT =
PNG_IMAGE_OFF_WIDTH + 4
PNG_IMAGE_OFF_FORMAT =
PNG_IMAGE_OFF_HEIGHT + 4
PNG_IMAGE_OFF_FLAGS =
PNG_IMAGE_OFF_FORMAT + 4
PNG_IMAGE_OFF_COLORMAP_ENTRIES =
PNG_IMAGE_OFF_FLAGS + 4
PNG_IMAGE_OFF_WARNING_OR_ERROR =
PNG_IMAGE_OFF_COLORMAP_ENTRIES + 4
PNG_IMAGE_OFF_MESSAGE =
PNG_IMAGE_OFF_WARNING_OR_ERROR + 4
LIBPNG_VERSION =

Gem version follows the pattern:

{LIBPNG_VERSION}.{LIBPNG_RUBY_ITERATION}

where LIBPNG_VERSION is the upstream libpng release this gem is built against, and LIBPNG_RUBY_ITERATION is a counter for Ruby-side changes (recipe bug fixes, CI changes, docs) that bump without a new libpng release. The iteration resets to 0 each time LIBPNG_VERSION bumps.

'1.6.58'
LIBPNG_RUBY_ITERATION =
5
VERSION =
"#{LIBPNG_VERSION}.#{LIBPNG_RUBY_ITERATION}"

Class Method Summary collapse

Class Method Details

.decode(png, **opts) ⇒ Object

Decode a PNG buffer via libpng's simplified read API. Returns a DecodedImage with width/height/format/pixels plus IHDR fields and text/color/phys metadata (parsed via ChunkWalker).



262
263
264
# File 'lib/libpng.rb', line 262

def decode(png, **opts)
  SimplifiedDecoder.new(png, **opts).call
end

.decode_standard(png, **opts) ⇒ Object

Decode a PNG buffer via libpng's standard read API (png_create_read_struct -> png_read_info -> optional transforms -> png_read_image). Use this instead of decode when you need explicit control over which transforms apply. Returns a DecodedImage with the same metadata fields as decode.



271
272
273
# File 'lib/libpng.rb', line 271

def decode_standard(png, **opts)
  StandardDecoder.new(png, **opts).call
end

.encode(width, height, pixels, **opts) ⇒ Object

Encode raw pixels via the simplified API. Output is post- processed to strip sRGB/gAMA/cHRM/iCCP chunks unless strip_colorspace: false.



246
247
248
# File 'lib/libpng.rb', line 246

def encode(width, height, pixels, **opts)
  SimplifiedEncoder.new(width, height, pixels, **opts).call
end

.encode_standard(width, height, pixels, **opts) ⇒ Object

Encode raw pixels via the standard write API. Accepts filter, compression_level, interlace, bit_depth, and palette options, plus text/gamma/srgb_intent/chromaticities/icc_profile/phys metadata writers. Emits only the chunks libpng's standard path produces (no post-hoc stripping needed).



255
256
257
# File 'lib/libpng.rb', line 255

def encode_standard(width, height, pixels, **opts)
  StandardEncoder.new(width, height, pixels, **opts).call
end