faster
This commit is contained in:
parent
2b67d52861
commit
b047aad920
2 changed files with 49 additions and 22 deletions
|
@ -4,6 +4,7 @@ import pixie/common, pixie/images, strutils
|
||||||
# See http://www.vip.sugovica.hu/Sardi/kepnezo/JPEG%20File%20Layout%20and%20Format.htm
|
# See http://www.vip.sugovica.hu/Sardi/kepnezo/JPEG%20File%20Layout%20and%20Format.htm
|
||||||
|
|
||||||
const
|
const
|
||||||
|
fastBits = 9
|
||||||
jpgStartOfImage* = [0xFF.uint8, 0xD8]
|
jpgStartOfImage* = [0xFF.uint8, 0xD8]
|
||||||
deZigZag = [
|
deZigZag = [
|
||||||
0.uint8, 1, 8, 16, 9, 2, 3, 10,
|
0.uint8, 1, 8, 16, 9, 2, 3, 10,
|
||||||
|
@ -26,9 +27,12 @@ const
|
||||||
|
|
||||||
type
|
type
|
||||||
Huffman = object
|
Huffman = object
|
||||||
|
codes: array[256, uint16]
|
||||||
symbols: array[256, uint8]
|
symbols: array[256, uint8]
|
||||||
|
sizes: array[257, uint8]
|
||||||
deltas: array[17, int]
|
deltas: array[17, int]
|
||||||
maxCodes: array[18, int]
|
maxCodes: array[18, int]
|
||||||
|
fast: array[1 shl fastBits, uint8]
|
||||||
|
|
||||||
ResampleProc = proc(dst, line0, line1: ptr UncheckedArray[uint8],
|
ResampleProc = proc(dst, line0, line1: ptr UncheckedArray[uint8],
|
||||||
widthPreExpansion, horizontalExpansionFactor: int
|
widthPreExpansion, horizontalExpansionFactor: int
|
||||||
|
@ -113,20 +117,20 @@ proc decodeDQT(state: var DecoderState) =
|
||||||
|
|
||||||
proc decodeDHT(state: var DecoderState) =
|
proc decodeDHT(state: var DecoderState) =
|
||||||
proc buildHuffman(huffman: var Huffman, counts: array[16, uint8]) =
|
proc buildHuffman(huffman: var Huffman, counts: array[16, uint8]) =
|
||||||
var sizes: array[257, uint8]
|
|
||||||
block:
|
block:
|
||||||
var k: int
|
var k: int
|
||||||
for i in 0.uint8 ..< 16:
|
for i in 0.uint8 ..< 16:
|
||||||
for j in 0.uint8 ..< counts[i]:
|
for j in 0.uint8 ..< counts[i]:
|
||||||
sizes[k] = i + 1
|
huffman.sizes[k] = i + 1
|
||||||
inc k
|
inc k
|
||||||
sizes[k] = 0
|
huffman.sizes[k] = 0
|
||||||
|
|
||||||
var code, j: int
|
var code, j: int
|
||||||
for i in 1.uint8 .. 16:
|
for i in 1.uint8 .. 16:
|
||||||
huffman.deltas[i] = j - code
|
huffman.deltas[i] = j - code
|
||||||
if sizes[j] == i:
|
if huffman.sizes[j] == i:
|
||||||
while sizes[j] == i:
|
while huffman.sizes[j] == i:
|
||||||
|
huffman.codes[j] = code.uint16
|
||||||
inc code
|
inc code
|
||||||
inc j
|
inc j
|
||||||
if code - 1 >= 1 shl i:
|
if code - 1 >= 1 shl i:
|
||||||
|
@ -135,6 +139,16 @@ proc decodeDHT(state: var DecoderState) =
|
||||||
code = code shl 1
|
code = code shl 1
|
||||||
huffman.maxCodes[17] = int.high
|
huffman.maxCodes[17] = int.high
|
||||||
|
|
||||||
|
for i in 0 ..< huffman.fast.len:
|
||||||
|
huffman.fast[i] = 255
|
||||||
|
|
||||||
|
for i in 0 ..< j:
|
||||||
|
let size = huffman.sizes[i]
|
||||||
|
if size <= fastBits:
|
||||||
|
let fast = huffman.codes[i].int shl (fastBits - size)
|
||||||
|
for k in 0 ..< 1 shl (fastBits - size):
|
||||||
|
huffman.fast[fast + k] = i.uint8
|
||||||
|
|
||||||
var len = state.readUint16be() - 2
|
var len = state.readUint16be() - 2
|
||||||
while len > 0:
|
while len > 0:
|
||||||
let
|
let
|
||||||
|
@ -313,28 +327,39 @@ proc huffmanDecode(state: var DecoderState, tableCurrent, table: int): uint8 =
|
||||||
if state.bitCount < 16:
|
if state.bitCount < 16:
|
||||||
state.fillBits()
|
state.fillBits()
|
||||||
|
|
||||||
var
|
let
|
||||||
tmp = (state.bits shr 16).int
|
fastId = (state.bits shr (32 - fastBits)) and ((1 shl fastBits) - 1)
|
||||||
i = 1
|
fast = state.huffmanTables[tableCurrent][table].fast[fastId]
|
||||||
while i < state.huffmanTables[tableCurrent][table].maxCodes.len:
|
if fast < 255:
|
||||||
if tmp < state.huffmanTables[tableCurrent][table].maxCodes[i]:
|
let size = state.huffmanTables[tableCurrent][table].sizes[fast].int
|
||||||
break
|
if size > state.bitCount:
|
||||||
inc i
|
failInvalid()
|
||||||
|
|
||||||
if i == 17 or i > state.bitCount:
|
result = state.huffmanTables[tableCurrent][table].symbols[fast]
|
||||||
failInvalid()
|
state.bits = state.bits shl size
|
||||||
|
state.bitCount -= size
|
||||||
|
else:
|
||||||
|
var
|
||||||
|
tmp = (state.bits shr 16).int
|
||||||
|
i = fastBits + 1
|
||||||
|
while i < state.huffmanTables[tableCurrent][table].maxCodes.len:
|
||||||
|
if tmp < state.huffmanTables[tableCurrent][table].maxCodes[i]:
|
||||||
|
break
|
||||||
|
inc i
|
||||||
|
|
||||||
let symbolId = (state.bits shr (32 - i)).int +
|
if i == 17 or i > state.bitCount:
|
||||||
state.huffmanTables[tableCurrent][table].deltas[i]
|
failInvalid()
|
||||||
result = state.huffmanTables[tableCurrent][table].symbols[symbolId]
|
|
||||||
|
|
||||||
state.bits = state.bits shl i
|
let symbolId = (state.bits shr (32 - i)).int +
|
||||||
state.bitCount -= i
|
state.huffmanTables[tableCurrent][table].deltas[i]
|
||||||
|
result = state.huffmanTables[tableCurrent][table].symbols[symbolId]
|
||||||
|
state.bits = state.bits shl i
|
||||||
|
state.bitCount -= i
|
||||||
|
|
||||||
template lrot(value: uint32, shift: int): uint32 =
|
template lrot(value: uint32, shift: int): uint32 =
|
||||||
(value shl shift) or (value shr (32 - shift))
|
(value shl shift) or (value shr (32 - shift))
|
||||||
|
|
||||||
proc extendReceive(state: var DecoderState, t: int): int =
|
proc extendReceive(state: var DecoderState, t: int): int {.inline.} =
|
||||||
if state.bitCount < t:
|
if state.bitCount < t:
|
||||||
state.fillBits()
|
state.fillBits()
|
||||||
|
|
||||||
|
@ -345,7 +370,9 @@ proc extendReceive(state: var DecoderState, t: int): int =
|
||||||
state.bitCount -= t
|
state.bitCount -= t
|
||||||
result = k.int + (biases[t] and (not sign))
|
result = k.int + (biases[t] and (not sign))
|
||||||
|
|
||||||
proc decodeImageBlock(state: var DecoderState, component: int): array[64, int16] =
|
proc decodeImageBlock(
|
||||||
|
state: var DecoderState, component: int
|
||||||
|
): array[64, int16] =
|
||||||
let t = state.huffmanDecode(0, state.components[component].huffmanDC).int
|
let t = state.huffmanDecode(0, state.components[component].huffmanDC).int
|
||||||
if t < 0:
|
if t < 0:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
|
@ -12,8 +12,8 @@ proc stbDecode*(data: string): Image =
|
||||||
|
|
||||||
let
|
let
|
||||||
original = readFile("tests/images/jpg/jpeg420exif.jpg")
|
original = readFile("tests/images/jpg/jpeg420exif.jpg")
|
||||||
pixieDecoded = decodeJpg(original)
|
|
||||||
stbDecoded = stbDecode(original)
|
stbDecoded = stbDecode(original)
|
||||||
|
pixieDecoded = decodeJpg(original)
|
||||||
|
|
||||||
doAssert pixieDecoded.width == stbDecoded.width
|
doAssert pixieDecoded.width == stbDecoded.width
|
||||||
doAssert pixieDecoded.height == stbDecoded.height
|
doAssert pixieDecoded.height == stbDecoded.height
|
||||||
|
|
Loading…
Reference in a new issue