gc:arc refactor nimPNG encoder/decoder

This commit is contained in:
andri lim 2020-04-14 11:49:37 +07:00
parent b755b8811e
commit a521c46f74
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
3 changed files with 347 additions and 772 deletions

1029
nimPNG.nim

File diff suppressed because it is too large Load Diff

View File

@ -14,10 +14,10 @@ type
const
# shared values used by multiple Adam7 related functions
ADAM7_IX = [ 0, 4, 0, 2, 0, 1, 0 ] # x start values
ADAM7_IY = [ 0, 0, 4, 0, 2, 0, 1 ] # y start values
ADAM7_DX = [ 8, 8, 4, 4, 2, 2, 1 ] # x delta values
ADAM7_DY = [ 8, 8, 8, 4, 4, 2, 2 ] # y delta values
ADAM7_IX* = [ 0, 4, 0, 2, 0, 1, 0 ] # x start values
ADAM7_IY* = [ 0, 0, 4, 0, 2, 0, 1 ] # y start values
ADAM7_DX* = [ 8, 8, 4, 4, 2, 2, 1 ] # x delta values
ADAM7_DY* = [ 8, 8, 8, 4, 4, 2, 2 ] # y delta values
# Paeth predicter, used by PNG filter type 4
proc paethPredictor(a, b, c: int): uint =
@ -400,11 +400,11 @@ proc unfilter*[T](output: var openArray[T], input: openArray[T], w, h, bpp: int)
TWidth, lineTs, filterType)
prevIndex = outIndex
proc readBitFromReversedStream[T](bitptr: var int, bitstream: openArray[T]): int =
proc readBitFromReversedStream*[T](bitptr: var int, bitstream: openArray[T]): int =
result = ((int(bitstream[bitptr shr 3]) shr (7 - (bitptr and 0x7))) and 1)
inc bitptr
proc readBitsFromReversedStream[T](bitptr: var int, bitstream: openArray[T], nbits: int): int =
proc readBitsFromReversedStream*[T](bitptr: var int, bitstream: openArray[T], nbits: int): int =
result = 0
var i = nbits - 1
while i > -1:
@ -417,20 +417,20 @@ proc `&=`[T](a: var T, b: T) =
proc `|=`[T](a: var T, b: T) =
a = T(int(a) or int(b))
proc setBitOfReversedStream0[T](bitptr: var int, bitstream: var openArray[T], bit: int) =
proc setBitOfReversedStream0*[T](bitptr: var int, bitstream: var openArray[T], bit: int) =
# the current bit in bitstream must be 0 for this to work
if bit != 0:
# earlier bit of huffman code is in a lesser significant bit of an earlier T
bitstream[bitptr shr 3] |= T(bit shl (7 - (bitptr and 0x7)))
bitstream[bitptr shr 3] |= cast[T](bit shl (7 - (bitptr and 0x7)))
inc bitptr
proc setBitOfReversedStream[T](bitptr: var int, bitstream: var openArray[T], bit: int) =
proc setBitOfReversedStream*[T](bitptr: var int, bitstream: var openArray[T], bit: int) =
# the current bit in bitstream may be 0 or 1 for this to work
if bit == 0: bitstream[bitptr shr 3] &= T(not (1 shl (7 - (bitptr and 0x7))))
else: bitstream[bitptr shr 3] |= T(1 shl (7 - (bitptr and 0x7)))
if bit == 0: bitstream[bitptr shr 3] &= cast[T](not (1 shl (7 - (bitptr and 0x7))))
else: bitstream[bitptr shr 3] |= cast[T](1 shl (7 - (bitptr and 0x7)))
inc bitptr
proc removePaddingBits[T](output: var openArray[T], input: openArray[T], olinebits, ilinebits, h: int) =
proc removePaddingBits*[T](output: var openArray[T], input: openArray[T], olinebits, ilinebits, h: int) =
# After filtering there are still padding bits if scanLines have non multiple of 8 bit amounts. They need
# to be removed (except at last scanLine of (Adam7-reduced) image) before working with pure image buffers
# for the Adam7 code, the color convert code and the output to the user.
@ -462,7 +462,7 @@ proc removePaddingBits[T](output: var openArray[T], input: openArray[T], olinebi
# bpp: bits per pixel
# "padded" is only relevant if bpp is less than 8 and a scanLine or image does not
# end at a full T
proc adam7PassValues(pass: var PNGPass, w, h, bpp: int) =
proc adam7PassValues*(pass: var PNGPass, w, h, bpp: int) =
# the passstart values have 8 values:
# the 8th one indicates the T after the end of the 7th (= last) pass
@ -554,3 +554,32 @@ proc adam7Interlace*[T](output: var openArray[T], input: openArray[T], w, h, bpp
for b in 0..<bpp:
let bit = readBitFromReversedStream(ibp, input)
setBitOfReversedStream(obp, output, bit)
# index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to
proc addColorBits*[T](output: var openArray[T], index, bits, input: int) =
var m = 1
if bits == 1: m = 7
elif bits == 2: m = 3
# p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half
let p = index and m
var val = input and ((1 shl bits) - 1) # filter out any other bits of the input value
val = val shl (bits * (m - p))
let idx = index * bits div 8
if p == 0: output[idx] = T(val)
else: output[idx] = T(int(output[idx]) or val)
proc addPaddingBits*[T](output: var openArray[T], input: openArray[T], olinebits, ilinebits, h: int) =
#The opposite of the removePaddingBits function
#olinebits must be >= ilinebits
let diff = olinebits - ilinebits
var
obp = 0
ibp = 0 #bit pointers
for y in 0..h-1:
for x in 0..ilinebits-1:
let bit = readBitFromReversedStream(ibp, input)
setBitOfReversedStream(obp, output, bit)
for x in 0..diff-1: setBitOfReversedStream(obp, output, 0)

View File

@ -1,5 +1,5 @@
import ../nimPNG, streams, math, strutils, tables, base64, os
import ../nimPNG/buffer
import ../nimPNG/[buffer, filters]
type
Image = ref object
@ -485,12 +485,12 @@ proc testPredefinedFilters() =
var state = makePNGEncoder()
state.filterStrategy = LFS_PREDEFINED
state.filterPaletteZero = false
# everything to filter type 'FLT_AVERAGE'
state.predefinedFilters = newSeq[PNGFilter](h)
for i in 0..<h:
state.predefinedFilters[i] = FLT_AVERAGE
var png = encodePNG(image.data, w, h, state)
var outFilters = png.getFilterTypes()
@ -591,12 +591,15 @@ proc colorConvertTest(bits_in: string, colorType_in: PNGcolorType, bitDepth_in:
echo "color convert test ", bits_in, " - ", bits_out
let expected = bitStringToBytes(bits_out)
let image = initBuffer(bitStringToBytes(bits_in))
let image = bitStringToBytes(bits_in)
let modeIn = newColorMode(colorType_in, bitDepth_in)
let modeOut = newColorMode(colorType_out, bitDepth_out)
var actual = newString(expected.len)
var actualView = initBuffer(actual)
convert(actualView, image, modeOut, modeIn, 1)
convert(
actual.toOpenArray(0, actual.len-1),
image.toOpenArray(0, image.len-1),
modeOut, modeIn, 1)
for i in 0..expected.high:
assertEquals(expected[i].int, actual[i].int, "byte " & $i)
@ -674,19 +677,19 @@ proc testColorConvert2() =
(colorType: LCT_RGBA, bitDepth: 8),
(colorType: LCT_RGBA, bitDepth: 16)]
eight = initBuffer([0,0,0,255, 255,255,255,255,
eight = [0,0,0,255, 255,255,255,255,
0,0,0,255, 255,255,255,255,
255,255,255,255, 0,0,0,255,
255,255,255,255, 255,255,255,255,
0,0,0,255].toString()) #input in RGBA8
0,0,0,255].toString() #input in RGBA8
var
modeIn = newColorMode()
modeOut = newColorMode()
mode_8 = newColorMode()
input = initBuffer(newString(72))
output = initBuffer(newString(72))
eight2 = initBuffer(newString(36))
input = newString(72)
output = newString(72)
eight2 = newString(36)
for i in 0..255:
let j = if i == 1: 255 else: i
@ -701,10 +704,10 @@ proc testColorConvert2() =
modeOut.colorType = cmb.colorType
modeOut.bitDepth = cmb.bitDepth
convert(input, eight, modeIn, mode_8, 3 * 3)
convert(output, input, modeOut, modeIn, 3 * 3) #Test input to output type
convert(eight2, output, mode_8, modeOut, 3 * 3)
assertEquals(eight.data, eight2.data)
convert(input.toOpenArray(0, input.len-1), eight.toOpenArray(0, eight.len-1), modeIn, mode_8, 3 * 3)
convert(output.toOpenArray(0, output.len-1), input.toOpenArray(0, input.len-1), modeOut, modeIn, 3 * 3) #Test input to output type
convert(eight2.toOpenArray(0, eight2.len-1), output.toOpenArray(0, output.len-1), mode_8, modeOut, 3 * 3)
assertEquals(eight, eight2)
#tests that there are no crashes with auto color chooser in case of palettes with translucency etc...
proc testPaletteToPaletteConvert() =
@ -1198,5 +1201,5 @@ proc doMain() =
testNoAutoConvert()
testAutoColorModels()
testFilter()
doMain()