mirror of https://github.com/status-im/nimPNG.git
gc:arc refactor 'filterScanline' and add tests
This commit is contained in:
parent
27e76f2d65
commit
43d5548237
|
@ -13,10 +13,13 @@ task tests, "Run tests":
|
||||||
exec "nim c -r tests/test_codec.nim"
|
exec "nim c -r tests/test_codec.nim"
|
||||||
exec "nim c -r tests/test_suite.nim"
|
exec "nim c -r tests/test_suite.nim"
|
||||||
exec "nim c -r tests/test_nimz.nim"
|
exec "nim c -r tests/test_nimz.nim"
|
||||||
|
exec "nim c -r tests/test_filters.nim"
|
||||||
|
|
||||||
exec "nim c -r -d:release tests/test_apng.nim"
|
exec "nim c -r -d:release tests/test_apng.nim"
|
||||||
exec "nim c -r -d:release tests/test_codec.nim"
|
exec "nim c -r -d:release tests/test_codec.nim"
|
||||||
exec "nim c -r -d:release tests/test_suite.nim"
|
exec "nim c -r -d:release tests/test_suite.nim"
|
||||||
exec "nim c -r -d:release tests/test_nimz.nim"
|
exec "nim c -r -d:release tests/test_nimz.nim"
|
||||||
|
exec "nim c -r -d:release tests/test_filters.nim"
|
||||||
|
|
||||||
exec "nim c -r --gc:arc -d:release tests/test_nimz.nim"
|
exec "nim c -r --gc:arc -d:release tests/test_nimz.nim"
|
||||||
|
exec "nim c -r --gc:arc -d:release tests/test_filters.nim"
|
||||||
|
|
|
@ -0,0 +1,310 @@
|
||||||
|
type
|
||||||
|
PNGFilter* = enum
|
||||||
|
FLT_NONE,
|
||||||
|
FLT_SUB,
|
||||||
|
FLT_UP,
|
||||||
|
FLT_AVERAGE,
|
||||||
|
FLT_PAETH
|
||||||
|
|
||||||
|
# Paeth predicter, used by PNG filter type 4
|
||||||
|
proc paethPredictor(a, b, c: int): uint =
|
||||||
|
let pa = abs(b - c)
|
||||||
|
let pb = abs(a - c)
|
||||||
|
let pc = abs(a + b - c - c)
|
||||||
|
|
||||||
|
if(pc < pa) and (pc < pb): return c.uint
|
||||||
|
elif pb < pa: return b.uint
|
||||||
|
result = a.uint
|
||||||
|
|
||||||
|
proc filterScanline*(output: var openArray[byte], input: openArray[byte], byteWidth, len: int, filterType: PNGFilter) =
|
||||||
|
template currPix: untyped = input[i].uint
|
||||||
|
template prevPix: untyped = input[i - byteWidth].uint
|
||||||
|
|
||||||
|
case filterType
|
||||||
|
of FLT_NONE:
|
||||||
|
for i in 0..<len:
|
||||||
|
output[i] = input[i]
|
||||||
|
of FLT_SUB:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = input[i]
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix - prevPix) and 0xFF)
|
||||||
|
of FLT_UP:
|
||||||
|
for i in 0..<len:
|
||||||
|
output[i] = input[i]
|
||||||
|
of FLT_AVERAGE:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = input[i]
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix - (prevPix div 2)) and 0xFF)
|
||||||
|
of FLT_PAETH:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = input[i]
|
||||||
|
#paethPredictor(prevPix, 0, 0) is always prevPix
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix - prevPix) and 0xFF)
|
||||||
|
|
||||||
|
proc filterScanline*(output: var openArray[byte], input, prevLine: openArray[byte], byteWidth, len: int, filterType: PNGFilter) =
|
||||||
|
template currPix: untyped = input[i].uint
|
||||||
|
template prevPix: untyped = input[i - byteWidth].uint
|
||||||
|
template upPix: untyped = prevLine[i].uint
|
||||||
|
template prevPixI: untyped = input[i - byteWidth].int
|
||||||
|
template upPixI: untyped = prevLine[i].int
|
||||||
|
template prevUpPix: untyped = prevLine[i - byteWidth].int
|
||||||
|
|
||||||
|
case filterType
|
||||||
|
of FLT_NONE:
|
||||||
|
for i in 0..<len:
|
||||||
|
output[i] = input[i]
|
||||||
|
of FLT_SUB:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = input[i]
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix - prevPix) and 0xFF)
|
||||||
|
of FLT_UP:
|
||||||
|
for i in 0..<len:
|
||||||
|
output[i] = byte((currPix - upPix) and 0xFF)
|
||||||
|
of FLT_AVERAGE:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = byte((currPix - (upPix div 2)) and 0xFF)
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix - ((prevPix + upPix) div 2)) and 0xFF)
|
||||||
|
of FLT_PAETH:
|
||||||
|
#paethPredictor(0, upPix, 0) is always upPix
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = byte((currPix - upPix) and 0xFF)
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix - paethPredictor(prevPixI, upPixI, prevUpPix)) and 0xFF)
|
||||||
|
#[
|
||||||
|
proc filterZero(output: var DataBuf, input: DataBuf, w, h, bpp: int) =
|
||||||
|
#the width of a input in bytes, not including the filter type
|
||||||
|
let lineBytes = (w * bpp + 7) div 8
|
||||||
|
#byteWidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise
|
||||||
|
let byteWidth = (bpp + 7) div 8
|
||||||
|
var prevLine: DataBuf
|
||||||
|
|
||||||
|
for y in 0..h-1:
|
||||||
|
let outindex = (1 + lineBytes) * y #the extra filterbyte added to each row
|
||||||
|
let inindex = lineBytes * y
|
||||||
|
output[outindex] = byte(int(FLT_NONE)) #filter type byte
|
||||||
|
var outp = output.subbuffer(outindex + 1)
|
||||||
|
let input = input.subbuffer(inindex)
|
||||||
|
filterScanline(outp, input, prevLine, lineBytes, byteWidth, FLT_NONE)
|
||||||
|
prevLine = input.subbuffer(inindex)
|
||||||
|
|
||||||
|
proc filterMinsum(output: var DataBuf, input: DataBuf, w, h, bpp: int) =
|
||||||
|
let lineBytes = (w * bpp + 7) div 8
|
||||||
|
let byteWidth = (bpp + 7) div 8
|
||||||
|
|
||||||
|
#adaptive filtering
|
||||||
|
var sum = [0, 0, 0, 0, 0]
|
||||||
|
var smallest = 0
|
||||||
|
|
||||||
|
#five filtering attempts, one for each filter type
|
||||||
|
var attempt: array[0..4, string]
|
||||||
|
var bestType = 0
|
||||||
|
var prevLine: DataBuf
|
||||||
|
|
||||||
|
for i in 0..attempt.high:
|
||||||
|
attempt[i] = newString(lineBytes)
|
||||||
|
|
||||||
|
for y in 0..h-1:
|
||||||
|
#try the 5 filter types
|
||||||
|
for fType in 0..4:
|
||||||
|
var outp = initBuffer(attempt[fType])
|
||||||
|
filterScanline(outp, input.subbuffer(y * lineBytes), prevLine, lineBytes, byteWidth, PNGFilter0(fType))
|
||||||
|
#calculate the sum of the result
|
||||||
|
sum[fType] = 0
|
||||||
|
if fType == 0:
|
||||||
|
for x in 0..lineBytes-1:
|
||||||
|
sum[fType] += ord(attempt[fType][x])
|
||||||
|
else:
|
||||||
|
for x in 0..lineBytes-1:
|
||||||
|
#For differences, each byte should be treated as signed, values above 127 are negative
|
||||||
|
#(converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there.
|
||||||
|
#This means filtertype 0 is almost never chosen, but that is justified.
|
||||||
|
let s = ord(attempt[fType][x])
|
||||||
|
if s < 128: sum[fType] += s
|
||||||
|
else: sum[fType] += (255 - s)
|
||||||
|
|
||||||
|
#check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
|
||||||
|
if(fType == 0) or (sum[fType] < smallest):
|
||||||
|
bestType = fType
|
||||||
|
smallest = sum[fType]
|
||||||
|
|
||||||
|
prevLine = input.subbuffer(y * lineBytes)
|
||||||
|
#now fill the out values
|
||||||
|
#the first byte of a input will be the filter type
|
||||||
|
output[y * (lineBytes + 1)] = byte(bestType)
|
||||||
|
for x in 0..lineBytes-1:
|
||||||
|
output[y * (lineBytes + 1) + 1 + x] = attempt[bestType][x]
|
||||||
|
|
||||||
|
proc filterEntropy(output: var DataBuf, input: DataBuf, w, h, bpp: int) =
|
||||||
|
let lineBytes = (w * bpp + 7) div 8
|
||||||
|
let byteWidth = (bpp + 7) div 8
|
||||||
|
var prevLine: DataBuf
|
||||||
|
|
||||||
|
var sum: array[0..4, float]
|
||||||
|
var smallest = 0.0
|
||||||
|
var bestType = 0
|
||||||
|
var attempt: array[0..4, string]
|
||||||
|
var count: array[0..255, int]
|
||||||
|
|
||||||
|
for i in 0..attempt.high:
|
||||||
|
attempt[i] = newString(lineBytes)
|
||||||
|
|
||||||
|
for y in 0..h-1:
|
||||||
|
#try the 5 filter types
|
||||||
|
for fType in 0..4:
|
||||||
|
var outp = initBuffer(attempt[fType])
|
||||||
|
filterScanline(outp, input.subbuffer(y * lineBytes), prevLine, lineBytes, byteWidth, PNGFilter0(fType))
|
||||||
|
for x in 0..255: count[x] = 0
|
||||||
|
for x in 0..lineBytes-1:
|
||||||
|
inc count[ord(attempt[fType][x])]
|
||||||
|
inc count[fType] #the filter type itself is part of the input
|
||||||
|
sum[fType] = 0
|
||||||
|
for x in 0..255:
|
||||||
|
let p = float(count[x]) / float(lineBytes + 1)
|
||||||
|
if count[x] != 0: sum[fType] += log2(1 / p) * p
|
||||||
|
|
||||||
|
#check if this is smallest sum (or if type == 0 it's the first case so always store the values)
|
||||||
|
if (fType == 0) or (sum[fType] < smallest):
|
||||||
|
bestType = fType
|
||||||
|
smallest = sum[fType]
|
||||||
|
|
||||||
|
prevLine = input.subbuffer(y * lineBytes)
|
||||||
|
#now fill the out values*/
|
||||||
|
#the first byte of a input will be the filter type
|
||||||
|
output[y * (lineBytes + 1)] = byte(bestType)
|
||||||
|
for x in 0..lineBytes-1:
|
||||||
|
output[y * (lineBytes + 1) + 1 + x] = attempt[bestType][x]
|
||||||
|
|
||||||
|
proc filterPredefined(output: var DataBuf, input: DataBuf, w, h, bpp: int, state: PNGEncoder) =
|
||||||
|
let lineBytes = (w * bpp + 7) div 8
|
||||||
|
let byteWidth = (bpp + 7) div 8
|
||||||
|
var prevLine: DataBuf
|
||||||
|
|
||||||
|
for y in 0..h-1:
|
||||||
|
let outindex = (1 + lineBytes) * y #the extra filterbyte added to each row
|
||||||
|
let inindex = lineBytes * y
|
||||||
|
let fType = ord(state.predefinedFilters[y])
|
||||||
|
output[outindex] = byte(fType) #filter type byte
|
||||||
|
var outp = output.subbuffer(outindex + 1)
|
||||||
|
filterScanline(outp, input.subbuffer(inindex), prevLine, lineBytes, byteWidth, PNGFilter0(fType))
|
||||||
|
prevLine = input.subbuffer(inindex)
|
||||||
|
|
||||||
|
proc filterBruteForce(output: var DataBuf, input: DataBuf, w, h, bpp: int) =
|
||||||
|
let lineBytes = (w * bpp + 7) div 8
|
||||||
|
let byteWidth = (bpp + 7) div 8
|
||||||
|
var prevLine: DataBuf
|
||||||
|
|
||||||
|
#brute force filter chooser.
|
||||||
|
#deflate the input after every filter attempt to see which one deflates best.
|
||||||
|
#This is very slow and gives only slightly smaller, sometimes even larger, result*/
|
||||||
|
|
||||||
|
var size: array[0..4, int]
|
||||||
|
var attempt: array[0..4, string] #five filtering attempts, one for each filter type
|
||||||
|
var smallest = 0
|
||||||
|
var bestType = 0
|
||||||
|
|
||||||
|
#use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose,
|
||||||
|
#to simulate the true case where the tree is the same for the whole image. Sometimes it gives
|
||||||
|
#better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare
|
||||||
|
#cases better compression. It does make this a bit less slow, so it's worth doing this.
|
||||||
|
|
||||||
|
for i in 0..attempt.high:
|
||||||
|
attempt[i] = newString(lineBytes)
|
||||||
|
|
||||||
|
for y in 0..h-1:
|
||||||
|
#try the 5 filter types
|
||||||
|
for fType in 0..4:
|
||||||
|
#let testSize = attempt[fType].len
|
||||||
|
var outp = initBuffer(attempt[fType])
|
||||||
|
filterScanline(outp, input.subbuffer(y * lineBytes), prevLine, lineBytes, byteWidth, PNGFilter0(fType))
|
||||||
|
size[fType] = 0
|
||||||
|
|
||||||
|
var nz = nzDeflateInit(attempt[fType])
|
||||||
|
let data = zlib_compress(nz)
|
||||||
|
size[fType] = data.len
|
||||||
|
|
||||||
|
#check if this is smallest size (or if type == 0 it's the first case so always store the values)
|
||||||
|
if(fType == 0) or (size[fType] < smallest):
|
||||||
|
bestType = fType
|
||||||
|
smallest = size[fType]
|
||||||
|
|
||||||
|
prevLine = input.subbuffer(y * lineBytes)
|
||||||
|
output[y * (lineBytes + 1)] = byte(bestType) #the first byte of a input will be the filter type
|
||||||
|
for x in 0..lineBytes-1:
|
||||||
|
output[y * (lineBytes + 1) + 1 + x] = attempt[bestType][x]
|
||||||
|
]#
|
||||||
|
|
||||||
|
proc unfilterScanline*(output: var openArray[byte], input: openArray[byte], byteWidth, len: int, filterType: PNGFilter) =
|
||||||
|
# When the pixels are smaller than 1 byte, the filter works byte per byte (byteWidth = 1)
|
||||||
|
# the incoming inputs do NOT include the filtertype byte, that one is given in the parameter filterType instead
|
||||||
|
# output and input MAY be the same memory address! output must be disjoint.
|
||||||
|
|
||||||
|
template currPix: untyped = input[i].uint
|
||||||
|
template prevPix: untyped = output[i - byteWidth].uint
|
||||||
|
|
||||||
|
case filterType
|
||||||
|
of FLT_NONE:
|
||||||
|
for i in 0..<len:
|
||||||
|
output[i] = input[i]
|
||||||
|
of FLT_SUB:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = input[i]
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix + prevPix) and 0xFF)
|
||||||
|
of FLT_UP:
|
||||||
|
for i in 0..<len:
|
||||||
|
output[i] = input[i]
|
||||||
|
of FLT_AVERAGE:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = input[i]
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix + (prevPix div 2)) and 0xFF)
|
||||||
|
of FLT_PAETH:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = input[i]
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
# paethPredictor(prevPix, 0, 0) is always prevPix
|
||||||
|
output[i] = byte((currPix + prevPix) and 0xFF)
|
||||||
|
|
||||||
|
proc unfilterScanline*(output: var openArray[byte], input, prevLine: openArray[byte], byteWidth, len: int, filterType: PNGFilter) =
|
||||||
|
# For PNG filter method 0
|
||||||
|
# unfilter a PNG image input by input. when the pixels are smaller than 1 byte,
|
||||||
|
# the filter works byte per byte (byteWidth = 1)
|
||||||
|
# prevLine is the previous unfiltered input, output the result, input the current one
|
||||||
|
# the incoming inputs do NOT include the filtertype byte, that one is given in the parameter filterType instead
|
||||||
|
# output and input MAY be the same memory address! prevLine must be disjoint.
|
||||||
|
|
||||||
|
template currPix: untyped = input[i].uint
|
||||||
|
template prevPix: untyped = output[i - byteWidth].uint
|
||||||
|
template upPix: untyped = prevLine[i].uint
|
||||||
|
template prevPixI: untyped = output[i - byteWidth].int
|
||||||
|
template upPixI: untyped = prevLine[i].int
|
||||||
|
template prevUpPix: untyped = prevLine[i - byteWidth].int
|
||||||
|
|
||||||
|
case filterType
|
||||||
|
of FLT_NONE:
|
||||||
|
for i in 0..<len:
|
||||||
|
output[i] = input[i]
|
||||||
|
of FLT_SUB:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = input[i]
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix + prevPix) and 0xFF)
|
||||||
|
of FLT_UP:
|
||||||
|
for i in 0..<len:
|
||||||
|
output[i] = byte((currPix + upPix) and 0xFF)
|
||||||
|
of FLT_AVERAGE:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
output[i] = byte((currPix + upPix div 2) and 0xFF)
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix + ((prevPix + upPix) div 2)) and 0xFF)
|
||||||
|
of FLT_PAETH:
|
||||||
|
for i in 0..<byteWidth:
|
||||||
|
# paethPredictor(0, upPix, 0) is always upPix
|
||||||
|
output[i] = byte((currPix + upPix) and 0xFF)
|
||||||
|
for i in byteWidth..<len:
|
||||||
|
output[i] = byte((currPix + paethPredictor(prevPixI, upPixI, prevUpPix)) and 0xFF)
|
|
@ -0,0 +1,58 @@
|
||||||
|
import random, sets
|
||||||
|
|
||||||
|
type
|
||||||
|
RandGen*[T] = object
|
||||||
|
minVal, maxVal: T
|
||||||
|
|
||||||
|
Bytes* = seq[byte]
|
||||||
|
|
||||||
|
proc rng*[T](minVal, maxVal: T): RandGen[T] =
|
||||||
|
doAssert(minVal <= maxVal)
|
||||||
|
result.minVal = minVal
|
||||||
|
result.maxVal = maxVal
|
||||||
|
|
||||||
|
proc rng*[T](minMax: T): RandGen[T] =
|
||||||
|
rng(minMax, minMax)
|
||||||
|
|
||||||
|
proc getVal*[T](x: RandGen[T]): T =
|
||||||
|
if x.minVal == x.maxVal: return x.minVal
|
||||||
|
rand(x.minVal..x.maxVal)
|
||||||
|
|
||||||
|
proc randString*(len: int): string =
|
||||||
|
result = newString(len)
|
||||||
|
for i in 0..<len:
|
||||||
|
result[i] = rand(255).char
|
||||||
|
|
||||||
|
proc randBytes*(len: int): Bytes =
|
||||||
|
result = newSeq[byte](len)
|
||||||
|
for i in 0..<len:
|
||||||
|
result[i] = rand(255).byte
|
||||||
|
|
||||||
|
proc randPrimitives*[T](val: int): T =
|
||||||
|
when T is string:
|
||||||
|
randString(val)
|
||||||
|
elif T is int:
|
||||||
|
result = val
|
||||||
|
elif T is byte:
|
||||||
|
result = val.byte
|
||||||
|
elif T is Bytes:
|
||||||
|
result = randBytes(val)
|
||||||
|
|
||||||
|
proc randList*(T: typedesc, fillGen: RandGen, listLen: int, unique: static[bool] = true): seq[T] =
|
||||||
|
result = newSeqOfCap[T](listLen)
|
||||||
|
when unique:
|
||||||
|
var set = initSet[T]()
|
||||||
|
for len in 0..<listLen:
|
||||||
|
while true:
|
||||||
|
let x = randPrimitives[T](fillGen.getVal())
|
||||||
|
if x notin set:
|
||||||
|
result.add x
|
||||||
|
set.incl x
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
for len in 0..<listLen:
|
||||||
|
let x = randPrimitives[T](fillGen.getVal())
|
||||||
|
result.add x
|
||||||
|
|
||||||
|
proc randList*(T: typedesc, fillGen, listGen: RandGen, unique: static[bool] = true): seq[T] =
|
||||||
|
randList(T, fillGen, listGen.getVal(), unique)
|
|
@ -0,0 +1,97 @@
|
||||||
|
import ../nimPNG/filters, ./randutils, unittest
|
||||||
|
|
||||||
|
template roundTripFilter(byteWidth: int, filter: PNGFilter) =
|
||||||
|
filterScanline(outPix, inPix, byteWidth, lineBytes, filter)
|
||||||
|
unfilterScanline(oriPix, outPix, byteWidth, lineBytes, filter)
|
||||||
|
check oriPix == inPix
|
||||||
|
|
||||||
|
template roundTripFilterP(byteWidth: int, filter: PNGFilter) =
|
||||||
|
# with prevLine
|
||||||
|
filterScanline(outPix, inPix, prevLine, byteWidth, lineBytes, filter)
|
||||||
|
unfilterScanline(oriPix, outPix, prevLine, byteWidth, lineBytes, filter)
|
||||||
|
check oriPix == inPix
|
||||||
|
|
||||||
|
proc testFilterScanline() =
|
||||||
|
suite "filterScanline":
|
||||||
|
const
|
||||||
|
lineBytes = 128
|
||||||
|
|
||||||
|
let
|
||||||
|
inPix = randList(byte, rng(0, 255), lineBytes, unique = false)
|
||||||
|
prevLine = randList(byte, rng(0, 255), lineBytes, unique = false)
|
||||||
|
|
||||||
|
var
|
||||||
|
outPix = newSeq[byte](lineBytes)
|
||||||
|
oriPix = newSeq[byte](lineBytes)
|
||||||
|
|
||||||
|
test "FLT_NONE":
|
||||||
|
roundTripFilter(1, FLT_NONE)
|
||||||
|
roundTripFilter(2, FLT_NONE)
|
||||||
|
roundTripFilter(3, FLT_NONE)
|
||||||
|
roundTripFilter(4, FLT_NONE)
|
||||||
|
|
||||||
|
test "FLT_SUB":
|
||||||
|
roundTripFilter(1, FLT_SUB)
|
||||||
|
roundTripFilter(2, FLT_SUB)
|
||||||
|
roundTripFilter(3, FLT_SUB)
|
||||||
|
roundTripFilter(4, FLT_SUB)
|
||||||
|
|
||||||
|
test "FLT_UP":
|
||||||
|
roundTripFilter(1, FLT_UP)
|
||||||
|
roundTripFilter(2, FLT_UP)
|
||||||
|
roundTripFilter(3, FLT_UP)
|
||||||
|
roundTripFilter(4, FLT_UP)
|
||||||
|
|
||||||
|
test "FLT_AVERAGE":
|
||||||
|
roundTripFilter(1, FLT_AVERAGE)
|
||||||
|
roundTripFilter(2, FLT_AVERAGE)
|
||||||
|
roundTripFilter(3, FLT_AVERAGE)
|
||||||
|
roundTripFilter(4, FLT_AVERAGE)
|
||||||
|
|
||||||
|
test "FLT_PAETH":
|
||||||
|
roundTripFilter(1, FLT_PAETH)
|
||||||
|
roundTripFilter(2, FLT_PAETH)
|
||||||
|
roundTripFilter(3, FLT_PAETH)
|
||||||
|
roundTripFilter(4, FLT_PAETH)
|
||||||
|
|
||||||
|
test "FLT_NONE with prevLine":
|
||||||
|
roundTripFilterP(1, FLT_NONE)
|
||||||
|
roundTripFilterP(2, FLT_NONE)
|
||||||
|
roundTripFilterP(3, FLT_NONE)
|
||||||
|
roundTripFilterP(4, FLT_NONE)
|
||||||
|
|
||||||
|
test "FLT_SUB with prevLine":
|
||||||
|
roundTripFilterP(1, FLT_SUB)
|
||||||
|
roundTripFilterP(2, FLT_SUB)
|
||||||
|
roundTripFilterP(3, FLT_SUB)
|
||||||
|
roundTripFilterP(4, FLT_SUB)
|
||||||
|
|
||||||
|
test "FLT_UP with prevLine":
|
||||||
|
roundTripFilterP(1, FLT_UP)
|
||||||
|
roundTripFilterP(2, FLT_UP)
|
||||||
|
roundTripFilterP(3, FLT_UP)
|
||||||
|
roundTripFilterP(4, FLT_UP)
|
||||||
|
|
||||||
|
test "FLT_AVERAGE with prevLine":
|
||||||
|
roundTripFilterP(1, FLT_AVERAGE)
|
||||||
|
roundTripFilterP(2, FLT_AVERAGE)
|
||||||
|
roundTripFilterP(3, FLT_AVERAGE)
|
||||||
|
roundTripFilterP(4, FLT_AVERAGE)
|
||||||
|
|
||||||
|
test "FLT_PAETH with prevLine":
|
||||||
|
roundTripFilterP(1, FLT_PAETH)
|
||||||
|
roundTripFilterP(2, FLT_PAETH)
|
||||||
|
roundTripFilterP(3, FLT_PAETH)
|
||||||
|
roundTripFilterP(4, FLT_PAETH)
|
||||||
|
|
||||||
|
#of LFS_ZERO: filterZero(output, input, w, h, bpp)
|
||||||
|
#of LFS_MINSUM: filterMinsum(output, input, w, h, bpp)
|
||||||
|
#of LFS_ENTROPY: filterEntropy(output, input, w, h, bpp)
|
||||||
|
#of LFS_BRUTE_FORCE: filterBruteForce(output, input, w, h, bpp)
|
||||||
|
#of LFS_PREDEFINED: filterPredefined(output, input, w, h, bpp, state)
|
||||||
|
|
||||||
|
proc main() =
|
||||||
|
testFilterScanline()
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
Loading…
Reference in New Issue