Some gif improvments.

This commit is contained in:
treeform 2021-03-01 08:46:03 -08:00
parent dc52e6f77b
commit d248457b0b

View file

@ -22,6 +22,7 @@ proc readBit(bs: BitStream, pos: int): int =
proc read*(bs: BitStream, bits: int): int = proc read*(bs: BitStream, bits: int): int =
## Reads number of bits ## Reads number of bits
# TODO: This can be faster.
for i in 0 ..< bits: for i in 0 ..< bits:
result = result shl 1 result = result shl 1
result += bs.readBit(bs.pos + bits - i - 1) result += bs.readBit(bs.pos + bits - i - 1)
@ -70,7 +71,7 @@ proc decodeGIF*(data: string): Image =
let blockType = data.readUint8(i) let blockType = data.readUint8(i)
i += 1 i += 1
case blockType: case blockType:
of 0x2c: # IMAGE of 0x2c: # Read IMAGE block.
if i + 9 >= data.len: failInvalid() if i + 9 >= data.len: failInvalid()
let let
left = data.readUint16(i + 0) left = data.readUint16(i + 0)
@ -114,8 +115,8 @@ proc decodeGIF*(data: string): Image =
i += lzwEncodedLen.int i += lzwEncodedLen.int
let let
clearMark = 1 shl lzwMinBitSize clearCode = 1 shl lzwMinBitSize
endMark = clearMark + 1 endCode = clearCode + 1
# Turn full lzw data into bit stream. # Turn full lzw data into bit stream.
var var
@ -127,7 +128,8 @@ proc decodeGIF*(data: string): Image =
colorIndexes: seq[int] colorIndexes: seq[int]
# Main decode loop. # Main decode loop.
while codeLast != endMark: while codeLast != endCode:
if bs.pos + bitSize.int > bs.len: failInvalid() if bs.pos + bitSize.int > bs.len: failInvalid()
var var
# Read variable bits out of the table. # Read variable bits out of the table.
@ -135,16 +137,16 @@ proc decodeGIF*(data: string): Image =
# Some time we need to carry over table information. # Some time we need to carry over table information.
carryOver: seq[int] carryOver: seq[int]
if codeId == clearMark: if codeId == clearCode:
# Clear and re-init the tables. # Clear and re-init the tables.
bitSize = lzwMinBitSize + 1 bitSize = lzwMinBitSize + 1
currentCodeTableMax = (1 shl (bitSize)) - 1 currentCodeTableMax = (1 shl (bitSize)) - 1
codeLast = -1 codeLast = -1
codeTable.setLen(0) codeTable.setLen(0)
for x in 0 ..< endMark + 1: for x in 0 ..< endCode + 1:
codeTable.add(@[x]) codeTable.add(@[x])
elif codeId == endMark: elif codeId == endCode:
# Exit we are done. # Exit we are done.
break break
@ -154,7 +156,7 @@ proc decodeGIF*(data: string): Image =
colorIndexes.add(current) colorIndexes.add(current)
carryOver = @[current[0]] carryOver = @[current[0]]
elif codeLast != -1 and codeLast != clearMark and codeLast != endMark: elif codeLast notin [-1, clearCode, endCode]:
# Its in the current table use it. # Its in the current table use it.
if codeLast >= codeTable.len: failInvalid() if codeLast >= codeTable.len: failInvalid()
var previous = codeTable[codeLast] var previous = codeTable[codeLast]
@ -166,7 +168,7 @@ proc decodeGIF*(data: string): Image =
inc bitSize inc bitSize
currentCodeTableMax = (1 shl (bitSize)) - 1 currentCodeTableMax = (1 shl (bitSize)) - 1
if codeLast != -1 and codeLast != clearMark and codeLast != endMark: if codeLast notin [-1, clearCode, endCode]:
# We had some left over and need to expand table. # We had some left over and need to expand table.
if codeLast >= codeTable.len: failInvalid() if codeLast >= codeTable.len: failInvalid()
codeTable.add(codeTable[codeLast] & carryOver) codeTable.add(codeTable[codeLast] & carryOver)
@ -178,8 +180,8 @@ proc decodeGIF*(data: string): Image =
if idx >= colors.len or j >= result.data.len: failInvalid() if idx >= colors.len or j >= result.data.len: failInvalid()
result.data[j] = colors[idx] result.data[j] = colors[idx]
of 0x21: of 0x21: # Read EXTENSION block.
# Skip over all extensions (mostly animation information) # Skip over all extensions (mostly animation information).
let extentionType = data.readUint8(i) let extentionType = data.readUint8(i)
inc i inc i
let byteLen = data.readUint8(i) let byteLen = data.readUint8(i)
@ -187,7 +189,7 @@ proc decodeGIF*(data: string): Image =
i += byteLen.int i += byteLen.int
doAssert data.readUint8(i) == 0 doAssert data.readUint8(i) == 0
inc i inc i
of 0x3b: of 0x3b: # Read TERMINAL block.
# Exit block byte - we are done. # Exit block byte - we are done.
return return
else: else: