diff --git a/nimPNG.nim b/nimPNG.nim index 8420f1d..ab23a64 100644 --- a/nimPNG.nim +++ b/nimPNG.nim @@ -28,8 +28,10 @@ import streams, endians, tables, hashes, math import nimPNG/[buffer, nimz, filters] +import strutils + const - NIM_PNG_VERSION = "0.2.4" + NIM_PNG_VERSION = "0.2.6" type PNGChunkType = distinct int32 @@ -2473,13 +2475,12 @@ proc preProcessScanLines[T](png: PNG, input: openArray[T], frameNo, w, h: int, m # if no Adam7: 1) add padding bits (= posible extra bits per scanLine if bpp < 8) 2) filter # if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter let bpp = getBPP(modeOut) - template output: untyped = png.apngPixels[frameNo] if state.interlaceMethod == IM_NONE: # image size plus an extra byte per scanLine + possible padding bits let scanLen = (w * bpp + 7) div 8 let outSize = h + (h * scanLen) - png.apngPixels[frameNo] = newString(outSize) + var output = newString(outSize) # non multiple of 8 bits per scanLine, padding bits needed per scanLine if(bpp < 8) and ((w * bpp) != (scanLen * 8)): @@ -2494,12 +2495,14 @@ proc preProcessScanLines[T](png: PNG, input: openArray[T], frameNo, w, h: int, m filter(output.toOpenArray(0, output.len-1), input, w, h, modeOut, state) + shallowCopy(png.apngPixels[frameNo], output) + else: #interlaceMethod is 1 (Adam7) var pass: PNGPass adam7PassValues(pass, w, h, bpp) let outSize = pass.filterStart[7] - png.apngPixels[frameNo] = newString(outSize) + var output = newString(outSize) var adam7 = newString(pass.start[7]) adam7Interlace(adam7.toOpenArray(0, adam7.len-1), @@ -2520,6 +2523,8 @@ proc preProcessScanLines[T](png: PNG, input: openArray[T], frameNo, w, h: int, m adam7.toOpenArray(pass.paddedStart[i], adam7.len-1), pass.w[i], pass.h[i], modeOut, state) + shallowCopy(png.apngPixels[frameNo], output) + #palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... #returns 0 if the palette is opaque, #returns 1 if the palette has a single color with alpha 0 ==> color key diff --git a/nimPNG.nimble b/nimPNG.nimble index 36ff277..574f6f7 100644 --- a/nimPNG.nimble +++ b/nimPNG.nimble @@ -9,17 +9,5 @@ skipDirs = @["tests", "docs"] requires "nim >= 0.19.0" task tests, "Run tests": - exec "nim c -r tests/test_apng.nim" - exec "nim c -r tests/test_codec.nim" - exec "nim c -r tests/test_suite.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_codec.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_filters.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" + exec "nim c -r -d:release tests/all_tests" + exec "nim c -r --gc:arc -d:release tests/all_tests" diff --git a/nimPNG/filters.nim b/nimPNG/filters.nim index 35591cb..9c97c73 100644 --- a/nimPNG/filters.nim +++ b/nimPNG/filters.nim @@ -29,77 +29,77 @@ proc paethPredictor(a, b, c: int): uint = elif pb < pa: return b.uint result = a.uint -proc filterScanline*[T](output: var openArray[T], input: openArray[T], TWidth, len: int, filterType: PNGFilter) = +proc filterScanline*[T](output: var openArray[T], input: openArray[T], byteWidth, len: int, filterType: PNGFilter) = template currPix: untyped = input[i].uint - template prevPix: untyped = input[i - TWidth].uint + template prevPix: untyped = input[i - byteWidth].uint case filterType of FLT_NONE: for i in 0.. 0: output[0] = T(FLT_NONE) # filterType T filterScanline(output.toOpenArray(1, output.len-1), # skip filterType - input, TWidth, lineTs, FLT_NONE) + input, byteWidth, lineTs, FLT_NONE) # next line start from 1 var prevIndex = 0 @@ -110,12 +110,12 @@ proc filterZero*[T](output: var openArray[T], input: openArray[T], w, h, bpp: in filterScanline(output.toOpenArray(outIndex + 1, output.len-1), # skip filterType input.toOpenArray(inIndex, input.len-1), input.toOpenArray(prevIndex, input.len-1), - TWidth, lineTs, FLT_NONE) + byteWidth, lineTs, FLT_NONE) prevIndex = inIndex proc filterMinsum*[T](output: var openArray[T], input: openArray[T], w, h, bpp: int) = let lineTs = (w * bpp + 7) div 8 - let TWidth = (bpp + 7) div 8 + let byteWidth = (bpp + 7) div 8 #adaptive filtering var @@ -137,12 +137,12 @@ proc filterMinsum*[T](output: var openArray[T], input: openArray[T], w, h, bpp: if y == 0: filterScanline(attempt[fType], input.toOpenArray(inIndex, input.len-1), - TWidth, lineTs, PNGFilter(fType)) + byteWidth, lineTs, PNGFilter(fType)) else: filterScanline(attempt[fType], input.toOpenArray(inIndex, input.len-1), input.toOpenArray(prevIndex, input.len-1), - TWidth, lineTs, PNGFilter(fType)) + byteWidth, lineTs, PNGFilter(fType)) # calculate the sum of the result sum[fType] = 0 @@ -172,7 +172,7 @@ proc filterMinsum*[T](output: var openArray[T], input: openArray[T], w, h, bpp: proc filterEntropy*[T](output: var openArray[T], input: openArray[T], w, h, bpp: int) = let lineTs = (w * bpp + 7) div 8 - let TWidth = (bpp + 7) div 8 + let byteWidth = (bpp + 7) div 8 var sum: array[0..4, float] @@ -192,12 +192,12 @@ proc filterEntropy*[T](output: var openArray[T], input: openArray[T], w, h, bpp: if y == 0: filterScanline(attempt[fType], input.toOpenArray(inIndex, input.len-1), - TWidth, lineTs, PNGFilter(fType)) + byteWidth, lineTs, PNGFilter(fType)) else: filterScanline(attempt[fType], input.toOpenArray(inIndex, input.len-1), input.toOpenArray(prevIndex, input.len-1), - TWidth, lineTs, PNGFilter(fType)) + byteWidth, lineTs, PNGFilter(fType)) for x in 0..255: count[x] = 0 for x in 0..lineTs-1: @@ -225,13 +225,13 @@ proc filterPredefined*[T](output: var openArray[T], input: openArray[T], w, h, bpp: int, predefinedFilters: openArray[PNGFilter]) = let lineTs = (w * bpp + 7) div 8 - let TWidth = (bpp + 7) div 8 + let byteWidth = (bpp + 7) div 8 # line 0 if h > 0: output[0] = T(predefinedFilters[0]) # filterType T filterScanline(output.toOpenArray(1, output.len-1), # skip filterType - input, TWidth, lineTs, predefinedFilters[0]) + input, byteWidth, lineTs, predefinedFilters[0]) # next line start from 1 var prevIndex = 0 @@ -243,12 +243,12 @@ proc filterPredefined*[T](output: var openArray[T], input: openArray[T], filterScanline(output.toOpenArray(outIndex + 1, output.len-1), # skip filterType input.toOpenArray(inIndex, input.len-1), input.toOpenArray(prevIndex, input.len-1), - TWidth, lineTs, PNGFilter(fType)) + byteWidth, lineTs, PNGFilter(fType)) prevIndex = inIndex proc filterBruteForce*[T](output: var openArray[T], input: openArray[T], w, h, bpp: int) = let lineTs = (w * bpp + 7) div 8 - let TWidth = (bpp + 7) div 8 + let byteWidth = (bpp + 7) div 8 # brute force filter chooser. # deflate the input after every filter attempt to see which one deflates best. @@ -277,12 +277,12 @@ proc filterBruteForce*[T](output: var openArray[T], input: openArray[T], w, h, b if y == 0: filterScanline(attempt[fType], input.toOpenArray(inIndex, input.len-1), - TWidth, lineTs, PNGFilter(fType)) + byteWidth, lineTs, PNGFilter(fType)) else: filterScanline(attempt[fType], input.toOpenArray(inIndex, input.len-1), input.toOpenArray(prevIndex, input.len-1), - TWidth, lineTs, PNGFilter(fType)) + byteWidth, lineTs, PNGFilter(fType)) size[fType] = 0 var nz = nzCompressInit(attempt[fType]) @@ -299,75 +299,75 @@ proc filterBruteForce*[T](output: var openArray[T], input: openArray[T], w, h, b for x in 0..lineTs-1: output[y * (lineTs + 1) + 1 + x] = attempt[bestType][x] -proc unfilterScanline*[T](output: var openArray[T], input: openArray[T], TWidth, len: int, filterType: PNGFilter) = - # When the pixels are smaller than 1 T, the filter works T per T (TWidth = 1) +proc unfilterScanline*[T](output: var openArray[T], input: openArray[T], byteWidth, len: int, filterType: PNGFilter) = + # When the pixels are smaller than 1 T, the filter works T per T (byteWidth = 1) # the incoming inputs do NOT include the filtertype T, 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 - TWidth].uint + template prevPix: untyped = output[i - byteWidth].uint case filterType of FLT_NONE: for i in 0.. 0: unfilterScanLine(output, input.toOpenArray(1, input.len-1), # skip the filterType - TWidth, lineTs, + byteWidth, lineTs, PNGFilter(input[0])) # next line start from 1 @@ -397,7 +397,7 @@ proc unfilter*[T](output: var openArray[T], input: openArray[T], w, h, bpp: int) unfilterScanLine(output.toOpenArray(outIndex, output.len-1), input.toOpenArray(inIndex + 1, input.len-1), # skip the filterType output.toOpenArray(prevIndex, output.len-1), # prevLine - TWidth, lineTs, filterType) + byteWidth, lineTs, filterType) prevIndex = outIndex proc readBitFromReversedStream*[T](bitptr: var int, bitstream: openArray[T]): int = @@ -501,12 +501,12 @@ proc adam7Deinterlace*[T](output: var openArray[T], input: openArray[T], w, h, b if bpp >= 8: for i in 0..6: - let TWidth = bpp div 8 + let byteWidth = bpp div 8 for y in 0..= 8: for i in 0..6: - let TWidth = bpp div 8 + let byteWidth = bpp div 8 for y in 0.. 512: #assertTrue(s.data.len < image.data.len, "compressed size") + #debugEcho "PNG LEN: ", s.getPosition() + #debugEcho "PNG DATA: ", s.data.toHex + s.setPosition 0 var decoded = s.decodePNG(image.colorType, image.bitDepth) + #debugEcho "DECODED LEN: ", decoded.data.len + #debugEcho "DECODED DATA: ", decoded.data.toHex + assertEquals(image.width, decoded.width) assertEquals(image.height, decoded.height) diff --git a/tests/test_nimz.nim b/tests/test_nimz.nim index 1b3c712..aca80d0 100644 --- a/tests/test_nimz.nim +++ b/tests/test_nimz.nim @@ -12,17 +12,20 @@ template check_roundtrip(source) = if uncomp != input: check false -suite "nimz": - check_roundtrip("alice29.txt") - check_roundtrip("house.jpg") - check_roundtrip("html") - check_roundtrip("urls.10K") - check_roundtrip("fireworks.jpeg") - check_roundtrip("paper-100k.pdf") - check_roundtrip("html_x_4") - check_roundtrip("asyoulik.txt") - check_roundtrip("lcet10.txt") - check_roundtrip("plrabn12.txt") - check_roundtrip("geo.protodata") - check_roundtrip("kppkn.gtb") - check_roundtrip("Mark.Twain-Tom.Sawyer.txt") +proc main() = + suite "nimz": + check_roundtrip("alice29.txt") + check_roundtrip("house.jpg") + check_roundtrip("html") + check_roundtrip("urls.10K") + check_roundtrip("fireworks.jpeg") + check_roundtrip("paper-100k.pdf") + check_roundtrip("html_x_4") + check_roundtrip("asyoulik.txt") + check_roundtrip("lcet10.txt") + check_roundtrip("plrabn12.txt") + check_roundtrip("geo.protodata") + check_roundtrip("kppkn.gtb") + check_roundtrip("Mark.Twain-Tom.Sawyer.txt") + +main()