Add support for decoding images from a pointer and a length instead of a string (TODO: qoi, ppm)
Some checks failed
Github Actions / build (1.4.x, ubuntu-latest) (push) Has been cancelled
Github Actions / build (1.4.x, windows-latest) (push) Has been cancelled
Github Actions / build (stable, ubuntu-latest) (push) Has been cancelled
Github Actions / build (stable, windows-latest) (push) Has been cancelled
Some checks failed
Github Actions / build (1.4.x, ubuntu-latest) (push) Has been cancelled
Github Actions / build (1.4.x, windows-latest) (push) Has been cancelled
Github Actions / build (stable, ubuntu-latest) (push) Has been cancelled
Github Actions / build (stable, windows-latest) (push) Has been cancelled
This commit is contained in:
parent
89ac8dfbe6
commit
8458981007
|
@ -49,8 +49,39 @@ proc decodeImageDimensions*(
|
||||||
## Decodes an image's dimensions from memory.
|
## Decodes an image's dimensions from memory.
|
||||||
decodeImageDimensions(data.cstring, data.len)
|
decodeImageDimensions(data.cstring, data.len)
|
||||||
|
|
||||||
|
template compare_as(T: typedesc, p,q: pointer): bool =
|
||||||
|
cast[ptr T](p)[] == cast[ptr T](q)[]
|
||||||
|
|
||||||
|
proc decodeImage*(data: pointer, len: int): Image {.raises: [PixieError].} =
|
||||||
|
## Loads an image from memory, from a pointer and a length.
|
||||||
|
if len > 8 and compare_as(uint64, data, pngSignature.addr):
|
||||||
|
decodePng(data, len).convertToImage()
|
||||||
|
elif len > 2 and compare_as(uint16, data, jpegStartOfImage.addr):
|
||||||
|
decodeJpeg(data, len)
|
||||||
|
elif len > 2 and compare_as(array[2,char], data, bmpSignature.cstring):
|
||||||
|
decodeBmp(data, len)
|
||||||
|
elif len > 5 and
|
||||||
|
compare_as(array[5,char], data, xmlSignature.cstring) or
|
||||||
|
compare_as(array[4,char], data, svgSignature.cstring):
|
||||||
|
# TODO: avoid allocating/initializing string
|
||||||
|
var s = newStringOfCap(len)
|
||||||
|
s.setLen len
|
||||||
|
copyMem(s.cstring, data, len)
|
||||||
|
newImage(parseSvg(s))
|
||||||
|
elif len > 6 and compare_as(array[6,char], data, gifSignatures[0].cstring) or
|
||||||
|
compare_as(array[6,char], data, gifSignatures[1].cstring):
|
||||||
|
newImage(decodeGif(data, len))
|
||||||
|
# TODO
|
||||||
|
# elif len > (14+8) and compare_as(array[4,char], data, qoiSignature.cstring):
|
||||||
|
# decodeQoi(data, len).convertToImage()
|
||||||
|
# elif len > 9 and compare_as(array[2,char], data, ppmSignatures[0].cstring) or
|
||||||
|
# compare_as(array[2,char], data, ppmSignatures[1].cstring):
|
||||||
|
# decodePpm(data, len)
|
||||||
|
else:
|
||||||
|
raise newException(PixieError, "Unsupported image file format")
|
||||||
|
|
||||||
proc decodeImage*(data: string): Image {.raises: [PixieError].} =
|
proc decodeImage*(data: string): Image {.raises: [PixieError].} =
|
||||||
## Loads an image from memory.
|
## Loads an image from memory as a string.
|
||||||
if data.len > 8 and data.readUint64(0) == cast[uint64](pngSignature):
|
if data.len > 8 and data.readUint64(0) == cast[uint64](pngSignature):
|
||||||
decodePng(data).convertToImage()
|
decodePng(data).convertToImage()
|
||||||
elif data.len > 2 and data.readUint16(0) == cast[uint16](jpegStartOfImage):
|
elif data.len > 2 and data.readUint16(0) == cast[uint16](jpegStartOfImage):
|
||||||
|
|
|
@ -227,6 +227,17 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
|
|
||||||
decodeDib(data[14].unsafeAddr, data.len - 14)
|
decodeDib(data[14].unsafeAddr, data.len - 14)
|
||||||
|
|
||||||
|
proc decodeBmp*(data: pointer, len: int): Image {.raises: [PixieError].} =
|
||||||
|
## Decodes bitmap data into an image.
|
||||||
|
if len < 14:
|
||||||
|
failInvalid()
|
||||||
|
|
||||||
|
# BMP Header
|
||||||
|
if cast[ptr int16](data)[] != cast[ptr int16]("BM".cstring)[]:
|
||||||
|
failInvalid()
|
||||||
|
|
||||||
|
decodeDib(cast[ptr UncheckedArray[char]](data)[14].addr, len - 14)
|
||||||
|
|
||||||
proc decodeBmpDimensions*(
|
proc decodeBmpDimensions*(
|
||||||
data: pointer, len: int
|
data: pointer, len: int
|
||||||
): ImageDimensions {.raises: [PixieError].} =
|
): ImageDimensions {.raises: [PixieError].} =
|
||||||
|
|
|
@ -22,12 +22,18 @@ template failInvalid() =
|
||||||
when defined(release):
|
when defined(release):
|
||||||
{.push checks: off.}
|
{.push checks: off.}
|
||||||
|
|
||||||
proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
template compare_as(T: typedesc, p,q: pointer): bool =
|
||||||
|
cast[ptr T](p)[] == cast[ptr T](q)[]
|
||||||
|
|
||||||
|
proc decodeGif*(data: pointer, len: int): Gif {.raises: [PixieError].} =
|
||||||
|
let data = cast[ptr UncheckedArray[uint8]](data)
|
||||||
## Decodes GIF data.
|
## Decodes GIF data.
|
||||||
if data.len < 13:
|
if len < 13:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
if data[0 .. 5] notin gifSignatures:
|
if not (len > 6 and
|
||||||
|
compare_as(array[6,char], data, gifSignatures[0].cstring) or
|
||||||
|
compare_as(array[6,char], data, gifSignatures[1].cstring)):
|
||||||
raise newException(PixieError, "Invalid GIF file signature")
|
raise newException(PixieError, "Invalid GIF file signature")
|
||||||
|
|
||||||
result = Gif()
|
result = Gif()
|
||||||
|
@ -49,7 +55,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
|
|
||||||
var pos = 13
|
var pos = 13
|
||||||
|
|
||||||
if pos + globalColorTableSize * 3 > data.len:
|
if pos + globalColorTableSize * 3 > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
var
|
var
|
||||||
|
@ -69,7 +75,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
|
|
||||||
proc skipSubBlocks() =
|
proc skipSubBlocks() =
|
||||||
while true: # Skip data sub-blocks
|
while true: # Skip data sub-blocks
|
||||||
if pos + 1 > data.len:
|
if pos + 1 > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
let subBlockSize = data.readUint8(pos).int
|
let subBlockSize = data.readUint8(pos).int
|
||||||
|
@ -82,7 +88,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
|
|
||||||
var controlExtension: ControlExtension
|
var controlExtension: ControlExtension
|
||||||
while true:
|
while true:
|
||||||
if pos + 1 > data.len:
|
if pos + 1 > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
let blockType = data.readUint8(pos)
|
let blockType = data.readUint8(pos)
|
||||||
|
@ -90,7 +96,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
|
|
||||||
case blockType:
|
case blockType:
|
||||||
of 0x2c: # Image
|
of 0x2c: # Image
|
||||||
if pos + 9 > data.len:
|
if pos + 9 > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
let
|
let
|
||||||
|
@ -108,7 +114,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
if imageWidth > screenWidth or imageHeight > screenHeight:
|
if imageWidth > screenWidth or imageHeight > screenHeight:
|
||||||
raise newException(PixieError, "Invalid GIF frame dimensions")
|
raise newException(PixieError, "Invalid GIF frame dimensions")
|
||||||
|
|
||||||
if pos + localColorTableSize * 3 > data.len:
|
if pos + localColorTableSize * 3 > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
var localColorTable: seq[ColorRGBX]
|
var localColorTable: seq[ColorRGBX]
|
||||||
|
@ -123,7 +129,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
)
|
)
|
||||||
pos += 3
|
pos += 3
|
||||||
|
|
||||||
if pos + 1 > data.len:
|
if pos + 1 > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
let minCodeSize = data.readUint8(pos).int
|
let minCodeSize = data.readUint8(pos).int
|
||||||
|
@ -135,7 +141,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
# The image data is contained in a sequence of sub-blocks
|
# The image data is contained in a sequence of sub-blocks
|
||||||
var lzwDataBlocks: seq[(int, int)] # (offset, len)
|
var lzwDataBlocks: seq[(int, int)] # (offset, len)
|
||||||
while true:
|
while true:
|
||||||
if pos + 1 > data.len:
|
if pos + 1 > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
let subBlockSize = data.readUint8(pos).int
|
let subBlockSize = data.readUint8(pos).int
|
||||||
|
@ -144,7 +150,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
if subBlockSize == 0:
|
if subBlockSize == 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
if pos + subBlockSize > data.len:
|
if pos + subBlockSize > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
lzwDataBlocks.add((pos, subBlockSize))
|
lzwDataBlocks.add((pos, subBlockSize))
|
||||||
|
@ -307,7 +313,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
controlExtension = ControlExtension()
|
controlExtension = ControlExtension()
|
||||||
|
|
||||||
of 0x21: # Extension
|
of 0x21: # Extension
|
||||||
if pos + 1 > data.len:
|
if pos + 1 > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
let extensionType = data.readUint8(pos + 0)
|
let extensionType = data.readUint8(pos + 0)
|
||||||
|
@ -316,7 +322,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
case extensionType:
|
case extensionType:
|
||||||
of 0xf9:
|
of 0xf9:
|
||||||
# Graphic Control Extension
|
# Graphic Control Extension
|
||||||
if pos + 1 > data.len:
|
if pos + 1 > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
let blockSize = data.readUint8(pos).int
|
let blockSize = data.readUint8(pos).int
|
||||||
|
@ -325,7 +331,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
if blockSize != 4:
|
if blockSize != 4:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
if pos + blockSize > data.len:
|
if pos + blockSize > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
controlExtension.fields = data.readUint8(pos + 0)
|
controlExtension.fields = data.readUint8(pos + 0)
|
||||||
|
@ -344,7 +350,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
|
|
||||||
of 0xff:
|
of 0xff:
|
||||||
# Application Specific
|
# Application Specific
|
||||||
if pos + 1 > data.len:
|
if pos + 1 > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
let blockSize = data.readUint8(pos).int
|
let blockSize = data.readUint8(pos).int
|
||||||
|
@ -353,7 +359,7 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
if blockSize != 11:
|
if blockSize != 11:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
if pos + blockSize > data.len:
|
if pos + blockSize > len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
pos += blockSize
|
pos += blockSize
|
||||||
|
@ -378,6 +384,9 @@ proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
for interval in result.intervals:
|
for interval in result.intervals:
|
||||||
result.duration += interval
|
result.duration += interval
|
||||||
|
|
||||||
|
proc decodeGif*(data: string): Gif {.raises: [PixieError].} =
|
||||||
|
return decodeGif(data.cstring, data.len)
|
||||||
|
|
||||||
proc decodeGifDimensions*(
|
proc decodeGifDimensions*(
|
||||||
data: pointer, len: int
|
data: pointer, len: int
|
||||||
): ImageDimensions {.raises: [PixieError].} =
|
): ImageDimensions {.raises: [PixieError].} =
|
||||||
|
|
|
@ -1092,12 +1092,12 @@ proc buildImage(state: var DecoderState): Image =
|
||||||
else:
|
else:
|
||||||
failInvalid("invalid orientation")
|
failInvalid("invalid orientation")
|
||||||
|
|
||||||
proc decodeJpeg*(data: string): Image {.raises: [PixieError].} =
|
proc decodeJpeg*(data: pointer, len: int): Image {.raises: [PixieError].} =
|
||||||
## Decodes the JPEG into an Image.
|
## Decodes the JPEG into an Image.
|
||||||
|
|
||||||
var state = DecoderState()
|
var state = DecoderState()
|
||||||
state.buffer = cast[ptr UncheckedArray[uint8]](data.cstring)
|
state.buffer = cast[ptr UncheckedArray[uint8]](data)
|
||||||
state.len = data.len
|
state.len = len
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
if state.readUint8() != 0xFF:
|
if state.readUint8() != 0xFF:
|
||||||
|
@ -1157,6 +1157,10 @@ proc decodeJpeg*(data: string): Image {.raises: [PixieError].} =
|
||||||
|
|
||||||
state.buildImage()
|
state.buildImage()
|
||||||
|
|
||||||
|
proc decodeJpeg*(data: string): Image {.raises: [PixieError].} =
|
||||||
|
## Decodes the JPEG into an Image.
|
||||||
|
decodeJpeg(data.cstring, data.len)
|
||||||
|
|
||||||
proc decodeJpegDimensions*(
|
proc decodeJpegDimensions*(
|
||||||
data: pointer, len: int
|
data: pointer, len: int
|
||||||
): ImageDimensions {.raises: [PixieError].} =
|
): ImageDimensions {.raises: [PixieError].} =
|
||||||
|
|
Loading…
Reference in a new issue