ChunkyPNG
| Language | Ruby (pure Ruby, no native extension) |
|---|---|
| License | MIT |
| Repository | github.com/wvanbergen/chunky_png |
| Documentation | rubydoc.info/gems/chunky_png, wiki |
| Depends on | nothing (Ruby's zlib) |
| Read / write | yes / yes, all color types (16-bit is reduced to 8 bits), text chunks, interlacing |
ChunkyPNG reads and writes PNG in plain Ruby, so it installs anywhere without compiling C code or installing ImageMagick. It gives pixel-level access (each pixel is a 32-bit RGBA integer), simple operations (crop, compose, rotate, flip, nearest-neighbor and bilinear resampling), text metadata and raw chunk access.
It’s slow for large images and uses a lot of memory, since every pixel is a Ruby integer. Use it for small images, generated graphics (badges, sparklines, QR codes) or where native dependencies aren’t allowed. The oily_png gem adds a C extension that speeds up encoding and decoding with the same API.
Installation#
gem install chunky_png
Or in a Gemfile: gem "chunky_png".
Basic usage: read, change and save a PNG#
require "chunky_png"
image = ChunkyPNG::Image.from_file("in.png")
puts "#{image.width} x #{image.height}"
# read a pixel and split it into channels
pixel = image[0, 0]
puts [ChunkyPNG::Color.r(pixel), ChunkyPNG::Color.g(pixel),
ChunkyPNG::Color.b(pixel), ChunkyPNG::Color.a(pixel)].inspect
# draw a half-transparent red square
(0...20).each do |y|
(0...20).each do |x|
image[x, y] = ChunkyPNG::Color.rgba(255, 0, 0, 128)
end
end
image.save("out.png", :best_compression)
How to get PNG width and height without decoding#
Datastream reads the chunks without decoding pixel data:
require "chunky_png"
header = ChunkyPNG::Datastream.from_file("in.png").header_chunk
puts "#{header.width} x #{header.height}, bit depth #{header.depth}, color type #{header.color}"
How to create a PNG from scratch#
require "chunky_png"
png = ChunkyPNG::Image.new(64, 64, ChunkyPNG::Color::TRANSPARENT)
png.rect(8, 8, 55, 55, ChunkyPNG::Color("black"), ChunkyPNG::Color("orange"))
png.circle(32, 32, 12, ChunkyPNG::Color::WHITE, ChunkyPNG::Color("teal"))
png.save("badge.png")
How to read and write PNG text metadata#
metadata maps keys to values of the tEXt and zTXt chunks:
require "chunky_png"
image = ChunkyPNG::Image.from_file("in.png")
image.metadata.each { |key, value| puts "#{key}: #{value}" }
image.metadata["Title"] = "Sunset"
image.metadata["Author"] = "Jane Doe"
image.save("out.png")
How to resize and crop a PNG#
require "chunky_png"
image = ChunkyPNG::Image.from_file("in.png")
thumb = image.resample_bilinear(100, 100) # or resample_nearest_neighbor for pixel art
part = image.crop(10, 10, 200, 150) # x, y, width, height
thumb.save("thumb.png")
part.save("part.png")
Tips#
- Save presets:
:fast_rgba,:fast_rgb,:best_compression,:good_compression,:no_compression,:black_and_white. Without a preset ChunkyPNG picks the smallest color mode that fits the pixels. image.to_blobreturns the PNG as a string, e.g. for a Railssend_dataresponse.ChunkyPNG::Datastream#each_chunklists every chunk with its type, for debugging files.