|
@ -9,4 +9,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"
|
||||
|
|
|
@ -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.
|
||||
|
|
432
src/pixie/fileformats/png.nim
Normal file
|
@ -0,0 +1,432 @@
|
|||
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 = 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.}
|
|
@ -1,4 +1,4 @@
|
|||
import strformat, chroma, chroma/blends, vmath
|
||||
import chroma, chroma/blends, vmath
|
||||
|
||||
type
|
||||
Image* = ref object
|
||||
|
|
22
tests/benchmark_png.nim
Normal file
|
@ -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
|
||||
)
|
BIN
tests/data/lenna.png
Normal file
After Width: | Height: | Size: 463 KiB |
9
tests/data/pngsuite/PngSuite.LICENSE
Normal file
|
@ -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
|
||||
|
25
tests/data/pngsuite/PngSuite.README
Normal file
|
@ -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
|
||||
|
BIN
tests/data/pngsuite/PngSuite.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
tests/data/pngsuite/basi0g01.png
Normal file
After Width: | Height: | Size: 217 B |
BIN
tests/data/pngsuite/basi0g02.png
Normal file
After Width: | Height: | Size: 154 B |
BIN
tests/data/pngsuite/basi0g04.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
tests/data/pngsuite/basi0g08.png
Normal file
After Width: | Height: | Size: 254 B |
BIN
tests/data/pngsuite/basi0g16.png
Normal file
After Width: | Height: | Size: 299 B |
BIN
tests/data/pngsuite/basi2c08.png
Normal file
After Width: | Height: | Size: 315 B |
BIN
tests/data/pngsuite/basi2c16.png
Normal file
After Width: | Height: | Size: 595 B |
BIN
tests/data/pngsuite/basi3p01.png
Normal file
After Width: | Height: | Size: 132 B |
BIN
tests/data/pngsuite/basi3p02.png
Normal file
After Width: | Height: | Size: 193 B |
BIN
tests/data/pngsuite/basi3p04.png
Normal file
After Width: | Height: | Size: 327 B |
BIN
tests/data/pngsuite/basi3p08.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
tests/data/pngsuite/basi4a08.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
tests/data/pngsuite/basi4a16.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
tests/data/pngsuite/basi6a08.png
Normal file
After Width: | Height: | Size: 361 B |
BIN
tests/data/pngsuite/basi6a16.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
tests/data/pngsuite/basn0g01.png
Normal file
After Width: | Height: | Size: 164 B |
BIN
tests/data/pngsuite/basn0g02.png
Normal file
After Width: | Height: | Size: 104 B |
BIN
tests/data/pngsuite/basn0g04.png
Normal file
After Width: | Height: | Size: 145 B |
BIN
tests/data/pngsuite/basn0g08.png
Normal file
After Width: | Height: | Size: 138 B |
BIN
tests/data/pngsuite/basn0g16.png
Normal file
After Width: | Height: | Size: 167 B |
BIN
tests/data/pngsuite/basn2c08.png
Normal file
After Width: | Height: | Size: 145 B |
BIN
tests/data/pngsuite/basn2c16.png
Normal file
After Width: | Height: | Size: 302 B |
BIN
tests/data/pngsuite/basn3p01.png
Normal file
After Width: | Height: | Size: 112 B |
BIN
tests/data/pngsuite/basn3p02.png
Normal file
After Width: | Height: | Size: 146 B |
BIN
tests/data/pngsuite/basn3p04.png
Normal file
After Width: | Height: | Size: 216 B |
BIN
tests/data/pngsuite/basn3p08.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
tests/data/pngsuite/basn4a08.png
Normal file
After Width: | Height: | Size: 126 B |
BIN
tests/data/pngsuite/basn4a16.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
tests/data/pngsuite/basn6a08.png
Normal file
After Width: | Height: | Size: 184 B |
BIN
tests/data/pngsuite/basn6a16.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
tests/data/pngsuite/bgai4a08.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
tests/data/pngsuite/bgai4a16.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
tests/data/pngsuite/bgan6a08.png
Normal file
After Width: | Height: | Size: 184 B |
BIN
tests/data/pngsuite/bgan6a16.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
tests/data/pngsuite/bgbn4a08.png
Normal file
After Width: | Height: | Size: 140 B |
BIN
tests/data/pngsuite/bggn4a16.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
tests/data/pngsuite/bgwn6a08.png
Normal file
After Width: | Height: | Size: 202 B |
BIN
tests/data/pngsuite/bgyn6a16.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
tests/data/pngsuite/ccwn2c08.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
tests/data/pngsuite/ccwn3p08.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
tests/data/pngsuite/cdfn2c08.png
Normal file
After Width: | Height: | Size: 404 B |
BIN
tests/data/pngsuite/cdhn2c08.png
Normal file
After Width: | Height: | Size: 344 B |
BIN
tests/data/pngsuite/cdsn2c08.png
Normal file
After Width: | Height: | Size: 232 B |
BIN
tests/data/pngsuite/cdun2c08.png
Normal file
After Width: | Height: | Size: 724 B |
BIN
tests/data/pngsuite/ch1n3p04.png
Normal file
After Width: | Height: | Size: 258 B |
BIN
tests/data/pngsuite/ch2n3p08.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
tests/data/pngsuite/cm0n0g04.png
Normal file
After Width: | Height: | Size: 292 B |
BIN
tests/data/pngsuite/cm7n0g04.png
Normal file
After Width: | Height: | Size: 292 B |
BIN
tests/data/pngsuite/cm9n0g04.png
Normal file
After Width: | Height: | Size: 292 B |
BIN
tests/data/pngsuite/cs3n2c16.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
tests/data/pngsuite/cs3n3p08.png
Normal file
After Width: | Height: | Size: 259 B |
BIN
tests/data/pngsuite/cs5n2c08.png
Normal file
After Width: | Height: | Size: 186 B |
BIN
tests/data/pngsuite/cs5n3p08.png
Normal file
After Width: | Height: | Size: 271 B |
BIN
tests/data/pngsuite/cs8n2c08.png
Normal file
After Width: | Height: | Size: 149 B |
BIN
tests/data/pngsuite/cs8n3p08.png
Normal file
After Width: | Height: | Size: 256 B |
BIN
tests/data/pngsuite/ct0n0g04.png
Normal file
After Width: | Height: | Size: 273 B |
BIN
tests/data/pngsuite/ct1n0g04.png
Normal file
After Width: | Height: | Size: 792 B |
BIN
tests/data/pngsuite/cten0g04.png
Normal file
After Width: | Height: | Size: 742 B |
BIN
tests/data/pngsuite/ctfn0g04.png
Normal file
After Width: | Height: | Size: 716 B |
BIN
tests/data/pngsuite/ctgn0g04.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tests/data/pngsuite/cthn0g04.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tests/data/pngsuite/ctjn0g04.png
Normal file
After Width: | Height: | Size: 941 B |
BIN
tests/data/pngsuite/ctzn0g04.png
Normal file
After Width: | Height: | Size: 753 B |
BIN
tests/data/pngsuite/exif2c08.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
tests/data/pngsuite/f00n0g08.png
Normal file
After Width: | Height: | Size: 319 B |
BIN
tests/data/pngsuite/f00n2c08.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
tests/data/pngsuite/f01n0g08.png
Normal file
After Width: | Height: | Size: 321 B |
BIN
tests/data/pngsuite/f01n2c08.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tests/data/pngsuite/f02n0g08.png
Normal file
After Width: | Height: | Size: 355 B |
BIN
tests/data/pngsuite/f02n2c08.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
tests/data/pngsuite/f03n0g08.png
Normal file
After Width: | Height: | Size: 389 B |
BIN
tests/data/pngsuite/f03n2c08.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
tests/data/pngsuite/f04n0g08.png
Normal file
After Width: | Height: | Size: 269 B |
BIN
tests/data/pngsuite/f04n2c08.png
Normal file
After Width: | Height: | Size: 985 B |
BIN
tests/data/pngsuite/f99n0g04.png
Normal file
After Width: | Height: | Size: 426 B |
BIN
tests/data/pngsuite/g03n0g16.png
Normal file
After Width: | Height: | Size: 345 B |
BIN
tests/data/pngsuite/g03n2c08.png
Normal file
After Width: | Height: | Size: 370 B |
BIN
tests/data/pngsuite/g03n3p04.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
tests/data/pngsuite/g04n0g16.png
Normal file
After Width: | Height: | Size: 363 B |
BIN
tests/data/pngsuite/g04n2c08.png
Normal file
After Width: | Height: | Size: 377 B |
BIN
tests/data/pngsuite/g04n3p04.png
Normal file
After Width: | Height: | Size: 219 B |
BIN
tests/data/pngsuite/g05n0g16.png
Normal file
After Width: | Height: | Size: 339 B |
BIN
tests/data/pngsuite/g05n2c08.png
Normal file
After Width: | Height: | Size: 350 B |
BIN
tests/data/pngsuite/g05n3p04.png
Normal file
After Width: | Height: | Size: 206 B |
BIN
tests/data/pngsuite/g07n0g16.png
Normal file
After Width: | Height: | Size: 321 B |
BIN
tests/data/pngsuite/g07n2c08.png
Normal file
After Width: | Height: | Size: 340 B |
BIN
tests/data/pngsuite/g07n3p04.png
Normal file
After Width: | Height: | Size: 207 B |
BIN
tests/data/pngsuite/g10n0g16.png
Normal file
After Width: | Height: | Size: 262 B |
BIN
tests/data/pngsuite/g10n2c08.png
Normal file
After Width: | Height: | Size: 285 B |
BIN
tests/data/pngsuite/g10n3p04.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
tests/data/pngsuite/g25n0g16.png
Normal file
After Width: | Height: | Size: 383 B |