From 7739e5988e4915eb2148c0e940029f951e471a98 Mon Sep 17 00:00:00 2001 From: Ryan Oldenburg Date: Thu, 9 Jun 2022 01:55:01 -0500 Subject: [PATCH 1/3] update flatty dep --- pixie.nimble | 3 +-- src/pixie/fileformats/png.nim | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/pixie.nimble b/pixie.nimble index fa8ec21..d3d2114 100644 --- a/pixie.nimble +++ b/pixie.nimble @@ -9,11 +9,10 @@ requires "nim >= 1.4.8" requires "vmath >= 1.1.4" requires "chroma >= 0.2.5" requires "zippy >= 0.9.11" -requires "flatty >= 0.3.3" +requires "flatty >= 0.3.4" requires "nimsimd >= 1.0.0" requires "bumpy >= 1.1.1" - task bindings, "Generate bindings": proc compile(libName: string, flags = "") = diff --git a/src/pixie/fileformats/png.nim b/src/pixie/fileformats/png.nim index eb2abc9..2091675 100644 --- a/src/pixie/fileformats/png.nim +++ b/src/pixie/fileformats/png.nim @@ -268,7 +268,6 @@ proc decodeImageData( result[i].a = 0 else: # While we can read an extra byte safely, do so. Much faster. - # var rgba: ColorRGBA for i in 0 ..< header.height * header.width - 1: copyMem(result[i].addr, unfiltered[i * 3].unsafeAddr, 4) result[i].a = 255 From 7ce724c0fd1b745687f4b98c318fd5ea4bc16b7f Mon Sep 17 00:00:00 2001 From: Ryan Oldenburg Date: Thu, 9 Jun 2022 12:46:58 -0500 Subject: [PATCH 2/3] fix docs --- src/pixie.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pixie.nim b/src/pixie.nim index 2b31dfb..3b8c5dd 100644 --- a/src/pixie.nim +++ b/src/pixie.nim @@ -67,7 +67,7 @@ proc decodeMask*(data: string): Mask {.raises: [PixieError].} = proc readImageDimensions*( filePath: string ): ImageDimensions {.inline, raises: [PixieError].} = - ## Loads an image from a file. + ## Decodes an image's dimensions from a file. try: decodeImageDimensions(readFile(filePath)) except IOError as e: From 58a7e3bcd0fe04c1da1d995231584f9a5c88345c Mon Sep 17 00:00:00 2001 From: Ryan Oldenburg Date: Thu, 9 Jun 2022 18:04:37 -0500 Subject: [PATCH 3/3] decode png has ptr+len proc --- src/pixie/fileformats/png.nim | 56 ++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/pixie/fileformats/png.nim b/src/pixie/fileformats/png.nim index 2091675..79e3a14 100644 --- a/src/pixie/fileformats/png.nim +++ b/src/pixie/fileformats/png.nim @@ -27,7 +27,8 @@ template failInvalid() = when defined(release): {.push checks: off.} -proc decodeHeader(data: string): PngHeader = +proc decodeHeader(data: pointer): PngHeader = + let data = cast[ptr UncheckedArray[uint8]](data) result.width = data.readUint32(0).swap().int result.height = data.readUint32(4).swap().int result.bitDepth = data.readUint8(8) @@ -78,18 +79,19 @@ proc decodeHeader(data: string): PngHeader = # Not yet supported: if result.bitDepth == 16: - raise newException(PixieError, "PNG 16 bit depth not yet supported") + raise newException(PixieError, "PNG 16 bit depth not supported yet") if result.interlaceMethod != 0: - raise newException(PixieError, "Interlaced PNG not yet supported") + raise newException(PixieError, "Interlaced PNG not supported yet") -proc decodePalette(data: string): seq[ColorRGB] = - if data.len == 0 or data.len mod 3 != 0: +proc decodePalette(data: pointer, len: int): seq[ColorRGB] = + if len == 0 or len mod 3 != 0: failInvalid() - result.setLen(data.len div 3) + result.setLen(len div 3) - for i in 0 ..< data.len div 3: + let data = cast[ptr UncheckedArray[uint8]](data) + for i in 0 ..< len div 3: copyMem(result[i].addr, data[i * 3].unsafeAddr, 3) proc unfilter( @@ -165,7 +167,7 @@ proc unfilter( discard # Not possible, parseHeader validates proc decodeImageData( - data: string, + data: ptr UncheckedArray[uint8], header: PngHeader, palette: seq[ColorRGB], transparency: string, @@ -183,7 +185,7 @@ proc decodeImageData( for (start, len) in idats: let op = imageData.len imageData.setLen(imageData.len + len) - copyMem(imageData[op].addr, data[start].unsafeAddr, len) + copyMem(imageData[op].addr, data[start].addr, len) try: uncompress(imageData) except ZippyError: failInvalid() else: let @@ -341,12 +343,14 @@ proc newImage*(png: Png): Image {.raises: [PixieError].} = result.data.toPremultipliedAlpha() proc decodePngDimensions*( - data: string + data: pointer, len: int ): ImageDimensions {.raises: [PixieError].} = ## Decodes the PNG dimensions. - if data.len < (8 + (8 + 13 + 4) + 4): # Magic bytes + IHDR + IEND + if len < (8 + (8 + 13 + 4) + 4): # Magic bytes + IHDR + IEND failInvalid() + let data = cast[ptr UncheckedArray[uint8]](data) + # PNG file signature let signature = cast[array[8, uint8]](data.readUint64(0)) if signature != pngSignature: @@ -356,15 +360,23 @@ proc decodePngDimensions*( if data.readUint32(8).swap() != 13 or data.readStr(12, 4) != "IHDR": failInvalid() - let header = decodeHeader(data[16 ..< 16 + 13]) + let header = decodeHeader(data[16].addr) result.width = header.width result.height = header.height -proc decodePng*(data: string): Png {.raises: [PixieError].} = +proc decodePngDimensions*( + data: string +): ImageDimensions {.inline, raises: [PixieError].} = + ## Decodes the PNG dimensions. + decodePngDimensions(data.cstring, data.len) + +proc decodePng*(data: pointer, len: int): Png {.raises: [PixieError].} = ## Decodes the PNG data. - if data.len < (8 + (8 + 13 + 4) + 4): # Magic bytes + IHDR + IEND + if len < (8 + (8 + 13 + 4) + 4): # Magic bytes + IHDR + IEND failInvalid() + let data = cast[ptr UncheckedArray[uint8]](data) + # PNG file signature let signature = cast[array[8, uint8]](data.readUint64(0)) if signature != pngSignature: @@ -384,7 +396,7 @@ proc decodePng*(data: string): Png {.raises: [PixieError].} = data.readStr(pos + 4, 4) != "IHDR": failInvalid() inc(pos, 8) - header = decodeHeader(data[pos ..< pos + 13]) + header = decodeHeader(data[pos].addr) prevChunkType = "IHDR" inc(pos, 13) @@ -393,7 +405,7 @@ proc decodePng*(data: string): Png {.raises: [PixieError].} = inc(pos, 4) # CRC while true: - if pos + 8 > data.len: + if pos + 8 > len: failInvalid() let @@ -404,7 +416,7 @@ proc decodePng*(data: string): Png {.raises: [PixieError].} = if chunkLen > high(int32).int: failInvalid() - if pos + chunkLen + 4 > data.len: + if pos + chunkLen + 4 > len: failInvalid() case chunkType: @@ -414,12 +426,12 @@ proc decodePng*(data: string): Png {.raises: [PixieError].} = inc counts.PLTE if counts.PLTE > 1 or counts.IDAT > 0 or counts.tRNS > 0: failInvalid() - palette = decodePalette(data[pos ..< pos + chunkLen]) + palette = decodePalette(data[pos].addr, chunkLen) of "tRNS": inc counts.tRNS if counts.tRNS > 1 or counts.IDAT > 0: failInvalid() - transparency = data[pos ..< pos + chunkLen] + transparency = data.readStr(pos, chunkLen) case header.colorType: of 0: if transparency.len != 2: @@ -456,7 +468,7 @@ proc decodePng*(data: string): Png {.raises: [PixieError].} = prevChunkType = chunkType - if pos == data.len or prevChunkType == "IEND": + if pos == len or prevChunkType == "IEND": break if prevChunkType != "IEND": @@ -468,6 +480,10 @@ proc decodePng*(data: string): Png {.raises: [PixieError].} = result.channels = 4 result.data = decodeImageData(data, header, palette, transparency, idats) +proc decodePng*(data: string): Png {.inline, raises: [PixieError].} = + ## Decodes the PNG data. + decodePng(data.cstring, data.len) + proc encodePng*( width, height, channels: int, data: pointer, len: int ): string {.raises: [PixieError].} =