# Overview

    library(fastpng)

`{fastpng}` reads and writes PNG images.

`{fastpng}` exposes configuration options so that the user can make a trade-off between speed of writing and PNG size. These options include:

- Compression level
- Filter use
- Image transposition

For example, writing uncompressed PNG images can be 100x faster than writing with regular compression settings.

`fastpng` uses libspng - current v0.7.4

## Features

### Supported image data in R

Supported images each have examples in the `test_image` as part of this package.

- Native rasters
- Rasters
  - With hex colour formats: #RGB, #RGBA, #RRGGBB, #RRGGBBAA
  - Standard R colour names also supported e.g. ‘red’, ‘white’
- Numeric arrays
  - Values in range [0,1]
  - 1-, 2-, 3- and 4-plane numeric arrays (interpreted as gray, gray+alpha, RGB and RGBA images)
- Integer arrays
  - Values in range [0,255] treated as 8-bit values
  - Values in range [0,65535] treated as 16-bit for PNG writing
- Integer matrix + an indexed palette of colours
- Raw vectors with a specification for data layout

### Supported PNG image types

- 8-bit and 16-bit PNGs
- RGBA, RGB, Gray + Alpha, Gray PNGs
- Indexed colour PNGs
- RGB PNGs with a specified transparency colour (using tRNS chunk)

### Comparison to standard `{png}` library

| `{fastpng}` | `{png}`
--- | --- | ---
Numeric arrays | Yes | Yes
Native rasters | Yes | Yes
Rasters | Yes |
Integer Arrays | Yes |
Indexed PNGs | Yes |
`tRNS` transparency | Yes |
Configurable compression | Yes |
Configurable filtering | Yes |
Configurable transposition | Yes |

## Compression Settings: Speed / size tradeoff

The following graph shows the speed of writing and the compression ratio for various settings in `fastpng`. A data point for the `png` package is also shown.

## Example: Read a PNG into R

    library(fastpng)
    png_file <- system.file("img", "Rlogo.png", package="png")
    fastpng::get_png_info(png_file)
    #> $width
    #> [1] 100
    #>
    #> $height
    #> [1] 76
    #>
    #> $bit_depth
    #> [1] 8
    #>
    #> $color_type
    #> [1] 6
    #>
    #> $compression_method
    #> [1] 0
    #>
    #> $filter_method
    #> [1] 0
    #>
    #> $interlace_method
    #> [1] 0
    #>
    #> $color_desc
    #> [1] "SPNG_COLOR_TYPE_TRUECOLOR_ALPHA"
    #>
    #> $filter_desc
    #> [1] "SPNG_FILTER_NONE"
    #>
    #> $interlate_desc
    #> [1] "SPNG_INTERLACE_NONE"

    ras <- fastpng::read_png(png_file, type = 'raster')
    grid::grid.raster(ras, interpolate = FALSE)

#### Read as a raster (of hex colours)

    ras <- fastpng::read_png(png_file, type = "raster")
    ras[7:11, 79:83]
    #>      [,1]        [,2]        [,3]        [,4]        [,5]
    #> [1,] "#686D6597" "#7579711F" "#00000000" "#00000000" "#00000000"
    #> [2,] "#5F645CFF" "#5D635AF9" "#63696098" "#7B80781C" "#00000000"
    #> [3,] "#686D64FF" "#61665DFF" "#5B6158FF" "#5C6158F5" "#656A6280"
    #> [4,] "#71766EFF" "#6B6F67FF" "#656A61FF" "#5E635BFF" "#595E55FF"
    #> [5,] "#797D75FF" "#747971FF" "#6E736AFF" "#686D64FF" "#60655DFF"

#### Read as a numeric array

    ras <- fastpng::read_png(png_file, type = "array")
    ras[7:11, 79:83, 1] # red channel
    #>           [,1]      [,2]      [,3]      [,4]      [,5]
    #> [1,] 0.4078431 0.4588235 0.0000000 0.0000000 0.0000000
    #> [2,] 0.3725490 0.3647059 0.3882353 0.4823529 0.0000000
    #> [3,] 0.4078431 0.3803922 0.3568627 0.3607843 0.3960784
    #> [4,] 0.4431373 0.4196078 0.3960784 0.3686275 0.3490196
    #> [5,] 0.4745098 0.4549020 0.4313725 0.4078431 0.3764706

#### Read as an integer array

    ras <- fastpng::read_png(png_file, type = "array", array_type = 'integer')
    ras[7:11, 79:83, 1] # red channel
    #>      [,1] [,2] [,3] [,4] [,5]
    #> [1,]  104  117    0    0    0
    #> [2,]   95   93   99  123    0
    #> [3,]  104   97   91   92  101
    #> [4,]  113  107  101   94   89
    #> [5,]  121  116  110  104   96

#### Read as a native raster

    im <- fastpng::read_png(png_file, type = "nativeraster")
    im[7:11, 79:83]
    #>          [,1] [,2] [,3]     [,4]      [,5]
    #> [1,] -7235693    0    0 -7301485  -7767184
    #> [2,] -7367279    0    0 -7367022  -5864589
    #> [3,] -7498608    0    0 -7301485  -4219764
    #> [4,] -7432815    0    0 -7235692   -995135
    #> [5,] -6648959    0    0 -7501694 -10268343

## Write an image to PNG with/without compression

    png_file <- tempfile()
    fastpng::write_png(im, png_file)  # standard compression
    file.size(png_file)
    #> [1] 11938

    fastpng::write_png(im, png_file, compression_level = 0) # no compression, but fast!
    file.size(png_file)
    #> [1] 30580

## Write integer matrix as indexed PNG

    indices <- test_image$indexed$integer_index
    palette <- test_image$indexed$palette

    dim(indices)
    #> [1] 200 300
    indices[1:10, 1:10]
    #>       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
    #>  [1,]    0    0    0    0    0    0    0    0    0     0
    #>  [2,]    0    0    0    0    0    0    0    0    0     0
    #>  [3,]    0    0    0    0    0    0    0    0    0     1
    #>  [4,]    0    0    0    0    0    0    0    1    1     1
    #>  [5,]    0    0    0    0    0    1    1    1    1     1
    #>  [6,]    0    0    0    0    1    1    1    1    1     1
    #>  [7,]    0    0    0    0    1    1    1    1    1     1
    #>  [8,]    0    0    0    1    1    1    1    1    1     1
    #>  [9,]    0    0    0    1    1    1    1    1    1     2
    #> [10,]    0    0    1    1    1    1    1    1    2     2
    palette[1:10]
    #>  [1] "#440154FF" "#440256FF" "#450457FF" "#450559FF" "#46075AFF" "#46085CFF"
    #>  [7] "#460A5DFF" "#460B5EFF" "#470D60FF" "#470E61FF"

    tmp <- tempfile()
    fastpng::write_png(image = indices, palette = palette, file = tmp)