diff --git a/.gitignore b/.gitignore index a89cde7..31b4a0b 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,5 @@ Temporary Items *.exe nimcache -bug \ No newline at end of file +bug +tester/temp.png \ No newline at end of file diff --git a/nimPNG.nim b/nimPNG.nim index 1f92d40..85d23e7 100644 --- a/nimPNG.nim +++ b/nimPNG.nim @@ -2412,7 +2412,7 @@ proc filterScanLine(output: var cstring, scanLine, prevLine: cstring, len, byteW for i in byteWidth..len-1: output[i] = chr(scanLine[i].uint - scanLine[i - byteWidth].uint) else: - raise PNGError("unsupported fitler type") + raise PNGError("unsupported filter type") proc filterZero(output: var cstring, input: cstring, w, h, bpp: int) = #the width of a scanline in bytes, not including the filter type diff --git a/testCodec.nim b/testCodec.nim index c02d697..c156f93 100644 --- a/testCodec.nim +++ b/testCodec.nim @@ -1,4 +1,4 @@ -import nimPNG, streams, math, strutils, tables, base64 +import nimPNG, streams, math, strutils, tables, base64, os type Image = ref object @@ -9,7 +9,7 @@ type proc fromBase64(input: string): string = result = base64.decode(input) - + proc assertEquals[T, U](expected: T, actual: U, message = "") = if expected != actual: echo "Error: Not equal! Expected ", expected, " got ", actual, ". ", @@ -24,7 +24,7 @@ proc getNumColorChannels(colorType: PNGcolorType): int = of LCT_GREY_ALPHA: result = 2 of LCT_RGBA: result = 4 else: result = 0 - + proc generateTestImage(width, height: int, colorType = LCT_RGBA, bitDepth = 8): Image = new(result) result.width = width @@ -55,7 +55,7 @@ proc assertPixels(image: Image, decoded: string, message: string) = for j in 0.. 512: #assertTrue(s.data.len < image.data.len, "compressed size") - + s.setPosition 0 var decoded = s.decodePNG(image.colorType, image.bitDepth) assertEquals(image.width, decoded.width) assertEquals(image.height, decoded.height) - + if state == nil: assertPixels(image, decoded.data, "Pixels") else: assertPixels(image, decoded.data, "Pixels Interlaced") - + #Test PNG encoding and decoding the encoded result proc doCodecTest(image: Image) = doCodecTest(image, nil) @@ -97,7 +97,7 @@ proc testOtherPattern1() = var image: Image new(image) - + let w = 192 let h = 192 image.width = w @@ -105,14 +105,14 @@ proc testOtherPattern1() = image.colorType = LCT_RGBA image.bitDepth = 8 image.data = newString(w * h * 4) - + for y in 0..h-1: for x in 0..w-1: image.data[4 * w * y + 4 * x + 0] = chr(int(127 * (1 + math.sin(float( x * x + y * y) / (float(w * h) / 8.0))))) image.data[4 * w * y + 4 * x + 1] = chr(int(127 * (1 + math.sin(float((w - x - 1) * (w - x - 1) + y * y) / (float(w * h) / 8.0))))) image.data[4 * w * y + 4 * x + 2] = chr(int(127 * (1 + math.sin(float( x * x + (h - y - 1) * (h - y - 1)) / (float(w * h) / 8.0))))) image.data[4 * w * y + 4 * x + 3] = chr(int(127 * (1 + math.sin(float((w - x - 1) * (w - x - 1) + (h - y - 1) * (h - y - 1)) / (float(w * h) / 8.0))))) - + doCodecTest(image) proc testOtherPattern2() = @@ -120,7 +120,7 @@ proc testOtherPattern2() = var image: Image new(image) - + let w = 192 let h = 192 image.width = w @@ -128,21 +128,21 @@ proc testOtherPattern2() = image.colorType = LCT_RGBA image.bitDepth = 8 image.data = newString(w * h * 4) - + for y in 0..h-1: for x in 0..w-1: image.data[4 * w * y + 4 * x + 0] = chr(255 * not (x and y) and 0xFF) image.data[4 * w * y + 4 * x + 1] = chr((x xor y) and 0xFF) image.data[4 * w * y + 4 * x + 2] = chr((x or y) and 0xFF) image.data[4 * w * y + 4 * x + 3] = chr(255) - + doCodecTest(image) proc testSinglePixel(r, g, b, a: int) = echo "codec single pixel " , r , " " , g , " " , b , " " , a var pixel: Image new(pixel) - + pixel.width = 1 pixel.height = 1 pixel.colorType = LCT_RGBA @@ -159,7 +159,7 @@ proc testColor(r, g, b, a: int) = echo "codec test color ", r , " " , g , " " , b , " " , a var image: Image new(image) - + let w = 20 let h = 20 image.width = w @@ -167,19 +167,19 @@ proc testColor(r, g, b, a: int) = image.colorType = LCT_RGBA image.bitDepth = 8 image.data = newString(w * h * 4) - + for y in 0..h-1: for x in 0..w-1: image.data[20 * 4 * y + 4 * x + 0] = r.chr image.data[20 * 4 * y + 4 * x + 0] = g.chr image.data[20 * 4 * y + 4 * x + 0] = b.chr image.data[20 * 4 * y + 4 * x + 0] = a.chr - + doCodecTest(image) image.data[3] = 0.chr #one fully transparent pixel doCodecTest(image) - + image.data[3] = 128.chr #one semi transparent pixel doCodecTest(image) @@ -190,16 +190,16 @@ proc testColor(r, g, b, a: int) = image3.colorType = image.colorType image3.bitDepth = image.bitDepth image3.data = image.data - + #add 255 different colors for i in 0..254: image.data[i * 4 + 0] = i.chr image.data[i * 4 + 1] = i.chr image.data[i * 4 + 2] = i.chr image.data[i * 4 + 3] = 255.chr - + doCodecTest(image3) - + #a 256th color image3.data[255 * 4 + 0] = 255.chr image3.data[255 * 4 + 1] = 255.chr @@ -214,20 +214,20 @@ proc testSize(w, h: int) = echo "codec test size ", w, " ", h var image: Image new(image) - + image.width = w image.height = h image.colorType = LCT_RGBA image.bitDepth = 8 image.data = newString(w * h * 4) - + for y in 0..h-1: for x in 0..w-1: image.data[w * 4 * y + 4 * x + 0] = (x mod 256).chr image.data[w * 4 * y + 4 * x + 0] = (y mod 256).chr image.data[w * 4 * y + 4 * x + 0] = 255.chr image.data[w * 4 * y + 4 * x + 0] = 255.chr - + doCodecTest(image) proc testPNGCodec() = @@ -261,7 +261,7 @@ proc testPNGCodec() = testColor(1, 2, 3, 0) testColor(255, 255, 255, 0) testColor(254, 254, 254, 0) - + #This is mainly to test the Adam7 interlacing for h in 1..11: for w in 1..12: @@ -278,14 +278,14 @@ proc doPngSuiteTinyTest(b64: string, w, h, r, g, b, a: int) = assertEquals (g, decoded.data[1].int) assertEquals (b, decoded.data[2].int) assertEquals (a, decoded.data[3].int) - + var state = makePNGEncoder() state.autoConvert = false var png = encodePNG(decoded.data, LCT_RGBA, 8, w, h, state) s = newStringStream() png.writeChunks s s.setPosition 0 - + var decoded2 = s.decodePNG(LCT_RGBA, 8) for i in 0..decoded.data.high: assertEquals(decoded.data[i], decoded2.data[i]) @@ -309,7 +309,7 @@ proc doPngSuiteEqualTest(b64a, b64b: string) = if decoded1.data[i] != decoded2.data[i]: echo "x: ", ((i div 4) mod decoded1.width), " y: ", ((i div 4) mod decoded1.width), " c: ", i mod 4 assertEquals(decoded1.data[i], decoded2.data[i]) - + proc testPngSuiteTiny() = echo "testPngSuiteTiny" @@ -351,7 +351,7 @@ proc testPngSuiteTiny() = "BAQEd/i1owAAAANQTFRFAAD/injSVwAAAApJREFUeJxjYAAAAAIAAUivpHEAAAAASUVORK5CYII=", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABGdBTUEAAYagMeiWXwAAAANzQklU" & "BAQEd/i1owAAAANQTFRFAAD/injSVwAAAApJREFUeJxjYAAAAAIAAUivpHEAAAAASUVORK5CYII=") - + #s07n3p02.png and s07i3p02.png doPngSuiteEqualTest("iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHAgMAAAC5PL9AAAAABGdBTUEAAYagMeiWXwAAAANzQklU" & "BAQEd/i1owAAAAxQTFRF/wB3AP93//8AAAD/G0OznAAAABpJREFUeJxj+P+H4WoMw605DDfmgEgg" & @@ -359,7 +359,7 @@ proc testPngSuiteTiny() = "iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHAgMAAAHOO4/WAAAABGdBTUEAAYagMeiWXwAAAANzQklU" & "BAQEd/i1owAAAAxQTFRF/wB3AP93//8AAAD/G0OznAAAACVJREFUeJxjOMBwgOEBwweGDQyvGf4z" & "/GFIAcI/DFdjGG7MAZIAweMMgVWC+YkAAAAASUVORK5CYII=") - + #basn0g16.png and basi0g16.png doPngSuiteEqualTest("iVBORw0KGgoAAAANSUhEUgAAACAAAAAgEAAAAAAGgflrAAAABGdBTUEAAYagMeiWXwAAAF5JREFU" & "eJzV0jEKwDAMQ1E5W+9/xtygk8AoezLVKgSj2Y8/OICnuFcTE2OgOoJgHQiZAN2C9kDKBOgW3AZC" & @@ -375,24 +375,24 @@ proc testPngSuiteTiny() = #Create a PNG image with all known chunks (except only one of tEXt or zTXt) plus #unknown chunks, and a palette. proc createComplexPNG(): string = - let + let w = 16 h = 17 - + var image = newString(w * h) for i in 0..image.high: image[i] = chr(i mod 256) - + var state = makePNGEncoder() state.modeIn.colorType = LCT_PALETTE state.modeIn.bitDepth = 8 state.modeOut.colorType = LCT_PALETTE state.modeOut.bitDepth = 8 - + state.autoConvert = false state.textCompression = true state.addID = true - + for i in 0..255: state.modeIn.addPalette(i, i, i ,i) state.modeOut.addPalette(i, i, i ,i) @@ -413,16 +413,16 @@ proc createComplexPNG(): string = state.hour = 3 state.minute = 4 state.second = 5 - + state.physDefined = true state.physX = 1 state.physY = 2 state.physUnit = 1 - + state.addUnknownChunk("uNKa", "a01") state.addUnknownChunk("uNKb", "b00") state.addUnknownChunk("uNKc", "c00") - + var png = encodePNG(image, w, h, state) var s = newStringStream() png.writeChunks s @@ -437,21 +437,21 @@ proc testPaletteFilterTypesZero() = var filterTypes = png.getFilterTypes() assertEquals(17, filterTypes.len) - for i in 0..16: + for i in 0..16: assertEquals(0.chr, filterTypes[i]) proc testComplexPNG() = echo "testComplexPNG" var raw = createComplexPNG() - + var s = newStringStream(raw) var state = makePNGDecoder() state.readTextChunks = true state.rememberUnknownChunks = true - + var png = s.decodePNG(state) var info = png.getInfo() - + assertEquals (16, info.width) assertEquals (17, info.height) assertEquals (true, info.backgroundDefined) @@ -467,7 +467,7 @@ proc testComplexPNG() = assertEquals (1 , info.physX) assertEquals (2 , info.physY) assertEquals (1 , info.physUnit) - + let chunkNames = png.getChunkNames() let expectedNames = "IHDR uNKa PLTE tRNS bKGD pHYs uNKb IDAT tIME zTXt zTXt tEXt iTXt iTXt uNKc IEND" assertEquals (expectedNames, chunkNames) @@ -478,27 +478,27 @@ proc testPredefinedFilters() = let w = 32 h = 32 - + echo "testPredefinedFilters" var image = generateTestImage(w, h, LCT_RGBA, 8) - + var state = makePNGEncoder() state.filterStrategy = LFS_PREDEFINED state.filterPaletteZero = false state.predefinedFilters = repeat(chr(3), h) #everything to filter type '3' var png = encodePNG(image.data, w, h, state) var outFilters = png.getFilterTypes() - + assertEquals(h, outFilters.len) for i in 0.. no more key testAutoColorModel(rgb_key2, 8, LCT_RGBA, 8, false) - + var rgb_key3 = rgb_key addColor(rgb_key3, 128, 0, 0, 255) #semi-translucent ==> no more key testAutoColorModel(rgb_key3, 8, LCT_RGBA, 8, false) - + var rgb_key4 = rgb_key addColor(rgb_key4, 128, 0, 0, 255) addColor(rgb_key4, 129, 0, 0, 255) #two different transparent colors ==> no more key @@ -978,7 +978,18 @@ proc testAutoColorModels() = var alpha16 = "" addColor16(alpha16, 257, 0, 0, 10000) testAutoColorModel(alpha16, 16, LCT_RGBA, 16, false) - + +proc testFilter() = + echo "test Filter" + let input = "tester" & DirSep & "tfilter.png" + let temp = "tester" & DirSep & "temp.png" + let png = loadPNG32(input) + discard savePNG32(temp, png.data, png.width, png.height) + let png2 = loadPNG32(temp) + if png.data != png2.data: + echo "testFilter failed" + quit() + proc doMain() = testPNGCodec() testPngSuiteTiny() @@ -990,8 +1001,9 @@ proc doMain() = testColorConvert2() testPaletteToPaletteConvert() testRGBToPaletteConvert() - test16bitColorEndianness(); - testNoAutoConvert(); - testAutoColorModels(); + test16bitColorEndianness() + testNoAutoConvert() + testAutoColorModels() + testFilter() doMain() diff --git a/tester/tfilter.png b/tester/tfilter.png new file mode 100644 index 0000000..4887efe Binary files /dev/null and b/tester/tfilter.png differ