2017-11-24 04:35:15 +00:00
# nimPNG (PNG + APNG)
Portable Network Graphics Encoder and Decoder written in Nim store lossless image with good compression.
Since version 0.2.0 also support Animated PNG!
2015-08-28 15:56:55 +00:00
2018-10-05 04:50:25 +00:00
[![Build Status (Travis) ](https://img.shields.io/travis/jangko/nimPNG/master.svg?label=Linux%20/%20macOS "Linux/macOS build status (Travis )")](https://travis-ci.org/jangko/nimPNG)
[![Windows build status (Appveyor) ](https://img.shields.io/appveyor/ci/jangko/nimPNG/master.svg?label=Windows "Windows build status (Appveyor )")](https://ci.appveyor.com/project/jangko/nimPNG)
![nimble ](https://img.shields.io/badge/available%20on-nimble-yellow.svg?style=flat-square )
![license ](https://img.shields.io/github/license/citycide/cascade.svg?style=flat-square )
2017-11-04 09:52:17 +00:00
2015-08-28 15:56:55 +00:00
all PNG standard color mode are supported:
- LCT_GREY = 0, # greyscale: 1,2,4,8,16 bit
- LCT_RGB = 2, # RGB: 8,16 bit
- LCT_PALETTE = 3, # palette: 1,2,4,8 bit
- LCT_GREY_ALPHA = 4, # greyscale with alpha: 8,16 bit
- LCT_RGBA = 6 # RGB with alpha: 8,16 bit
both interlaced and non-interlaced mode supported
recognize all PNG standard chunks:
IHDR, IEND, PLTE, IDAT, tRNS, bKGD, pHYs, tIME, iTXt, zTXt
tEXt, gAMA, cHRM, sRGB, iCCP, sBIT, sPLT, hIST
unknown chunks will be handled properly
the following chunks are supported (generated/interpreted) by both encoder and decoder:
- IHDR: header information
- PLTE: color palette
- IDAT: pixel data
- IEND: the final chunk
- tRNS: transparency for palettized images
- tEXt: textual information
- zTXt: compressed textual information
- iTXt: international textual information
- bKGD: suggested background color
- pHYs: physical dimensions
- tIME: modification time
the following chunks are parsed correctly, but not used by decoder:
cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT
Supported color conversions:
- anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA
- any grey or grey+alpha, to grey or grey+alpha
- anything to a palette, as long as the palette has the requested colors in it
- removing alpha channel
2015-09-03 04:56:22 +00:00
- higher to smaller bitdepth, and vice versa
2017-05-12 11:46:09 +00:00
### Planned Feature(s):
2015-09-03 04:56:22 +00:00
- streaming for progressive loading
2015-09-30 05:45:24 +00:00
2017-05-12 11:46:09 +00:00
## Basic Usage
2015-09-30 05:45:24 +00:00
```nimrod
import nimPNG
let png = loadPNG32("image.png")
#is equivalent to:
#let png = loadPNG("image.png", LCT_RGBA, 8)
#will produce rgba pixels:
#png.width -> width of the image
#png.height -> height of the image
#png.data -> pixels data in RGBA format
```
2015-12-09 04:51:30 +00:00
if you already have the whole file in memory:
```nimrod
2015-09-30 05:45:24 +00:00
let png = decodePNG32(raw_bytes)
2015-12-09 04:51:30 +00:00
#will do the same as above
```
2015-09-30 05:45:24 +00:00
other variants:
2015-12-09 04:51:30 +00:00
* loadPNG24 -> will produce pixels in RGB format 8 bpp
* decodePNG24 -> load png from memory instead of file
2015-09-30 05:45:24 +00:00
to create PNG:
2015-12-09 04:51:30 +00:00
* savePNG32("output.png", rgba_pixels, width, height) or savePNG24
* encodePNG32(rgba_pixels, width, height) or encodePNG24
special notes:
2015-09-30 05:45:24 +00:00
2017-11-04 09:52:17 +00:00
* Use **loadPNG** or **savePNG** if you need specific input/output format by supplying supported **colorType** and **bitDepth** information.
2017-11-24 05:40:33 +00:00
* Use **encodePNG** or **decodePNG** to do *in-memory* encoding/decoding by supplying desired **colorType** and **bitDepth** information
2015-09-30 05:45:24 +00:00
2015-12-09 04:51:30 +00:00
pixels are stored as raw bytes using Nim's string as container:
2015-09-30 05:45:24 +00:00
2015-12-09 04:51:30 +00:00
| Byte Order | Format |
|:------------------------------:|:----------------:|
| r1,g1,b1,a1,...,rn,gn,bn,an | RGBA 8 bit |
| r1,g1,b1,r2,g2,b2,...,rn,gn,bn | RGB 8 bit |
| grey1,grey2,grey3, ..., greyn | GREY 8 bit |
| grey1,a1,grey2,a2,...,greyn,an | GREY ALPHA 8 bit |
2017-11-04 09:52:17 +00:00
2017-11-23 17:08:48 +00:00
## Animated PNG (APNG)
2017-11-24 10:58:44 +00:00
Since version 0.2.0, nimPNG provides support for [Animated PNG ](https://en.wikipedia.org/wiki/APNG ).
2017-11-23 17:08:48 +00:00
2017-11-24 04:35:15 +00:00
Both decoder and encoder recognize/generate APNG chunks correctly: acTL, fcTL, fdAT.
Decoded frames is provided as is, the dimension and coordinate offset might be different with default frame.
No alpha blending or other blending method performed.
It is up to the application to do proper in-memory rendering before displaying the animation.
Don't ask how to do it, any decent graphics rendering library have their own set of API to do alpha blending and
offset rendering. In the future nimPNG might be shipped with simple frame rendering utility for common cases.
Right now nimPNG is just a PNG encoder/decoder.
2017-11-23 17:08:48 +00:00
### Decoding
```Nim
2017-11-24 04:35:15 +00:00
#let png = loadPNG32("image.png")
# or
2017-11-23 17:08:48 +00:00
#let png = loadPNG("image.png", LCT_RGBA, 8)
# or
#let png = decodePNG32(raw_bytes)
```
The usual loadPNG and decodePNG can decode both unanimated and animated PNG.
2017-11-24 04:35:15 +00:00
`png.width` , `png.height` , `png.data` works as usual. If the decoded PNG is an APNG, `png.data` will contains default frame.
Animation frames can be accessible via `png.frames` . If it is not an APNG, `png.frames` will be nil.
2017-11-23 17:08:48 +00:00
### Encoding
2017-11-24 10:58:44 +00:00
```Nim
2017-11-24 11:05:36 +00:00
var png = prepareAPNG24(numPlays)
2017-11-24 10:58:44 +00:00
```
2017-11-24 11:05:36 +00:00
* First step is to call `prepareAPNG` , `prepareAPNG24` , or `prepareAPNG32` . You also can specify how many times the animation
2017-11-24 10:58:44 +00:00
will be played
```Nim
png.addDefaultImage(framePixels, w, h, ctl)
```
2017-11-24 11:05:36 +00:00
* Second step is also mandatory, you should call `addDefaultImage` . `ctl` is optional, if you provide a `ctl` (Frame Control),
the default image will be part of the animation. If `ctl` is nil, default image will not be part of animation.
2017-11-24 10:58:44 +00:00
```Nim
png.addFrame(frames[i].data, ctl)
```
2017-11-24 11:05:36 +00:00
* Third step is calling `addFrame` one or more times. Here `ctl` is mandatory.
2017-11-24 10:58:44 +00:00
```Nim
png.saveAPNG("rainbow.png")
# or
var str = png.encodeAPNG()
```
2017-11-24 11:05:36 +00:00
* Final step is to call `saveAPNG` if you want save it to file or call `encodeAPNG` if you want to get the result in a string container
2017-11-24 10:58:44 +00:00
You can read the details of frame control from [spec ](https://wiki.mozilla.org/APNG_Specification ).
You can also see an example in tester/test.nim -> generateAPNG
2018-10-09 01:56:52 +00:00
## Installation via nimble
> nimble install nimPNG