Dumb PNG output (Java)
This Java library takes an array of pixel values and writes it as a PNG image file. My simple implementation is inefficient in many ways, but it behaves correctly and produces legal PNG files. The whole program is only about 140 lines of code long.
The PNG file format is widely supported for because it flexibly supports many color formats and has compression built in. (By contrast, the Windows BMP format has no compression, and the GIF format was patented in the past.) When I read the PNG file format specification, I realized that writing a basic compliant encoder wasn’t too difficult and wouldn’t take too much code. Thus this is the result of my effort.
Source code
The provided code includes two items:
A demo main program which shows you how to use the library. It writes a sanity check 3×2 image to disk.
A public API method
DumbPngOutput.write(int[][] image, OutputStream out)
.
Download: DumbPngOutput.java. License: MIT (open source).
Notes
This library only supports writing RGB24 (RGB 8.8.8) images. No alpha, no paletted types, no other color depths. The image dimensions must be at least 1×1. The top 8 bits of pixel values are ignored.
The code has no dependencies other than the standard Java libraries. It uses I/O, buffering, CRC-32, and Adler-32 from Java standard libraries, but it implements image representation, PNG encoding, zlib container, and DEFLATE compression by itself.
The implementation buffers the entire image in memory multiple times, so when writing big images you may run out of memory during execution. If your image has more than about 700 million pixels, then this implementation will necessarily fail due to Java arrays being limited to less than 231 in size. Otherwise, failure will depend on the amount of overhead in DEFLATE, the amount of physical and virtual memory on your system, and the use of a 64-bit Java virtual machine.
While this implementation may run out of memory in cases where a better implementation won’t, the logic is structured so that it will never write corrupt data (due to overflow, etc.).
By replacing the logic of
deflate()
to instead utilizejava.util.zip.DeflaterOutputStream
, you can actually achieve decent compression with this “dumb” PNG output library.
References
If you want to write your own PNG encoder entirely from scratch (including the compression), these are the reference documents you need to read:
- W3C: Portable Network Graphics (PNG) Specification (Second Edition)
- RFC 1950: ZLIB Compressed Data Format Specification version 3.3
- RFC 1951: DEFLATE Compressed Data Format Specification version 1.3