Skip to content
Anderson edited this page May 5, 2023 · 11 revisions

ChunkyPNG is a pure Ruby library to read and write PNG images and access textual metadata. It has no dependency on RMagick, or any other library for that matter.

See the API documentation on rubydoc.info/gems/chunky_png/frames for more information. Also, take a look at the Changelog to see what’s new.

Features

  • Decodes any image that the PNG standard allows. This includes all standard color modes with different bit depths and all transparency, interlacing and filtering options.

  • Encodes images supports all color modes (true color, grayscale and indexed) and transparency for all these color modes. The best color mode will be chosen automatically, based on the image’s colors.

  • R/W access to the image’s pixels.

  • R/W access to all image metadata that is stored in chunks.

  • Alpha composition of different images.

  • Memory efficient (uses a Fixnum, i.e. 4 or 8 bytes of memory per pixel, depending on the machine)

  • Reasonably fast for Ruby standards, by only using integer math and a optimized encoding routine. If the performance is not enough have a look at OilyPNG (see github.com/wvanbergen/oily_png), a mixin module that replaces the slowest routines with a C-based implementation.

  • Interoperability with RMagick if you really need to.

Loading image data

You can load PNG from files, IO streams or binary string:

image = ChunkyPNG::Image.from_file('file.png')
File.open('file.png', 'rb') { |io| image = ChunkyPNG::Image.from_io(io) }
image = ChunkyPNG::Image.from_blob(File.read('file.png'))

Using raw RGB(A) streams

Decoding PNG files is slow. If you can control the input data, consider supplying the pixel data as an RGBA or RGB formatted stream, in which all pixels are encoded from left to right, top to bottom, using 1 byte per channel:

image = ChunkyPNG::Image.from_rgba_stream(width, height, File.read('pixeldata.rgba')) # or
image = ChunkyPNG::Image.from_rgb_stream(width, height, File.read('pixeldata.rgb'))

Loading these kinds of streams is 1500% faster (!) than loading the same image encoded as PNG.

Manipulating images

ChunkyPNG comes with a small library of image manipulation functions, e.g.:

image = ChunkyPNG::Image.from_file('filename.png')
image[0, 0] = ChunkyPNG::Color.rgba(255, 0,0, 128)
image.line(1, 1, 10, 1, ChunkyPNG::Color.from_hex('#aa007f'))
new_image = image.flip_horizontally.rotate_right
image.compose(ChunkyPNG::Image.new(16, 16, ChunkyPNG::Color.rgba(10, 10, 10, 128)))

See the RDoc documentation for drawing methods at rubydoc.info/gems/chunky_png/ChunkyPNG/Canvas/Drawing and composition operations at rubydoc.info/gems/chunky_png/ChunkyPNG/Canvas/Operations for more information.

Saving image data

You can encode an image to a file, IO stream, or binary string:

image.save('filename.png')
File.open('newfile.png', 'wb' ) { |io| image.write(io) }
binary_string = image.to_blob

Encoding options

ChunkyPNG tries to detect the optimal encoding parameters when saving an image. The detection costs some time, and it may choose a slow encoding method. To override the detection mechanism, and always save as RGB or RGBA image, use the @:fast_rgba@ or @:fast_rgb@ modifier when calling save:

image.save('filename.png', :fast_rgb) # for RGB only images.
png_data = image.to_blob(:fast_rgba) # or for RGBA images.

Note that this may result in bloated files, especially if the image uses little colors. The get the smallest images possible by sacrificing speed, use the following call:

image.save('filename.png', :best_compression)

Instead of these options, you can also use a hash with specific options, e.g.:

image.save('filename.png', :color_mode => ChunkyPNG::COLOR_INDEXED, 
           :compression => Zlib::NO_COMPRESSION, :interlace => true)

See the RDoc documentation for the to_datastream method at rubydoc.info/gems/chunky_png/ChunkyPNG/Canvas/PNGEncoding#to_datastream-instance_method to see what options are available.

Development

Contributions are gladly accepted, but keep the following in mind:

  • Fork the project, and commit your changes.

  • Always add specs, so I won’t break your newly added functionality.

  • Add yardoc style comments (see yardoc.org) to your code so we always have up-to-date documentation.

  • No hard tabs or trailing whitespace please. This drives me MAD!

  • Send me a pull request.

After you have submitted a patch that convinces me that you understand the internals of the library, I can add you as a collaborator to the project if you wish.

More information

This library is MIT licensed and tested against all currently supported Ruby versions. Other Ruby versions and implementations may work as well, but support is not tested or guaranteed.

Also, see the homepage of ChunkyPNG for more information: www.chunkypng.com