decode png has ptr+len proc
This commit is contained in:
parent
7ce724c0fd
commit
58a7e3bcd0
1 changed files with 36 additions and 20 deletions
|
@ -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].} =
|
||||
|
|
Loading…
Reference in a new issue