import nimPNG, streams, math, strutils, tables, base64, os type Image = ref object data: string width, height: int colorType: PNGcolorType bitDepth: int 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, ". ", "Message: ", message quit() proc getNumColorChannels(colorType: PNGcolorType): int = case colorType of LCT_GREY: result = 1 of LCT_RGB: result = 3 of LCT_PALETTE: result = 1 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 result.height = height result.colorType = colorType result.bitDepth = bitDepth let bits = bitDepth * getNumColorChannels(colorType) let size = (width * height * bits + 7) div 8 result.data = newString(size) var value = 128 for i 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) var state = makePNGEncoder() state.interlaceMethod = IM_INTERLACED doCodecTest(image, state) #Test PNG encoding and decoding using some image generated with the given parameters proc codecTest(width, height: int, colorType = LCT_RGBA, bitDepth = 8) = echo "codec test ", width, " ", height var image = generateTestImage(width, height, colorType, bitDepth) image.doCodecTest() proc testOtherPattern1() = echo "codec other pattern 1" var image: Image new(image) let w = 192 let h = 192 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[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() = echo "codec other pattern 2" var image: Image new(image) let w = 192 let h = 192 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[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 pixel.bitDepth = 8 pixel.data = newString(4) pixel.data[0] = r.chr pixel.data[1] = g.chr pixel.data[2] = b.chr pixel.data[3] = a.chr doCodecTest(pixel) 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 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[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) var image3: Image new(image3) image3.width = image.width image3.height = image.height 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 image3.data[255 * 4 + 2] = 255.chr image3.data[255 * 4 + 3] = 255.chr doCodecTest(image3) testSinglePixel(r, g, b, a) 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() = codecTest(1, 1) codecTest(2, 2) codecTest(1, 1, LCT_GREY, 1) codecTest(7, 7, LCT_GREY, 1) codecTest(127, 127) codecTest(127, 127, LCT_GREY, 1) testOtherPattern1() testOtherPattern2() testColor(255, 255, 255, 255) testColor(0, 0, 0, 255) testColor(1, 2, 3, 255) testColor(255, 0, 0, 255) testColor(0, 255, 0, 255) testColor(0, 0, 255, 255) testColor(0, 0, 0, 255) testColor(1, 1, 1, 255) testColor(1, 1, 1, 1) testColor(0, 0, 0, 128) testColor(255, 0, 0, 128) testColor(127, 127, 127, 255) testColor(128, 128, 128, 255) testColor(127, 127, 127, 128) testColor(128, 128, 128, 128) #transparent single pixels testColor(0, 0, 0, 0) testColor(255, 0, 0, 0) 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: testSize(w, h) proc doPngSuiteTinyTest(b64: string, w, h, r, g, b, a: int) = var input = fromBase64(b64) var s = newStringStream(input) var decoded = s.decodePNG(LCT_RGBA, 8) assertEquals (w, decoded.width) assertEquals (h, decoded.height) assertEquals (r, decoded.data[0].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]) #checks that both png suite images have the exact same pixel content, e.g. to check that #it decodes an interlaced and non-interlaced corresponding png suite image equally proc doPngSuiteEqualTest(b64a, b64b: string) = var input1 = fromBase64(b64a) var s1 = newStringStream(input1) var decoded1 = s1.decodePNG(LCT_RGBA, 8) var input2 = fromBase64(b64b) var s2 = newStringStream(input2) var decoded2 = s2.decodePNG(LCT_RGBA, 8) assertEquals (decoded1.height, decoded2.height) assertEquals (decoded1.width, decoded2.width) let size = decoded1.height * decoded1.width * 4 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 testAutoColorModel(rgb_key4, 8, LCT_RGBA, 8, false) var grey1_key = grey1 grey1_key[7] = 0.chr testAutoColorModel(grey1_key, 8, LCT_GREY, 1, true) var grey2_key = grey2 grey2_key[7] = 0.chr testAutoColorModel(grey2_key, 8, LCT_GREY, 2, true) var grey4_key = grey4 grey4_key[7] = 0.chr testAutoColorModel(grey4_key, 8, LCT_GREY, 4, true) var grey8_key = grey8 grey8_key[7] = 0.chr testAutoColorModel(grey8_key, 8, LCT_GREY, 8, true) var small16 = "" addColor16(small16, 1, 0, 0, 65535) testAutoColorModel(small16, 16, LCT_RGB, 16, false) var small16a = "" addColor16(small16a, 1, 0, 0, 1) testAutoColorModel(small16a, 16, LCT_RGBA, 16, false) var not16 = "" addColor16(not16, 257, 257, 257, 0) testAutoColorModel(not16, 16, LCT_PALETTE, 1, false) 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() testPaletteFilterTypesZero() testComplexPNG() testPredefinedFilters() testColorKeyConvert() testColorConvert() testColorConvert2() testPaletteToPaletteConvert() testRGBToPaletteConvert() test16bitColorEndianness() testNoAutoConvert() testAutoColorModels() testFilter() doMain()