invalid
This commit is contained in:
parent
ccccd883bb
commit
97515a3849
1 changed files with 18 additions and 15 deletions
|
@ -5,6 +5,9 @@ import bitops, chroma, flatty/binny, pixie/common, pixie/images
|
||||||
|
|
||||||
const bmpSignature* = "BM"
|
const bmpSignature* = "BM"
|
||||||
|
|
||||||
|
template failInvalid() =
|
||||||
|
raise newException(PixieError, "Invalid BMP buffer, unable to load")
|
||||||
|
|
||||||
proc colorMaskShift(color: uint32, mask: uint32): uint8 =
|
proc colorMaskShift(color: uint32, mask: uint32): uint8 =
|
||||||
((color and mask) shr (mask.firstSetBit() - 1)).uint8
|
((color and mask) shr (mask.firstSetBit() - 1)).uint8
|
||||||
|
|
||||||
|
@ -12,11 +15,11 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
## Decodes bitmap data into an Image.
|
## Decodes bitmap data into an Image.
|
||||||
|
|
||||||
if data.len < 48:
|
if data.len < 48:
|
||||||
raise newException(PixieError, "Invalid BMP data")
|
failInvalid()
|
||||||
|
|
||||||
# BMP Header
|
# BMP Header
|
||||||
if data[0 .. 1] != "BM":
|
if data[0 .. 1] != "BM":
|
||||||
raise newException(PixieError, "Invalid BMP data")
|
failInvalid()
|
||||||
|
|
||||||
let
|
let
|
||||||
bits = data.readUint16(28).int
|
bits = data.readUint16(28).int
|
||||||
|
@ -36,16 +39,16 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
flipVertical = false
|
flipVertical = false
|
||||||
|
|
||||||
if numColors < 0 or numColors > 256:
|
if numColors < 0 or numColors > 256:
|
||||||
raise newException(PixieError, "Invalid number of colors")
|
failInvalid()
|
||||||
if dibHeader notin [40, 108]:
|
if dibHeader notin [40, 108]:
|
||||||
raise newException(PixieError, "Invalid BMP data")
|
failInvalid()
|
||||||
|
|
||||||
var
|
var
|
||||||
colorTable = newSeq[ColorRGBA](numColors)
|
colorTable = newSeq[ColorRGBA](numColors)
|
||||||
|
|
||||||
if dibHeader == 108:
|
if dibHeader == 108:
|
||||||
if data.len < 14 + dibHeader:
|
if data.len < 14 + dibHeader:
|
||||||
raise newException(PixieError, "Invalid BMP data")
|
failInvalid()
|
||||||
|
|
||||||
redChannel = data.readUInt32(54)
|
redChannel = data.readUInt32(54)
|
||||||
greenChannel = data.readUInt32(58)
|
greenChannel = data.readUInt32(58)
|
||||||
|
@ -59,13 +62,13 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
|
|
||||||
if numColors > 0:
|
if numColors > 0:
|
||||||
if data.len < 14 + dibHeader + numColors * 4:
|
if data.len < 14 + dibHeader + numColors * 4:
|
||||||
raise newException(PixieError, "Invalid BMP data")
|
failInvalid()
|
||||||
|
|
||||||
var colorOffset = dibHeader + 14
|
var colorOffset = dibHeader + 14
|
||||||
for i in 0 ..< numColors:
|
for i in 0 ..< numColors:
|
||||||
var rgba: ColorRGBA
|
var rgba: ColorRGBA
|
||||||
if colorOffset + 3 > data.len - 2:
|
if colorOffset + 3 > data.len - 2:
|
||||||
raise newException(PixieError, "Truncated BMP data")
|
failInvalid()
|
||||||
rgba.r = data.readUint8(colorOffset + 2)
|
rgba.r = data.readUint8(colorOffset + 2)
|
||||||
rgba.g = data.readUint8(colorOffset + 1)
|
rgba.g = data.readUint8(colorOffset + 1)
|
||||||
rgba.b = data.readUint8(colorOffset + 0)
|
rgba.b = data.readUint8(colorOffset + 0)
|
||||||
|
@ -75,7 +78,7 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
|
|
||||||
if redChannel == 0 or greenChannel == 0 or
|
if redChannel == 0 or greenChannel == 0 or
|
||||||
blueChannel == 0 or alphaChannel == 0:
|
blueChannel == 0 or alphaChannel == 0:
|
||||||
raise newException(PixieError, "Unsupported 0 channel mask.")
|
failInvalid()
|
||||||
|
|
||||||
if bits notin [1, 4, 8, 32, 24]:
|
if bits notin [1, 4, 8, 32, 24]:
|
||||||
raise newException(PixieError, "Unsupported BMP data format")
|
raise newException(PixieError, "Unsupported BMP data format")
|
||||||
|
@ -104,7 +107,7 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
var rgba: ColorRGBA
|
var rgba: ColorRGBA
|
||||||
if haveBits == 0:
|
if haveBits == 0:
|
||||||
if offset >= data.len:
|
if offset >= data.len:
|
||||||
raise newException(PixieError, "Truncated BMP data")
|
failInvalid()
|
||||||
colorBits = data.readUint8(offset)
|
colorBits = data.readUint8(offset)
|
||||||
haveBits = 8
|
haveBits = 8
|
||||||
offset += 1
|
offset += 1
|
||||||
|
@ -130,13 +133,13 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
var rgba: ColorRGBA
|
var rgba: ColorRGBA
|
||||||
if haveBits == 0:
|
if haveBits == 0:
|
||||||
if offset >= data.len:
|
if offset >= data.len:
|
||||||
raise newException(PixieError, "Truncated BMP data")
|
failInvalid()
|
||||||
colorBits = data.readUint8(offset)
|
colorBits = data.readUint8(offset)
|
||||||
haveBits = 8
|
haveBits = 8
|
||||||
offset += 1
|
offset += 1
|
||||||
let index = (colorBits and 0b1111_0000) shr 4
|
let index = (colorBits and 0b1111_0000) shr 4
|
||||||
if index.int >= numColors:
|
if index.int >= numColors:
|
||||||
raise newException(PixieError, "Invalid BMP index")
|
failInvalid()
|
||||||
rgba = colorTable[index]
|
rgba = colorTable[index]
|
||||||
colorBits = colorBits shl 4
|
colorBits = colorBits shl 4
|
||||||
haveBits -= 4
|
haveBits -= 4
|
||||||
|
@ -150,12 +153,12 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
offset += 4 - padding
|
offset += 4 - padding
|
||||||
for x in 0 ..< result.width:
|
for x in 0 ..< result.width:
|
||||||
if offset >= data.len:
|
if offset >= data.len:
|
||||||
raise newException(PixieError, "Truncated BMP data")
|
failInvalid()
|
||||||
var rgba: ColorRGBA
|
var rgba: ColorRGBA
|
||||||
let index = data.readUint8(offset)
|
let index = data.readUint8(offset)
|
||||||
offset += 1
|
offset += 1
|
||||||
if index.int >= numColors:
|
if index.int >= numColors:
|
||||||
raise newException(PixieError, "Invalid BMP index")
|
failInvalid()
|
||||||
rgba = colorTable[index]
|
rgba = colorTable[index]
|
||||||
result[x, result.height - y - 1] = rgba.rgbx()
|
result[x, result.height - y - 1] = rgba.rgbx()
|
||||||
|
|
||||||
|
@ -167,7 +170,7 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
offset += 4 - padding
|
offset += 4 - padding
|
||||||
for x in 0 ..< result.width:
|
for x in 0 ..< result.width:
|
||||||
if offset + 2 >= data.len:
|
if offset + 2 >= data.len:
|
||||||
raise newException(PixieError, "Truncated BMP data")
|
failInvalid()
|
||||||
var rgba: ColorRGBA
|
var rgba: ColorRGBA
|
||||||
rgba.r = data.readUint8(offset + 2)
|
rgba.r = data.readUint8(offset + 2)
|
||||||
rgba.g = data.readUint8(offset + 1)
|
rgba.g = data.readUint8(offset + 1)
|
||||||
|
@ -180,7 +183,7 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
for y in 0 ..< result.height:
|
for y in 0 ..< result.height:
|
||||||
for x in 0 ..< result.width:
|
for x in 0 ..< result.width:
|
||||||
if offset + 3 >= data.len:
|
if offset + 3 >= data.len:
|
||||||
raise newException(PixieError, "Truncated BMP data")
|
failInvalid()
|
||||||
var rgba: ColorRGBA
|
var rgba: ColorRGBA
|
||||||
let color = data.readUint32(offset)
|
let color = data.readUint32(offset)
|
||||||
rgba.r = color.colorMaskShift(redChannel)
|
rgba.r = color.colorMaskShift(redChannel)
|
||||||
|
|
Loading…
Reference in a new issue