diff --git a/pixie.nimble b/pixie.nimble
index 6ba1661..3604207 100644
--- a/pixie.nimble
+++ b/pixie.nimble
@@ -1,3 +1,4 @@
+packageName = "pixie"
 version     = "0.0.1"
 author      = "Andre von Houck and Ryan Oldenburg"
 description = "Full-featured 2d graphics library for Nim."
@@ -9,4 +10,4 @@ requires "nim >= 1.2.6"
 requires "vmath >= 0.3.2"
 requires "chroma >= 0.1.5"
 requires "zippy >= 0.3.5"
-requires "flatty >= 0.1.1"
+requires "flatty >= 0.1.2"
diff --git a/src/pixie.nim b/src/pixie.nim
index 7d71504..9cf7e6a 100644
--- a/src/pixie.nim
+++ b/src/pixie.nim
@@ -1,7 +1,7 @@
 ## Public interface to you library.
 
-import pixie/images, pixie/masks, pixie/paths
-export images, masks, paths
+import pixie/images, pixie/masks, pixie/paths, pixie/common
+export images, masks, paths, PixieError
 
 proc toMask*(image: Image): Mask =
   ## Converts an Image to a Mask.
diff --git a/src/pixie/fileformats/png.nim b/src/pixie/fileformats/png.nim
new file mode 100644
index 0000000..3a75136
--- /dev/null
+++ b/src/pixie/fileformats/png.nim
@@ -0,0 +1,443 @@
+import chroma, pixie/images, pixie/common, math, zippy, zippy/crc, flatty/binny
+
+# See http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html
+
+type
+  ChunkCounts = object
+    PLTE, IDAT: uint8
+
+  PngHeader = object
+    width, height: int
+    bitDepth, colorType, compressionMethod, filterMethod, interlaceMethod: uint8
+
+template failInvalid() =
+  raise newException(PixieError, "Invalid PNG buffer, unable to load")
+
+# template failCRC() =
+#   raise newException(PixieError, "CRC check failed")
+
+when defined(release):
+  {.push checks: off.}
+
+proc parseHeader(data: seq[uint8]): PngHeader =
+  result.width = data.readUint32(0).swap().int
+  result.height = data.readUint32(4).swap().int
+  result.bitDepth = data[8]
+  result.colorType = data[9]
+  result.compressionMethod = data[10]
+  result.filterMethod = data[11]
+  result.interlaceMethod = data[12]
+
+  if result.width == 0 or result.width > int32.high.int:
+    raise newException(PixieError, "Invalid PNG width")
+
+  if result.height == 0 or result.height > int32.high.int:
+    raise newException(PixieError, "Invalid PNG height")
+
+  template failInvalidCombo() =
+    raise newException(
+      PixieError, "Invalid PNG color type and bit depth combination"
+    )
+
+  case result.colorType:
+  of 0:
+    if result.bitDepth notin [1.uint8, 2, 4, 8, 16]:
+      failInvalidCombo()
+  of 2:
+    if result.bitDepth notin [8.uint8, 16]:
+      failInvalidCombo()
+  of 3: # PLTE chunk is required, sample depth is always 8 bits
+    if result.bitDepth notin [1.uint8, 2, 4, 8]:
+      failInvalidCombo()
+  of 4:
+    if result.bitDepth notin [8.uint8, 16]:
+      failInvalidCombo()
+  of 6:
+    if result.bitDepth notin [8.uint8, 16]:
+      failInvalidCombo()
+  else:
+    failInvalidCombo()
+
+  if result.compressionMethod != 0:
+    raise newException(PixieError, "Invalid PNG compression method")
+
+  if result.filterMethod != 0:
+    raise newException(PixieError, "Invalid PNG filter method")
+
+  if result.interlaceMethod notin [0.uint8, 1]:
+    raise newException(PixieError, "Invalid PNG interlace method")
+
+  # Not yet supported:
+
+  if result.bitDepth == 16:
+    raise newException(PixieError, "PNG 16 bit depth not yet supported")
+
+  if result.interlaceMethod != 0:
+    raise newException(PixieError, "Interlaced PNG not yet supported")
+
+proc parsePalette(data: seq[uint8]): seq[array[3, uint8]] =
+  if data.len == 0 or data.len mod 3 != 0:
+    failInvalid()
+
+  result.setLen(data.len div 3)
+
+  for i in 0 ..< data.len div 3:
+    result[i] = cast[ptr array[3, uint8]](data[i * 3].unsafeAddr)[]
+
+proc unfilter(
+  uncompressed: seq[uint8], height, rowBytes, bpp: int
+): seq[uint8] =
+  result.setLen(uncompressed.len - height)
+
+  template uncompressedIdx(x, y: int): int =
+    x + y * (rowBytes + 1)
+
+  template unfiteredIdx(x, y: int): int =
+    x + y * rowBytes
+
+  # Unfilter the image data
+  for y in 0 ..< height:
+    let filterType = uncompressed[uncompressedIdx(0, y)]
+    for x in 0 ..< rowBytes:
+      var value = uncompressed[uncompressedIdx(x + 1, y)]
+      case filterType:
+      of 0: # None
+        discard
+      of 1: # Sub
+        if x - bpp >= 0:
+          value += result[unfiteredIdx(x - bpp, y)]
+      of 2: # Up
+        if y - 1 >= 0:
+          value += result[unfiteredIdx(x, y - 1)]
+      of 3: # Average
+        var left, up: int
+        if x - bpp >= 0:
+          left = result[unfiteredIdx(x - bpp, y)].int
+        if y - 1 >= 0:
+          up = result[unfiteredIdx(x, y - 1)].int
+        value += ((left + up) div 2).uint8
+      of 4: # Paeth
+        var left, up, upLeft: int
+        if x - bpp >= 0:
+          left = result[unfiteredIdx(x - bpp, y)].int
+        if y - 1 >= 0:
+          up = result[unfiteredIdx(x, y - 1)].int
+        if x - bpp >= 0 and y - 1 >= 0:
+          upLeft = result[unfiteredIdx(x - bpp, y - 1)].int
+        proc paethPredictor(a, b, c: int): int {.inline.} =
+          let
+            p = a + b - c
+            pa = abs(p - a)
+            pb = abs(p - b)
+            pc = abs(p - c)
+          if pa <= pb and pa <= pc:
+            a
+          elif pb <= pc:
+            b
+          else:
+            c
+        value += paethPredictor(up, left, upLeft).uint8
+      else:
+        discard # Not possible, parseHeader validates
+
+      result[unfiteredIdx(x, y)] = value
+
+proc parseImageData(
+  header: PngHeader, palette: seq[array[3, uint8]], data: seq[uint8]
+): seq[ColorRGBA] =
+  result.setLen(header.width * header.height)
+
+  let
+    uncompressed = try: uncompress(data) except ZippyError: failInvalid()
+    valuesPerPixel =
+      case header.colorType:
+      of 0:
+        1
+      of 2:
+        3
+      of 3:
+        1
+      of 4:
+        2
+      of 6:
+        4
+      else:
+        0 # Not possible, parseHeader validates
+    valuesPerByte = 8 div header.bitDepth.int
+    rowBytes = ceil((header.width.int * valuesPerPixel) / valuesPerByte).int
+    totalBytes = rowBytes * header.height.int
+
+  # Uncompressed image data should be the total bytes of pixel data plus
+  # a filter byte for each row.
+  if uncompressed.len != totalBytes + header.height.int:
+    failInvalid()
+
+  let unfiltered = unfilter(
+    uncompressed,
+    header.height,
+    rowBytes,
+    max(valuesPerPixel div valuesPerByte, 1)
+  )
+
+  var bytePos, bitPos: int
+  for y in 0 ..< header.height:
+    for x in 0 ..< header.width:
+      var rgba: array[4, uint8]
+      case header.colorType:
+      of 0:
+        var value = unfiltered[bytePos]
+        case header.bitDepth:
+        of 1:
+          value = (value shr (7 - bitPos)) and 1
+          value *= 255
+          inc bitPos
+        of 2:
+          value = (value shr (6 - bitPos)) and 3
+          value *= 85
+          inc(bitPos, 2)
+        of 4:
+          value = (value shr (4 - bitPos)) and 15
+          value *= 17
+          inc(bitPos, 4)
+        of 8:
+          inc bytePos
+        else:
+          discard # Not possible, parseHeader validates
+
+        if bitPos == 8:
+          inc bytePos
+          bitPos = 0
+        rgba = [value, value, value, 255]
+      of 2:
+        let rgb = cast[ptr array[3, uint8]](unfiltered[bytePos].unsafeAddr)[]
+        rgba = [rgb[0], rgb[1], rgb[2], 255]
+        inc(bytePos, 3)
+      of 3:
+        var value = unfiltered[bytePos]
+        case header.bitDepth:
+        of 1:
+          value = (value shr (7 - bitPos)) and 1
+          inc bitPos
+        of 2:
+          value = (value shr (6 - bitPos)) and 3
+          inc(bitPos, 2)
+        of 4:
+          value = (value shr (4 - bitPos)) and 15
+          inc(bitPos, 4)
+        of 8:
+          inc bytePos
+        else:
+          discard # Not possible, parseHeader validates
+
+        if bitPos == 8:
+          inc bytePos
+          bitPos = 0
+        if value.int >= palette.len:
+          failInvalid()
+        let rgb = palette[value]
+        rgba = [rgb[0], rgb[1], rgb[2], 255]
+      of 4:
+        rgba = [
+          unfiltered[bytePos],
+          unfiltered[bytePos],
+          unfiltered[bytePos],
+          unfiltered[bytePos + 1]
+        ]
+        inc(bytePos, 2)
+      of 6:
+        rgba = cast[array[4, uint8]](unfiltered.readUint32(bytePos))
+        inc(bytePos, 4)
+      else:
+        discard # Not possible, parseHeader validates
+
+      result[x + y * header.width] = cast[ColorRGBA](rgba)
+
+    # If we move to a new row, skip to the next full byte
+    if bitPos > 0:
+      inc bytePos
+      bitPos = 0
+
+proc decodePng*(data: seq[uint8]): Image =
+  ## Decodes the PNG from the parameter buffer. Check png.channels and
+  ## png.bitDepth to see how the png.data is formatted.
+  ## The returned png.data is currently always RGBA (4 channels)
+  ## with bitDepth of 8.
+
+  if data.len < (8 + (8 + 13 + 4) + 4): # Magic bytes + IHDR + IEND
+    failInvalid()
+
+  # PNG file signature
+  let signature = cast[array[8, uint8]](data.readUint64(0))
+  if signature != [137.uint8, 80, 78, 71, 13, 10, 26, 10]:
+    failInvalid()
+
+  var
+    pos = 8 # After signature
+    counts = ChunkCounts()
+    header: PngHeader
+    palette: seq[array[3, uint8]]
+    imageData: seq[uint8]
+    prevChunkType: string
+
+  # First chunk must be IHDR
+  if data.readUint32(pos).swap() != 13 or
+    data.readStr(pos + 4, 4) != "IHDR":
+    failInvalid()
+  inc(pos, 8)
+  header = parseHeader(data[pos ..< pos + 13])
+  prevChunkType = "IHDR"
+  inc(pos, 13)
+
+  # if crc32(data[pos - 17 ..< pos]) != read32be(data, pos):
+  #   failCRC()
+  inc(pos, 4) # CRC
+
+  while true:
+    if pos + 8 > data.len:
+      failInvalid()
+
+    let
+      chunkLen = data.readUint32(pos).swap().int
+      chunkType = data.readStr(pos + 4, 4)
+    inc(pos, 8)
+
+    if chunkLen > high(int32).int:
+      failInvalid()
+
+    if pos + chunkLen + 4 > data.len:
+      failInvalid()
+
+    case chunkType:
+    of "IHDR":
+      failInvalid()
+    of "PLTE":
+      inc counts.PLTE
+      if counts.PLTE > 1 or counts.IDAT > 0:
+        failInvalid()
+      palette = parsePalette(data[pos ..< pos + chunkLen])
+    of "IDAT":
+      inc counts.IDAT
+      if counts.IDAT > 1 and prevChunkType != "IDAT":
+        failInvalid()
+      if header.colorType == 3 and counts.PLTE == 0:
+        failInvalid()
+      let op = imageData.len
+      imageData.setLen(imageData.len + chunkLen)
+      copyMem(imageData[op].addr, data[pos].unsafeAddr, chunkLen)
+    of "IEND":
+      if chunkLen != 0:
+        failInvalid()
+    else:
+      let bytes = cast[seq[uint8]](chunkType)
+      if (bytes[0] and 0b00100000) == 0:
+        raise newException(
+          PixieError, "Unrecognized PNG critical chunk " & chunkType
+        )
+
+    inc(pos, chunkLen)
+
+    # if crc32(data[pos - chunkLen - 4 ..< pos]) != read32be(data, pos):
+    #   failCRC()
+    inc(pos, 4) # CRC
+
+    prevChunkType = chunkType
+
+    if pos == data.len:
+      break
+
+  if prevChunkType != "IEND":
+    failInvalid()
+
+  result = Image()
+  result.width = header.width
+  result.height = header.height
+  result.data = parseImageData(header, palette, imageData)
+
+proc encodePng*(
+  width, height, channels: int, data: pointer, len: int
+): seq[uint8] =
+  ## Encodes the image data into the PNG file format.
+
+  if width <= 0 or width > int32.high.int:
+    raise newException(PixieError, "Invalid PNG width")
+
+  if height <= 0 or height > int32.high.int:
+    raise newException(PixieError, "Invalid PNG height")
+
+  if len != width * height * channels:
+    raise newException(PixieError, "Invalid PNG data size")
+
+  let colorType = block:
+    case channels:
+    of 1:
+      0.uint8
+    of 2:
+      4
+    of 3:
+      2
+    of 4:
+      6
+    else:
+      raise newException(PixieError, "Invalid PNG number of channels")
+
+  # Add the PNG file signature
+  result.add([137.uint8, 80, 78, 71, 13, 10, 26, 10])
+
+  # Add IHDR
+  result.addUint32(13.uint32.swap())
+  result.addStr("IHDR")
+  result.addUint32(width.uint32.swap())
+  result.addUint32(height.uint32.swap())
+  result.add(8.uint8)
+  result.add([colorType, 0, 0, 0])
+  result.addUint32(crc32(result[result.len - 17 ..< result.len]).swap())
+
+  # Add IDAT
+  # Add room for 1 byte before each row for the filter type.
+  var filtered = newSeq[uint8](width * height * channels + height)
+  for y in 0 ..< height:
+    filtered[y * width * channels + y] = 3 # Average
+    for x in 0 ..< width * channels:
+      # Move through the image data byte-by-byte
+      let
+        data = cast[ptr UncheckedArray[uint8]](data)
+        dataPos = y * width * channels + x
+        filteredPos = y * width * channels + y + 1 + x
+      var left, up: int
+      if x - channels >= 0:
+        left = data[dataPos - channels].int
+      if y - 1 >= 0:
+        up = data[(y - 1) * width * channels + x].int
+      let avg = ((left + up) div 2).uint8
+      filtered[filteredPos] = data[dataPos] - avg
+
+  let compressed =
+    try:
+      compress(filtered, DefaultCompression, dfZlib)
+    except ZippyError:
+      raise newException(
+        PixieError, "Unexpected error compressing PNG image data"
+      )
+  if compressed.len > int32.high.int:
+    raise newException(PixieError, "Compressed PNG image data too large")
+
+  result.addUint32(compressed.len.uint32.swap())
+  result.add(cast[seq[uint8]]("IDAT"))
+  result.add(compressed)
+  result.addUint32(
+    crc32(result[result.len - compressed.len - 4 ..< result.len]).swap()
+  )
+
+  # Add IEND
+  result.addUint32(0)
+  result.addStr("IEND")
+  result.addUint32(crc32(result[result.len - 4 ..< result.len]).swap())
+
+proc encodePng*(image: Image): string =
+  ## Encodes the image data into the PNG file format.
+  cast[string](encodePng(
+    image.width, image.height, 4, image.data[0].addr, image.data.len * 4
+  ))
+
+when defined(release):
+  {.pop.}
diff --git a/src/pixie/images.nim b/src/pixie/images.nim
index 91b8629..0adbc21 100644
--- a/src/pixie/images.nim
+++ b/src/pixie/images.nim
@@ -1,4 +1,4 @@
-import strformat, chroma, chroma/blends, vmath
+import chroma, chroma/blends, vmath
 
 type
   Image* = ref object
diff --git a/tests/benchmark_png.nim b/tests/benchmark_png.nim
new file mode 100644
index 0000000..1b9c586
--- /dev/null
+++ b/tests/benchmark_png.nim
@@ -0,0 +1,22 @@
+import pixie/fileformats/png, stb_image/read as stbi, fidget/opengl/perf, nimPNG
+
+let data = readFile("tests/data/lenna.png")
+
+timeIt "pixie":
+  for i in 0 ..< 100:
+    discard decodePng(cast[seq[uint8]](data))
+
+timeIt "nimPNG":
+  for i in 0 ..< 100:
+    discard decodePNG32(data)
+
+timeIt "stb_image":
+  for i in 0 ..< 100:
+    var width, height, channels: int
+    discard loadFromMemory(
+      cast[seq[byte]](data),
+      width,
+      height,
+      channels,
+      stbi.RGBA
+    )
diff --git a/tests/data/lenna.png b/tests/data/lenna.png
new file mode 100644
index 0000000..59ef68a
Binary files /dev/null and b/tests/data/lenna.png differ
diff --git a/tests/data/pngsuite/PngSuite.LICENSE b/tests/data/pngsuite/PngSuite.LICENSE
new file mode 100644
index 0000000..8d4d1d0
--- /dev/null
+++ b/tests/data/pngsuite/PngSuite.LICENSE
@@ -0,0 +1,9 @@
+PngSuite
+--------
+
+Permission to use, copy, modify and distribute these images for any
+purpose and without fee is hereby granted.
+
+
+(c) Willem van Schaik, 1996, 2011
+
diff --git a/tests/data/pngsuite/PngSuite.README b/tests/data/pngsuite/PngSuite.README
new file mode 100644
index 0000000..3ef8f24
--- /dev/null
+++ b/tests/data/pngsuite/PngSuite.README
@@ -0,0 +1,25 @@
+        PNGSUITE
+----------------
+
+        testset for PNG-(de)coders
+        created by Willem van Schaik
+------------------------------------
+
+This is a collection of graphics images created to test the png applications
+like viewers, converters and editors. All (as far as that is possible)
+formats supported by the PNG standard are represented.
+
+The suite consists of the following files:
+
+-	PngSuite.README		- this file
+-	PngSuite.LICENSE	- the PngSuite is freeware
+-	PngSuite.png		- image with PngSuite logo
+-	PngSuite.tgz		- archive of all PNG testfiles
+-	PngSuite.zip		- same in .zip format for PCs
+
+
+--------
+    (c) Willem van Schaik
+	willem@schaik.com
+        Calgary, April 2011
+
diff --git a/tests/data/pngsuite/PngSuite.png b/tests/data/pngsuite/PngSuite.png
new file mode 100644
index 0000000..205460d
Binary files /dev/null and b/tests/data/pngsuite/PngSuite.png differ
diff --git a/tests/data/pngsuite/basi0g01.png b/tests/data/pngsuite/basi0g01.png
new file mode 100644
index 0000000..556fa72
Binary files /dev/null and b/tests/data/pngsuite/basi0g01.png differ
diff --git a/tests/data/pngsuite/basi0g02.png b/tests/data/pngsuite/basi0g02.png
new file mode 100644
index 0000000..ce09821
Binary files /dev/null and b/tests/data/pngsuite/basi0g02.png differ
diff --git a/tests/data/pngsuite/basi0g04.png b/tests/data/pngsuite/basi0g04.png
new file mode 100644
index 0000000..3853273
Binary files /dev/null and b/tests/data/pngsuite/basi0g04.png differ
diff --git a/tests/data/pngsuite/basi0g08.png b/tests/data/pngsuite/basi0g08.png
new file mode 100644
index 0000000..faed8be
Binary files /dev/null and b/tests/data/pngsuite/basi0g08.png differ
diff --git a/tests/data/pngsuite/basi0g16.png b/tests/data/pngsuite/basi0g16.png
new file mode 100644
index 0000000..a9f2816
Binary files /dev/null and b/tests/data/pngsuite/basi0g16.png differ
diff --git a/tests/data/pngsuite/basi2c08.png b/tests/data/pngsuite/basi2c08.png
new file mode 100644
index 0000000..2aab44d
Binary files /dev/null and b/tests/data/pngsuite/basi2c08.png differ
diff --git a/tests/data/pngsuite/basi2c16.png b/tests/data/pngsuite/basi2c16.png
new file mode 100644
index 0000000..cd7e50f
Binary files /dev/null and b/tests/data/pngsuite/basi2c16.png differ
diff --git a/tests/data/pngsuite/basi3p01.png b/tests/data/pngsuite/basi3p01.png
new file mode 100644
index 0000000..00a7cea
Binary files /dev/null and b/tests/data/pngsuite/basi3p01.png differ
diff --git a/tests/data/pngsuite/basi3p02.png b/tests/data/pngsuite/basi3p02.png
new file mode 100644
index 0000000..bb16b44
Binary files /dev/null and b/tests/data/pngsuite/basi3p02.png differ
diff --git a/tests/data/pngsuite/basi3p04.png b/tests/data/pngsuite/basi3p04.png
new file mode 100644
index 0000000..b4e888e
Binary files /dev/null and b/tests/data/pngsuite/basi3p04.png differ
diff --git a/tests/data/pngsuite/basi3p08.png b/tests/data/pngsuite/basi3p08.png
new file mode 100644
index 0000000..50a6d1c
Binary files /dev/null and b/tests/data/pngsuite/basi3p08.png differ
diff --git a/tests/data/pngsuite/basi4a08.png b/tests/data/pngsuite/basi4a08.png
new file mode 100644
index 0000000..398132b
Binary files /dev/null and b/tests/data/pngsuite/basi4a08.png differ
diff --git a/tests/data/pngsuite/basi4a16.png b/tests/data/pngsuite/basi4a16.png
new file mode 100644
index 0000000..51192e7
Binary files /dev/null and b/tests/data/pngsuite/basi4a16.png differ
diff --git a/tests/data/pngsuite/basi6a08.png b/tests/data/pngsuite/basi6a08.png
new file mode 100644
index 0000000..aecb32e
Binary files /dev/null and b/tests/data/pngsuite/basi6a08.png differ
diff --git a/tests/data/pngsuite/basi6a16.png b/tests/data/pngsuite/basi6a16.png
new file mode 100644
index 0000000..4181533
Binary files /dev/null and b/tests/data/pngsuite/basi6a16.png differ
diff --git a/tests/data/pngsuite/basn0g01.png b/tests/data/pngsuite/basn0g01.png
new file mode 100644
index 0000000..1d72242
Binary files /dev/null and b/tests/data/pngsuite/basn0g01.png differ
diff --git a/tests/data/pngsuite/basn0g02.png b/tests/data/pngsuite/basn0g02.png
new file mode 100644
index 0000000..5083324
Binary files /dev/null and b/tests/data/pngsuite/basn0g02.png differ
diff --git a/tests/data/pngsuite/basn0g04.png b/tests/data/pngsuite/basn0g04.png
new file mode 100644
index 0000000..0bf3687
Binary files /dev/null and b/tests/data/pngsuite/basn0g04.png differ
diff --git a/tests/data/pngsuite/basn0g08.png b/tests/data/pngsuite/basn0g08.png
new file mode 100644
index 0000000..23c8237
Binary files /dev/null and b/tests/data/pngsuite/basn0g08.png differ
diff --git a/tests/data/pngsuite/basn0g16.png b/tests/data/pngsuite/basn0g16.png
new file mode 100644
index 0000000..e7c82f7
Binary files /dev/null and b/tests/data/pngsuite/basn0g16.png differ
diff --git a/tests/data/pngsuite/basn2c08.png b/tests/data/pngsuite/basn2c08.png
new file mode 100644
index 0000000..db5ad15
Binary files /dev/null and b/tests/data/pngsuite/basn2c08.png differ
diff --git a/tests/data/pngsuite/basn2c16.png b/tests/data/pngsuite/basn2c16.png
new file mode 100644
index 0000000..50c1cb9
Binary files /dev/null and b/tests/data/pngsuite/basn2c16.png differ
diff --git a/tests/data/pngsuite/basn3p01.png b/tests/data/pngsuite/basn3p01.png
new file mode 100644
index 0000000..b145c2b
Binary files /dev/null and b/tests/data/pngsuite/basn3p01.png differ
diff --git a/tests/data/pngsuite/basn3p02.png b/tests/data/pngsuite/basn3p02.png
new file mode 100644
index 0000000..8985b3d
Binary files /dev/null and b/tests/data/pngsuite/basn3p02.png differ
diff --git a/tests/data/pngsuite/basn3p04.png b/tests/data/pngsuite/basn3p04.png
new file mode 100644
index 0000000..0fbf9e8
Binary files /dev/null and b/tests/data/pngsuite/basn3p04.png differ
diff --git a/tests/data/pngsuite/basn3p08.png b/tests/data/pngsuite/basn3p08.png
new file mode 100644
index 0000000..0ddad07
Binary files /dev/null and b/tests/data/pngsuite/basn3p08.png differ
diff --git a/tests/data/pngsuite/basn4a08.png b/tests/data/pngsuite/basn4a08.png
new file mode 100644
index 0000000..3e13052
Binary files /dev/null and b/tests/data/pngsuite/basn4a08.png differ
diff --git a/tests/data/pngsuite/basn4a16.png b/tests/data/pngsuite/basn4a16.png
new file mode 100644
index 0000000..8243644
Binary files /dev/null and b/tests/data/pngsuite/basn4a16.png differ
diff --git a/tests/data/pngsuite/basn6a08.png b/tests/data/pngsuite/basn6a08.png
new file mode 100644
index 0000000..e608738
Binary files /dev/null and b/tests/data/pngsuite/basn6a08.png differ
diff --git a/tests/data/pngsuite/basn6a16.png b/tests/data/pngsuite/basn6a16.png
new file mode 100644
index 0000000..984a995
Binary files /dev/null and b/tests/data/pngsuite/basn6a16.png differ
diff --git a/tests/data/pngsuite/bgai4a08.png b/tests/data/pngsuite/bgai4a08.png
new file mode 100644
index 0000000..398132b
Binary files /dev/null and b/tests/data/pngsuite/bgai4a08.png differ
diff --git a/tests/data/pngsuite/bgai4a16.png b/tests/data/pngsuite/bgai4a16.png
new file mode 100644
index 0000000..51192e7
Binary files /dev/null and b/tests/data/pngsuite/bgai4a16.png differ
diff --git a/tests/data/pngsuite/bgan6a08.png b/tests/data/pngsuite/bgan6a08.png
new file mode 100644
index 0000000..e608738
Binary files /dev/null and b/tests/data/pngsuite/bgan6a08.png differ
diff --git a/tests/data/pngsuite/bgan6a16.png b/tests/data/pngsuite/bgan6a16.png
new file mode 100644
index 0000000..984a995
Binary files /dev/null and b/tests/data/pngsuite/bgan6a16.png differ
diff --git a/tests/data/pngsuite/bgbn4a08.png b/tests/data/pngsuite/bgbn4a08.png
new file mode 100644
index 0000000..7cbefc3
Binary files /dev/null and b/tests/data/pngsuite/bgbn4a08.png differ
diff --git a/tests/data/pngsuite/bggn4a16.png b/tests/data/pngsuite/bggn4a16.png
new file mode 100644
index 0000000..13fd85b
Binary files /dev/null and b/tests/data/pngsuite/bggn4a16.png differ
diff --git a/tests/data/pngsuite/bgwn6a08.png b/tests/data/pngsuite/bgwn6a08.png
new file mode 100644
index 0000000..a67ff20
Binary files /dev/null and b/tests/data/pngsuite/bgwn6a08.png differ
diff --git a/tests/data/pngsuite/bgyn6a16.png b/tests/data/pngsuite/bgyn6a16.png
new file mode 100644
index 0000000..ae3e9be
Binary files /dev/null and b/tests/data/pngsuite/bgyn6a16.png differ
diff --git a/tests/data/pngsuite/ccwn2c08.png b/tests/data/pngsuite/ccwn2c08.png
new file mode 100644
index 0000000..47c2481
Binary files /dev/null and b/tests/data/pngsuite/ccwn2c08.png differ
diff --git a/tests/data/pngsuite/ccwn3p08.png b/tests/data/pngsuite/ccwn3p08.png
new file mode 100644
index 0000000..8bb2c10
Binary files /dev/null and b/tests/data/pngsuite/ccwn3p08.png differ
diff --git a/tests/data/pngsuite/cdfn2c08.png b/tests/data/pngsuite/cdfn2c08.png
new file mode 100644
index 0000000..559e526
Binary files /dev/null and b/tests/data/pngsuite/cdfn2c08.png differ
diff --git a/tests/data/pngsuite/cdhn2c08.png b/tests/data/pngsuite/cdhn2c08.png
new file mode 100644
index 0000000..3e07e8e
Binary files /dev/null and b/tests/data/pngsuite/cdhn2c08.png differ
diff --git a/tests/data/pngsuite/cdsn2c08.png b/tests/data/pngsuite/cdsn2c08.png
new file mode 100644
index 0000000..076c32c
Binary files /dev/null and b/tests/data/pngsuite/cdsn2c08.png differ
diff --git a/tests/data/pngsuite/cdun2c08.png b/tests/data/pngsuite/cdun2c08.png
new file mode 100644
index 0000000..846033b
Binary files /dev/null and b/tests/data/pngsuite/cdun2c08.png differ
diff --git a/tests/data/pngsuite/ch1n3p04.png b/tests/data/pngsuite/ch1n3p04.png
new file mode 100644
index 0000000..17cd12d
Binary files /dev/null and b/tests/data/pngsuite/ch1n3p04.png differ
diff --git a/tests/data/pngsuite/ch2n3p08.png b/tests/data/pngsuite/ch2n3p08.png
new file mode 100644
index 0000000..25c1798
Binary files /dev/null and b/tests/data/pngsuite/ch2n3p08.png differ
diff --git a/tests/data/pngsuite/cm0n0g04.png b/tests/data/pngsuite/cm0n0g04.png
new file mode 100644
index 0000000..9fba5db
Binary files /dev/null and b/tests/data/pngsuite/cm0n0g04.png differ
diff --git a/tests/data/pngsuite/cm7n0g04.png b/tests/data/pngsuite/cm7n0g04.png
new file mode 100644
index 0000000..f7dc46e
Binary files /dev/null and b/tests/data/pngsuite/cm7n0g04.png differ
diff --git a/tests/data/pngsuite/cm9n0g04.png b/tests/data/pngsuite/cm9n0g04.png
new file mode 100644
index 0000000..dd70911
Binary files /dev/null and b/tests/data/pngsuite/cm9n0g04.png differ
diff --git a/tests/data/pngsuite/cs3n2c16.png b/tests/data/pngsuite/cs3n2c16.png
new file mode 100644
index 0000000..bf5fd20
Binary files /dev/null and b/tests/data/pngsuite/cs3n2c16.png differ
diff --git a/tests/data/pngsuite/cs3n3p08.png b/tests/data/pngsuite/cs3n3p08.png
new file mode 100644
index 0000000..f4a6623
Binary files /dev/null and b/tests/data/pngsuite/cs3n3p08.png differ
diff --git a/tests/data/pngsuite/cs5n2c08.png b/tests/data/pngsuite/cs5n2c08.png
new file mode 100644
index 0000000..40f947c
Binary files /dev/null and b/tests/data/pngsuite/cs5n2c08.png differ
diff --git a/tests/data/pngsuite/cs5n3p08.png b/tests/data/pngsuite/cs5n3p08.png
new file mode 100644
index 0000000..dfd6e6e
Binary files /dev/null and b/tests/data/pngsuite/cs5n3p08.png differ
diff --git a/tests/data/pngsuite/cs8n2c08.png b/tests/data/pngsuite/cs8n2c08.png
new file mode 100644
index 0000000..8e01d32
Binary files /dev/null and b/tests/data/pngsuite/cs8n2c08.png differ
diff --git a/tests/data/pngsuite/cs8n3p08.png b/tests/data/pngsuite/cs8n3p08.png
new file mode 100644
index 0000000..a44066e
Binary files /dev/null and b/tests/data/pngsuite/cs8n3p08.png differ
diff --git a/tests/data/pngsuite/ct0n0g04.png b/tests/data/pngsuite/ct0n0g04.png
new file mode 100644
index 0000000..40d1e06
Binary files /dev/null and b/tests/data/pngsuite/ct0n0g04.png differ
diff --git a/tests/data/pngsuite/ct1n0g04.png b/tests/data/pngsuite/ct1n0g04.png
new file mode 100644
index 0000000..3ba110a
Binary files /dev/null and b/tests/data/pngsuite/ct1n0g04.png differ
diff --git a/tests/data/pngsuite/cten0g04.png b/tests/data/pngsuite/cten0g04.png
new file mode 100644
index 0000000..a6a56fa
Binary files /dev/null and b/tests/data/pngsuite/cten0g04.png differ
diff --git a/tests/data/pngsuite/ctfn0g04.png b/tests/data/pngsuite/ctfn0g04.png
new file mode 100644
index 0000000..353873e
Binary files /dev/null and b/tests/data/pngsuite/ctfn0g04.png differ
diff --git a/tests/data/pngsuite/ctgn0g04.png b/tests/data/pngsuite/ctgn0g04.png
new file mode 100644
index 0000000..453f2b0
Binary files /dev/null and b/tests/data/pngsuite/ctgn0g04.png differ
diff --git a/tests/data/pngsuite/cthn0g04.png b/tests/data/pngsuite/cthn0g04.png
new file mode 100644
index 0000000..8fce253
Binary files /dev/null and b/tests/data/pngsuite/cthn0g04.png differ
diff --git a/tests/data/pngsuite/ctjn0g04.png b/tests/data/pngsuite/ctjn0g04.png
new file mode 100644
index 0000000..a77b8d2
Binary files /dev/null and b/tests/data/pngsuite/ctjn0g04.png differ
diff --git a/tests/data/pngsuite/ctzn0g04.png b/tests/data/pngsuite/ctzn0g04.png
new file mode 100644
index 0000000..b4401c9
Binary files /dev/null and b/tests/data/pngsuite/ctzn0g04.png differ
diff --git a/tests/data/pngsuite/exif2c08.png b/tests/data/pngsuite/exif2c08.png
new file mode 100644
index 0000000..56eb734
Binary files /dev/null and b/tests/data/pngsuite/exif2c08.png differ
diff --git a/tests/data/pngsuite/f00n0g08.png b/tests/data/pngsuite/f00n0g08.png
new file mode 100644
index 0000000..45a0075
Binary files /dev/null and b/tests/data/pngsuite/f00n0g08.png differ
diff --git a/tests/data/pngsuite/f00n2c08.png b/tests/data/pngsuite/f00n2c08.png
new file mode 100644
index 0000000..d6a1fff
Binary files /dev/null and b/tests/data/pngsuite/f00n2c08.png differ
diff --git a/tests/data/pngsuite/f01n0g08.png b/tests/data/pngsuite/f01n0g08.png
new file mode 100644
index 0000000..4a1107b
Binary files /dev/null and b/tests/data/pngsuite/f01n0g08.png differ
diff --git a/tests/data/pngsuite/f01n2c08.png b/tests/data/pngsuite/f01n2c08.png
new file mode 100644
index 0000000..26fee95
Binary files /dev/null and b/tests/data/pngsuite/f01n2c08.png differ
diff --git a/tests/data/pngsuite/f02n0g08.png b/tests/data/pngsuite/f02n0g08.png
new file mode 100644
index 0000000..bfe410c
Binary files /dev/null and b/tests/data/pngsuite/f02n0g08.png differ
diff --git a/tests/data/pngsuite/f02n2c08.png b/tests/data/pngsuite/f02n2c08.png
new file mode 100644
index 0000000..e590f12
Binary files /dev/null and b/tests/data/pngsuite/f02n2c08.png differ
diff --git a/tests/data/pngsuite/f03n0g08.png b/tests/data/pngsuite/f03n0g08.png
new file mode 100644
index 0000000..ed01e29
Binary files /dev/null and b/tests/data/pngsuite/f03n0g08.png differ
diff --git a/tests/data/pngsuite/f03n2c08.png b/tests/data/pngsuite/f03n2c08.png
new file mode 100644
index 0000000..7581150
Binary files /dev/null and b/tests/data/pngsuite/f03n2c08.png differ
diff --git a/tests/data/pngsuite/f04n0g08.png b/tests/data/pngsuite/f04n0g08.png
new file mode 100644
index 0000000..663fdae
Binary files /dev/null and b/tests/data/pngsuite/f04n0g08.png differ
diff --git a/tests/data/pngsuite/f04n2c08.png b/tests/data/pngsuite/f04n2c08.png
new file mode 100644
index 0000000..3c8b511
Binary files /dev/null and b/tests/data/pngsuite/f04n2c08.png differ
diff --git a/tests/data/pngsuite/f99n0g04.png b/tests/data/pngsuite/f99n0g04.png
new file mode 100644
index 0000000..0b521c1
Binary files /dev/null and b/tests/data/pngsuite/f99n0g04.png differ
diff --git a/tests/data/pngsuite/g03n0g16.png b/tests/data/pngsuite/g03n0g16.png
new file mode 100644
index 0000000..41083ca
Binary files /dev/null and b/tests/data/pngsuite/g03n0g16.png differ
diff --git a/tests/data/pngsuite/g03n2c08.png b/tests/data/pngsuite/g03n2c08.png
new file mode 100644
index 0000000..a9354db
Binary files /dev/null and b/tests/data/pngsuite/g03n2c08.png differ
diff --git a/tests/data/pngsuite/g03n3p04.png b/tests/data/pngsuite/g03n3p04.png
new file mode 100644
index 0000000..60396c9
Binary files /dev/null and b/tests/data/pngsuite/g03n3p04.png differ
diff --git a/tests/data/pngsuite/g04n0g16.png b/tests/data/pngsuite/g04n0g16.png
new file mode 100644
index 0000000..32395b7
Binary files /dev/null and b/tests/data/pngsuite/g04n0g16.png differ
diff --git a/tests/data/pngsuite/g04n2c08.png b/tests/data/pngsuite/g04n2c08.png
new file mode 100644
index 0000000..a652b0c
Binary files /dev/null and b/tests/data/pngsuite/g04n2c08.png differ
diff --git a/tests/data/pngsuite/g04n3p04.png b/tests/data/pngsuite/g04n3p04.png
new file mode 100644
index 0000000..5661cc3
Binary files /dev/null and b/tests/data/pngsuite/g04n3p04.png differ
diff --git a/tests/data/pngsuite/g05n0g16.png b/tests/data/pngsuite/g05n0g16.png
new file mode 100644
index 0000000..70b37f0
Binary files /dev/null and b/tests/data/pngsuite/g05n0g16.png differ
diff --git a/tests/data/pngsuite/g05n2c08.png b/tests/data/pngsuite/g05n2c08.png
new file mode 100644
index 0000000..932c136
Binary files /dev/null and b/tests/data/pngsuite/g05n2c08.png differ
diff --git a/tests/data/pngsuite/g05n3p04.png b/tests/data/pngsuite/g05n3p04.png
new file mode 100644
index 0000000..9619930
Binary files /dev/null and b/tests/data/pngsuite/g05n3p04.png differ
diff --git a/tests/data/pngsuite/g07n0g16.png b/tests/data/pngsuite/g07n0g16.png
new file mode 100644
index 0000000..d6a47c2
Binary files /dev/null and b/tests/data/pngsuite/g07n0g16.png differ
diff --git a/tests/data/pngsuite/g07n2c08.png b/tests/data/pngsuite/g07n2c08.png
new file mode 100644
index 0000000..5973464
Binary files /dev/null and b/tests/data/pngsuite/g07n2c08.png differ
diff --git a/tests/data/pngsuite/g07n3p04.png b/tests/data/pngsuite/g07n3p04.png
new file mode 100644
index 0000000..c73fb61
Binary files /dev/null and b/tests/data/pngsuite/g07n3p04.png differ
diff --git a/tests/data/pngsuite/g10n0g16.png b/tests/data/pngsuite/g10n0g16.png
new file mode 100644
index 0000000..85f2c95
Binary files /dev/null and b/tests/data/pngsuite/g10n0g16.png differ
diff --git a/tests/data/pngsuite/g10n2c08.png b/tests/data/pngsuite/g10n2c08.png
new file mode 100644
index 0000000..b303997
Binary files /dev/null and b/tests/data/pngsuite/g10n2c08.png differ
diff --git a/tests/data/pngsuite/g10n3p04.png b/tests/data/pngsuite/g10n3p04.png
new file mode 100644
index 0000000..1b6a6be
Binary files /dev/null and b/tests/data/pngsuite/g10n3p04.png differ
diff --git a/tests/data/pngsuite/g25n0g16.png b/tests/data/pngsuite/g25n0g16.png
new file mode 100644
index 0000000..a9f6787
Binary files /dev/null and b/tests/data/pngsuite/g25n0g16.png differ
diff --git a/tests/data/pngsuite/g25n2c08.png b/tests/data/pngsuite/g25n2c08.png
new file mode 100644
index 0000000..03f505a
Binary files /dev/null and b/tests/data/pngsuite/g25n2c08.png differ
diff --git a/tests/data/pngsuite/g25n3p04.png b/tests/data/pngsuite/g25n3p04.png
new file mode 100644
index 0000000..4f943c6
Binary files /dev/null and b/tests/data/pngsuite/g25n3p04.png differ
diff --git a/tests/data/pngsuite/oi1n0g16.png b/tests/data/pngsuite/oi1n0g16.png
new file mode 100644
index 0000000..e7c82f7
Binary files /dev/null and b/tests/data/pngsuite/oi1n0g16.png differ
diff --git a/tests/data/pngsuite/oi1n2c16.png b/tests/data/pngsuite/oi1n2c16.png
new file mode 100644
index 0000000..50c1cb9
Binary files /dev/null and b/tests/data/pngsuite/oi1n2c16.png differ
diff --git a/tests/data/pngsuite/oi2n0g16.png b/tests/data/pngsuite/oi2n0g16.png
new file mode 100644
index 0000000..14d64c5
Binary files /dev/null and b/tests/data/pngsuite/oi2n0g16.png differ
diff --git a/tests/data/pngsuite/oi2n2c16.png b/tests/data/pngsuite/oi2n2c16.png
new file mode 100644
index 0000000..4c2e3e3
Binary files /dev/null and b/tests/data/pngsuite/oi2n2c16.png differ
diff --git a/tests/data/pngsuite/oi4n0g16.png b/tests/data/pngsuite/oi4n0g16.png
new file mode 100644
index 0000000..69e73ed
Binary files /dev/null and b/tests/data/pngsuite/oi4n0g16.png differ
diff --git a/tests/data/pngsuite/oi4n2c16.png b/tests/data/pngsuite/oi4n2c16.png
new file mode 100644
index 0000000..93691e3
Binary files /dev/null and b/tests/data/pngsuite/oi4n2c16.png differ
diff --git a/tests/data/pngsuite/oi9n0g16.png b/tests/data/pngsuite/oi9n0g16.png
new file mode 100644
index 0000000..9248413
Binary files /dev/null and b/tests/data/pngsuite/oi9n0g16.png differ
diff --git a/tests/data/pngsuite/oi9n2c16.png b/tests/data/pngsuite/oi9n2c16.png
new file mode 100644
index 0000000..f0512e4
Binary files /dev/null and b/tests/data/pngsuite/oi9n2c16.png differ
diff --git a/tests/data/pngsuite/pp0n2c16.png b/tests/data/pngsuite/pp0n2c16.png
new file mode 100644
index 0000000..8f2aad7
Binary files /dev/null and b/tests/data/pngsuite/pp0n2c16.png differ
diff --git a/tests/data/pngsuite/pp0n6a08.png b/tests/data/pngsuite/pp0n6a08.png
new file mode 100644
index 0000000..4ed7a30
Binary files /dev/null and b/tests/data/pngsuite/pp0n6a08.png differ
diff --git a/tests/data/pngsuite/ps1n0g08.png b/tests/data/pngsuite/ps1n0g08.png
new file mode 100644
index 0000000..99625fa
Binary files /dev/null and b/tests/data/pngsuite/ps1n0g08.png differ
diff --git a/tests/data/pngsuite/ps1n2c16.png b/tests/data/pngsuite/ps1n2c16.png
new file mode 100644
index 0000000..0c7a6b3
Binary files /dev/null and b/tests/data/pngsuite/ps1n2c16.png differ
diff --git a/tests/data/pngsuite/ps2n0g08.png b/tests/data/pngsuite/ps2n0g08.png
new file mode 100644
index 0000000..90b2979
Binary files /dev/null and b/tests/data/pngsuite/ps2n0g08.png differ
diff --git a/tests/data/pngsuite/ps2n2c16.png b/tests/data/pngsuite/ps2n2c16.png
new file mode 100644
index 0000000..a4a181e
Binary files /dev/null and b/tests/data/pngsuite/ps2n2c16.png differ
diff --git a/tests/data/pngsuite/s01i3p01.png b/tests/data/pngsuite/s01i3p01.png
new file mode 100644
index 0000000..6c0fad1
Binary files /dev/null and b/tests/data/pngsuite/s01i3p01.png differ
diff --git a/tests/data/pngsuite/s01n3p01.png b/tests/data/pngsuite/s01n3p01.png
new file mode 100644
index 0000000..cb2c8c7
Binary files /dev/null and b/tests/data/pngsuite/s01n3p01.png differ
diff --git a/tests/data/pngsuite/s02i3p01.png b/tests/data/pngsuite/s02i3p01.png
new file mode 100644
index 0000000..2defaed
Binary files /dev/null and b/tests/data/pngsuite/s02i3p01.png differ
diff --git a/tests/data/pngsuite/s02n3p01.png b/tests/data/pngsuite/s02n3p01.png
new file mode 100644
index 0000000..2b1b669
Binary files /dev/null and b/tests/data/pngsuite/s02n3p01.png differ
diff --git a/tests/data/pngsuite/s03i3p01.png b/tests/data/pngsuite/s03i3p01.png
new file mode 100644
index 0000000..c23fdc4
Binary files /dev/null and b/tests/data/pngsuite/s03i3p01.png differ
diff --git a/tests/data/pngsuite/s03n3p01.png b/tests/data/pngsuite/s03n3p01.png
new file mode 100644
index 0000000..6d96ee4
Binary files /dev/null and b/tests/data/pngsuite/s03n3p01.png differ
diff --git a/tests/data/pngsuite/s04i3p01.png b/tests/data/pngsuite/s04i3p01.png
new file mode 100644
index 0000000..0e710c2
Binary files /dev/null and b/tests/data/pngsuite/s04i3p01.png differ
diff --git a/tests/data/pngsuite/s04n3p01.png b/tests/data/pngsuite/s04n3p01.png
new file mode 100644
index 0000000..956396c
Binary files /dev/null and b/tests/data/pngsuite/s04n3p01.png differ
diff --git a/tests/data/pngsuite/s05i3p02.png b/tests/data/pngsuite/s05i3p02.png
new file mode 100644
index 0000000..d14cbd3
Binary files /dev/null and b/tests/data/pngsuite/s05i3p02.png differ
diff --git a/tests/data/pngsuite/s05n3p02.png b/tests/data/pngsuite/s05n3p02.png
new file mode 100644
index 0000000..bf940f0
Binary files /dev/null and b/tests/data/pngsuite/s05n3p02.png differ
diff --git a/tests/data/pngsuite/s06i3p02.png b/tests/data/pngsuite/s06i3p02.png
new file mode 100644
index 0000000..456ada3
Binary files /dev/null and b/tests/data/pngsuite/s06i3p02.png differ
diff --git a/tests/data/pngsuite/s06n3p02.png b/tests/data/pngsuite/s06n3p02.png
new file mode 100644
index 0000000..501064d
Binary files /dev/null and b/tests/data/pngsuite/s06n3p02.png differ
diff --git a/tests/data/pngsuite/s07i3p02.png b/tests/data/pngsuite/s07i3p02.png
new file mode 100644
index 0000000..44b66ba
Binary files /dev/null and b/tests/data/pngsuite/s07i3p02.png differ
diff --git a/tests/data/pngsuite/s07n3p02.png b/tests/data/pngsuite/s07n3p02.png
new file mode 100644
index 0000000..6a58259
Binary files /dev/null and b/tests/data/pngsuite/s07n3p02.png differ
diff --git a/tests/data/pngsuite/s08i3p02.png b/tests/data/pngsuite/s08i3p02.png
new file mode 100644
index 0000000..acf74f3
Binary files /dev/null and b/tests/data/pngsuite/s08i3p02.png differ
diff --git a/tests/data/pngsuite/s08n3p02.png b/tests/data/pngsuite/s08n3p02.png
new file mode 100644
index 0000000..b7094e1
Binary files /dev/null and b/tests/data/pngsuite/s08n3p02.png differ
diff --git a/tests/data/pngsuite/s09i3p02.png b/tests/data/pngsuite/s09i3p02.png
new file mode 100644
index 0000000..0bfae8e
Binary files /dev/null and b/tests/data/pngsuite/s09i3p02.png differ
diff --git a/tests/data/pngsuite/s09n3p02.png b/tests/data/pngsuite/s09n3p02.png
new file mode 100644
index 0000000..711ab82
Binary files /dev/null and b/tests/data/pngsuite/s09n3p02.png differ
diff --git a/tests/data/pngsuite/s32i3p04.png b/tests/data/pngsuite/s32i3p04.png
new file mode 100644
index 0000000..0841910
Binary files /dev/null and b/tests/data/pngsuite/s32i3p04.png differ
diff --git a/tests/data/pngsuite/s32n3p04.png b/tests/data/pngsuite/s32n3p04.png
new file mode 100644
index 0000000..fa58e3e
Binary files /dev/null and b/tests/data/pngsuite/s32n3p04.png differ
diff --git a/tests/data/pngsuite/s33i3p04.png b/tests/data/pngsuite/s33i3p04.png
new file mode 100644
index 0000000..ab0dc14
Binary files /dev/null and b/tests/data/pngsuite/s33i3p04.png differ
diff --git a/tests/data/pngsuite/s33n3p04.png b/tests/data/pngsuite/s33n3p04.png
new file mode 100644
index 0000000..764f1a3
Binary files /dev/null and b/tests/data/pngsuite/s33n3p04.png differ
diff --git a/tests/data/pngsuite/s34i3p04.png b/tests/data/pngsuite/s34i3p04.png
new file mode 100644
index 0000000..bd99039
Binary files /dev/null and b/tests/data/pngsuite/s34i3p04.png differ
diff --git a/tests/data/pngsuite/s34n3p04.png b/tests/data/pngsuite/s34n3p04.png
new file mode 100644
index 0000000..9cbc68b
Binary files /dev/null and b/tests/data/pngsuite/s34n3p04.png differ
diff --git a/tests/data/pngsuite/s35i3p04.png b/tests/data/pngsuite/s35i3p04.png
new file mode 100644
index 0000000..e2a5e0a
Binary files /dev/null and b/tests/data/pngsuite/s35i3p04.png differ
diff --git a/tests/data/pngsuite/s35n3p04.png b/tests/data/pngsuite/s35n3p04.png
new file mode 100644
index 0000000..90b892e
Binary files /dev/null and b/tests/data/pngsuite/s35n3p04.png differ
diff --git a/tests/data/pngsuite/s36i3p04.png b/tests/data/pngsuite/s36i3p04.png
new file mode 100644
index 0000000..eb61b6f
Binary files /dev/null and b/tests/data/pngsuite/s36i3p04.png differ
diff --git a/tests/data/pngsuite/s36n3p04.png b/tests/data/pngsuite/s36n3p04.png
new file mode 100644
index 0000000..b38d179
Binary files /dev/null and b/tests/data/pngsuite/s36n3p04.png differ
diff --git a/tests/data/pngsuite/s37i3p04.png b/tests/data/pngsuite/s37i3p04.png
new file mode 100644
index 0000000..6e2b1e9
Binary files /dev/null and b/tests/data/pngsuite/s37i3p04.png differ
diff --git a/tests/data/pngsuite/s37n3p04.png b/tests/data/pngsuite/s37n3p04.png
new file mode 100644
index 0000000..4d3054d
Binary files /dev/null and b/tests/data/pngsuite/s37n3p04.png differ
diff --git a/tests/data/pngsuite/s38i3p04.png b/tests/data/pngsuite/s38i3p04.png
new file mode 100644
index 0000000..a0a8a14
Binary files /dev/null and b/tests/data/pngsuite/s38i3p04.png differ
diff --git a/tests/data/pngsuite/s38n3p04.png b/tests/data/pngsuite/s38n3p04.png
new file mode 100644
index 0000000..1233ed0
Binary files /dev/null and b/tests/data/pngsuite/s38n3p04.png differ
diff --git a/tests/data/pngsuite/s39i3p04.png b/tests/data/pngsuite/s39i3p04.png
new file mode 100644
index 0000000..04fee93
Binary files /dev/null and b/tests/data/pngsuite/s39i3p04.png differ
diff --git a/tests/data/pngsuite/s39n3p04.png b/tests/data/pngsuite/s39n3p04.png
new file mode 100644
index 0000000..c750100
Binary files /dev/null and b/tests/data/pngsuite/s39n3p04.png differ
diff --git a/tests/data/pngsuite/s40i3p04.png b/tests/data/pngsuite/s40i3p04.png
new file mode 100644
index 0000000..68f358b
Binary files /dev/null and b/tests/data/pngsuite/s40i3p04.png differ
diff --git a/tests/data/pngsuite/s40n3p04.png b/tests/data/pngsuite/s40n3p04.png
new file mode 100644
index 0000000..864b6b9
Binary files /dev/null and b/tests/data/pngsuite/s40n3p04.png differ
diff --git a/tests/data/pngsuite/tbbn0g04.png b/tests/data/pngsuite/tbbn0g04.png
new file mode 100644
index 0000000..39a7050
Binary files /dev/null and b/tests/data/pngsuite/tbbn0g04.png differ
diff --git a/tests/data/pngsuite/tbbn2c16.png b/tests/data/pngsuite/tbbn2c16.png
new file mode 100644
index 0000000..dd3168e
Binary files /dev/null and b/tests/data/pngsuite/tbbn2c16.png differ
diff --git a/tests/data/pngsuite/tbbn3p08.png b/tests/data/pngsuite/tbbn3p08.png
new file mode 100644
index 0000000..0ede357
Binary files /dev/null and b/tests/data/pngsuite/tbbn3p08.png differ
diff --git a/tests/data/pngsuite/tbgn2c16.png b/tests/data/pngsuite/tbgn2c16.png
new file mode 100644
index 0000000..85cec39
Binary files /dev/null and b/tests/data/pngsuite/tbgn2c16.png differ
diff --git a/tests/data/pngsuite/tbgn3p08.png b/tests/data/pngsuite/tbgn3p08.png
new file mode 100644
index 0000000..8cf2e6f
Binary files /dev/null and b/tests/data/pngsuite/tbgn3p08.png differ
diff --git a/tests/data/pngsuite/tbrn2c08.png b/tests/data/pngsuite/tbrn2c08.png
new file mode 100644
index 0000000..5cca0d6
Binary files /dev/null and b/tests/data/pngsuite/tbrn2c08.png differ
diff --git a/tests/data/pngsuite/tbwn0g16.png b/tests/data/pngsuite/tbwn0g16.png
new file mode 100644
index 0000000..99bdeed
Binary files /dev/null and b/tests/data/pngsuite/tbwn0g16.png differ
diff --git a/tests/data/pngsuite/tbwn3p08.png b/tests/data/pngsuite/tbwn3p08.png
new file mode 100644
index 0000000..eacab7a
Binary files /dev/null and b/tests/data/pngsuite/tbwn3p08.png differ
diff --git a/tests/data/pngsuite/tbyn3p08.png b/tests/data/pngsuite/tbyn3p08.png
new file mode 100644
index 0000000..656db09
Binary files /dev/null and b/tests/data/pngsuite/tbyn3p08.png differ
diff --git a/tests/data/pngsuite/tm3n3p02.png b/tests/data/pngsuite/tm3n3p02.png
new file mode 100644
index 0000000..fb3ef1d
Binary files /dev/null and b/tests/data/pngsuite/tm3n3p02.png differ
diff --git a/tests/data/pngsuite/tp0n0g08.png b/tests/data/pngsuite/tp0n0g08.png
new file mode 100644
index 0000000..333465f
Binary files /dev/null and b/tests/data/pngsuite/tp0n0g08.png differ
diff --git a/tests/data/pngsuite/tp0n2c08.png b/tests/data/pngsuite/tp0n2c08.png
new file mode 100644
index 0000000..fc6e42c
Binary files /dev/null and b/tests/data/pngsuite/tp0n2c08.png differ
diff --git a/tests/data/pngsuite/tp0n3p08.png b/tests/data/pngsuite/tp0n3p08.png
new file mode 100644
index 0000000..69a69e5
Binary files /dev/null and b/tests/data/pngsuite/tp0n3p08.png differ
diff --git a/tests/data/pngsuite/tp1n3p08.png b/tests/data/pngsuite/tp1n3p08.png
new file mode 100644
index 0000000..a6c9f35
Binary files /dev/null and b/tests/data/pngsuite/tp1n3p08.png differ
diff --git a/tests/data/pngsuite/xc1n0g08.png b/tests/data/pngsuite/xc1n0g08.png
new file mode 100644
index 0000000..9404227
Binary files /dev/null and b/tests/data/pngsuite/xc1n0g08.png differ
diff --git a/tests/data/pngsuite/xc9n2c08.png b/tests/data/pngsuite/xc9n2c08.png
new file mode 100644
index 0000000..b11c2a7
Binary files /dev/null and b/tests/data/pngsuite/xc9n2c08.png differ
diff --git a/tests/data/pngsuite/xcrn0g04.png b/tests/data/pngsuite/xcrn0g04.png
new file mode 100644
index 0000000..48abba1
Binary files /dev/null and b/tests/data/pngsuite/xcrn0g04.png differ
diff --git a/tests/data/pngsuite/xcsn0g01.png b/tests/data/pngsuite/xcsn0g01.png
new file mode 100644
index 0000000..9863a26
Binary files /dev/null and b/tests/data/pngsuite/xcsn0g01.png differ
diff --git a/tests/data/pngsuite/xd0n2c08.png b/tests/data/pngsuite/xd0n2c08.png
new file mode 100644
index 0000000..2f00161
Binary files /dev/null and b/tests/data/pngsuite/xd0n2c08.png differ
diff --git a/tests/data/pngsuite/xd3n2c08.png b/tests/data/pngsuite/xd3n2c08.png
new file mode 100644
index 0000000..9e4a3ff
Binary files /dev/null and b/tests/data/pngsuite/xd3n2c08.png differ
diff --git a/tests/data/pngsuite/xd9n2c08.png b/tests/data/pngsuite/xd9n2c08.png
new file mode 100644
index 0000000..2c3b91a
Binary files /dev/null and b/tests/data/pngsuite/xd9n2c08.png differ
diff --git a/tests/data/pngsuite/xdtn0g01.png b/tests/data/pngsuite/xdtn0g01.png
new file mode 100644
index 0000000..1a81abe
Binary files /dev/null and b/tests/data/pngsuite/xdtn0g01.png differ
diff --git a/tests/data/pngsuite/xhdn0g08.png b/tests/data/pngsuite/xhdn0g08.png
new file mode 100644
index 0000000..fcb8737
Binary files /dev/null and b/tests/data/pngsuite/xhdn0g08.png differ
diff --git a/tests/data/pngsuite/xlfn0g04.png b/tests/data/pngsuite/xlfn0g04.png
new file mode 100644
index 0000000..d9ec53e
Binary files /dev/null and b/tests/data/pngsuite/xlfn0g04.png differ
diff --git a/tests/data/pngsuite/xs1n0g01.png b/tests/data/pngsuite/xs1n0g01.png
new file mode 100644
index 0000000..1817c51
Binary files /dev/null and b/tests/data/pngsuite/xs1n0g01.png differ
diff --git a/tests/data/pngsuite/xs2n0g01.png b/tests/data/pngsuite/xs2n0g01.png
new file mode 100644
index 0000000..b8147f2
Binary files /dev/null and b/tests/data/pngsuite/xs2n0g01.png differ
diff --git a/tests/data/pngsuite/xs4n0g01.png b/tests/data/pngsuite/xs4n0g01.png
new file mode 100644
index 0000000..45237a1
Binary files /dev/null and b/tests/data/pngsuite/xs4n0g01.png differ
diff --git a/tests/data/pngsuite/xs7n0g01.png b/tests/data/pngsuite/xs7n0g01.png
new file mode 100644
index 0000000..3f307f1
Binary files /dev/null and b/tests/data/pngsuite/xs7n0g01.png differ
diff --git a/tests/data/pngsuite/z00n2c08.png b/tests/data/pngsuite/z00n2c08.png
new file mode 100644
index 0000000..7669eb8
Binary files /dev/null and b/tests/data/pngsuite/z00n2c08.png differ
diff --git a/tests/data/pngsuite/z03n2c08.png b/tests/data/pngsuite/z03n2c08.png
new file mode 100644
index 0000000..bfb10de
Binary files /dev/null and b/tests/data/pngsuite/z03n2c08.png differ
diff --git a/tests/data/pngsuite/z06n2c08.png b/tests/data/pngsuite/z06n2c08.png
new file mode 100644
index 0000000..b90ebc1
Binary files /dev/null and b/tests/data/pngsuite/z06n2c08.png differ
diff --git a/tests/data/pngsuite/z09n2c08.png b/tests/data/pngsuite/z09n2c08.png
new file mode 100644
index 0000000..5f191a7
Binary files /dev/null and b/tests/data/pngsuite/z09n2c08.png differ
diff --git a/tests/fuzz_png.nim b/tests/fuzz_png.nim
new file mode 100644
index 0000000..fc15db4
--- /dev/null
+++ b/tests/fuzz_png.nim
@@ -0,0 +1,16 @@
+import random, strformat, pixie/fileformats/png, pixie/common, pngsuite
+
+randomize()
+
+for i in 0 ..< 10_000:
+  let file = pngSuiteFiles[rand(pngSuiteFiles.len - 1)]
+  var data = cast[seq[uint8]](readFile(&"tests/data/pngsuite/{file}.png"))
+  let
+    pos = 29 + rand(data.len - 30)
+    value = rand(255).uint8
+  data[pos] = value
+  echo &"{i} {file} {pos} {value}"
+  try:
+    discard decodePng(data)
+  except PixieError:
+    discard
diff --git a/tests/pngsuite.nim b/tests/pngsuite.nim
new file mode 100644
index 0000000..d843c73
--- /dev/null
+++ b/tests/pngsuite.nim
@@ -0,0 +1,73 @@
+const pngSuiteFiles* = [
+  # Basic
+  "basn0g01", # black & white
+  "basn0g02", # 2 bit (4 level) grayscale
+  "basn0g04", # 4 bit (16 level) grayscale
+  "basn0g08", # 8 bit (256 level) grayscale
+  # "basn0g16", # 16 bit (64k level) grayscale
+  "basn2c08", # 3x8 bits rgb color
+  # "basn2c16", # 3x16 bits rgb color
+  "basn3p01", # 1 bit (2 color) paletted
+  "basn3p02", # 2 bit (4 color) paletted
+  "basn3p04", # 4 bit (16 color) paletted
+  "basn3p08", # 8 bit (256 color) paletted
+  "basn4a08", # 8 bit grayscale + 8 bit alpha-channel
+  # "basn4a16", # 16 bit grayscale + 16 bit alpha-channel
+  "basn6a08", # 3x8 bits rgb color + 8 bit alpha-channel
+  # "basn6a16", # 3x16 bits rgb color + 16 bit alpha-channel
+
+  # Interlaced
+  # "basi0g01", # black & white
+  # "basi0g02", # 2 bit (4 level) grayscale
+  # "basi0g04", # 4 bit (16 level) grayscale
+  # "basi0g08", # 8 bit (256 level) grayscale
+  # "basi0g16", # 16 bit (64k level) grayscale
+  # "basi2c08", # 3x8 bits rgb color
+  # "basi2c16", # 3x16 bits rgb color
+  # "basi3p01", # 1 bit (2 color) paletted
+  # "basi3p02", # 2 bit (4 color) paletted
+  # "basi3p04", # 4 bit (16 color) paletted
+  # "basi3p08", # 8 bit (256 color) paletted
+  # "basi4a08", # 8 bit grayscale + 8 bit alpha-channel
+  # "basi4a16", # 16 bit grayscale + 16 bit alpha-channel
+  # "basi6a08", # 3x8 bits rgb color + 8 bit alpha-channel
+  # "basi6a16", # 3x16 bits rgb color + 16 bit alpha-channel
+
+  # Odd sizes
+  # "s01i3p01", # 1x1 paletted file, interlaced
+  "s01n3p01", # 1x1 paletted file, no interlacing
+  # "s02i3p01", # 2x2 paletted file, interlaced
+  "s02n3p01", # 2x2 paletted file, no interlacing
+  # "s03i3p01", # 3x3 paletted file, interlaced
+  "s03n3p01", # 3x3 paletted file, no interlacing
+  # "s04i3p01", # 4x4 paletted file, interlaced
+  "s04n3p01", # 4x4 paletted file, no interlacing
+  # "s05i3p02", # 5x5 paletted file, interlaced
+  "s05n3p02", # 5x5 paletted file, no interlacing
+  # "s06i3p02", # 6x6 paletted file, interlaced
+  "s06n3p02", # 6x6 paletted file, no interlacing
+  # "s07i3p02", # 7x7 paletted file, interlaced
+  "s07n3p02", # 7x7 paletted file, no interlacing
+  # "s08i3p02", # 8x8 paletted file, interlaced
+  "s08n3p02", # 8x8 paletted file, no interlacing
+  # "s09i3p02", # 9x9 paletted file, interlaced
+  "s09n3p02", # 9x9 paletted file, no interlacing
+  # "s32i3p04", # 32x32 paletted file, interlaced
+  "s32n3p04", # 32x32 paletted file, no interlacing
+  # "s33i3p04", # 33x33 paletted file, interlaced
+  "s33n3p04", # 33x33 paletted file, no interlacing
+  # "s34i3p04", # 34x34 paletted file, interlaced
+  "s34n3p04", # 34x34 paletted file, no interlacing
+  # "s35i3p04", # 35x35 paletted file, interlaced
+  "s35n3p04", # 35x35 paletted file, no interlacing
+  # "s36i3p04", # 36x36 paletted file, interlaced
+  "s36n3p04", # 36x36 paletted file, no interlacing
+  # "s37i3p04", # 37x37 paletted file, interlaced
+  "s37n3p04", # 37x37 paletted file, no interlacing
+  # "s38i3p04", # 38x38 paletted file, interlaced
+  "s38n3p04", # 38x38 paletted file, no interlacing
+  # "s39i3p04", # 39x39 paletted file, interlaced
+  "s39n3p04", # 39x39 paletted file, no interlacing
+  # "s40i3p04", # 40x40 paletted file, interlaced
+  "s40n3p04", # 40x40 paletted file, no interlacing
+]
diff --git a/tests/test_png.nim b/tests/test_png.nim
new file mode 100644
index 0000000..5ad64fe
--- /dev/null
+++ b/tests/test_png.nim
@@ -0,0 +1,22 @@
+import pixie/fileformats/png, strformat, pngsuite
+
+for file in pngSuiteFiles:
+  let
+    original = cast[seq[uint8]](readFile(&"tests/data/pngsuite/{file}.png"))
+    decoded = decodePng(original)
+    encoded = encodePng(decoded)
+    decoded2 = decodePng(cast[seq[uint8]](encoded))
+
+  doAssert decoded.height == decoded2.height
+  doAssert decoded.width == decoded2.width
+  doAssert decoded.data == decoded2.data
+
+for channels in 1 .. 4:
+  var data: seq[uint8]
+  for x in 0 ..< 16:
+    for y in 0 ..< 16:
+        var components = newSeq[uint8](channels)
+        for i in 0 ..< channels:
+          components[i] = (x * 16).uint8
+        data.add(components)
+  let encoded = encodePng(16, 16, channels, data[0].addr, data.len)
diff --git a/tests/validate_png.nim b/tests/validate_png.nim
new file mode 100644
index 0000000..4acc22a
--- /dev/null
+++ b/tests/validate_png.nim
@@ -0,0 +1,32 @@
+import chroma, pixie/fileformats/png, stb_image/read as stbi, strformat, pngsuite
+
+for file in pngSuiteFiles:
+  let
+    data = readFile(&"tests/data/pngsuite/{file}.png")
+    pixieLoaded = decodePng(cast[seq[uint8]](data))
+
+  var
+    width, height, channels: int
+    stbiLoadedData = loadFromMemory(
+      cast[seq[byte]](data),
+      width,
+      height,
+      channels,
+      stbi.RGBA
+    )
+    stbiLoadedRGBA: seq[ColorRGBA]
+
+  var i: int
+  while i < stbiLoadedData.len:
+    stbiLoadedRGBA.add(ColorRGBA(
+      r: stbiLoadedData[i + 0],
+      g: stbiLoadedData[i + 1],
+      b: stbiLoadedData[i + 2],
+      a: stbiLoadedData[i + 3]
+    ))
+    i += 4
+
+  doAssert pixieLoaded.width == width
+  doAssert pixieLoaded.height == height
+  doAssert pixieLoaded.data.len == stbiLoadedRGBA.len
+  doAssert pixieLoaded.data == stbiLoadedRGBA