Merge branch 'master' of github.com:treeform/pixie

This commit is contained in:
treeform 2020-11-28 22:28:55 -08:00
commit 84c6a1e2eb
5 changed files with 66 additions and 24 deletions

View file

@ -4,6 +4,7 @@ import pixie/common, pixie/images, strutils
# See http://www.vip.sugovica.hu/Sardi/kepnezo/JPEG%20File%20Layout%20and%20Format.htm
const
fastBits = 9
jpgStartOfImage* = [0xFF.uint8, 0xD8]
deZigZag = [
0.uint8, 1, 8, 16, 9, 2, 3, 10,
@ -26,9 +27,12 @@ const
type
Huffman = object
codes: array[256, uint16]
symbols: array[256, uint8]
sizes: array[257, uint8]
deltas: array[17, int]
maxCodes: array[18, int]
fast: array[1 shl fastBits, uint8]
ResampleProc = proc(dst, line0, line1: ptr UncheckedArray[uint8],
widthPreExpansion, horizontalExpansionFactor: int
@ -113,20 +117,20 @@ proc decodeDQT(state: var DecoderState) =
proc decodeDHT(state: var DecoderState) =
proc buildHuffman(huffman: var Huffman, counts: array[16, uint8]) =
var sizes: array[257, uint8]
block:
var k: int
for i in 0.uint8 ..< 16:
for j in 0.uint8 ..< counts[i]:
sizes[k] = i + 1
huffman.sizes[k] = i + 1
inc k
sizes[k] = 0
huffman.sizes[k] = 0
var code, j: int
for i in 1.uint8 .. 16:
huffman.deltas[i] = j - code
if sizes[j] == i:
while sizes[j] == i:
if huffman.sizes[j] == i:
while huffman.sizes[j] == i:
huffman.codes[j] = code.uint16
inc code
inc j
if code - 1 >= 1 shl i:
@ -135,6 +139,16 @@ proc decodeDHT(state: var DecoderState) =
code = code shl 1
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
while len > 0:
let
@ -313,28 +327,39 @@ proc huffmanDecode(state: var DecoderState, tableCurrent, table: int): uint8 =
if state.bitCount < 16:
state.fillBits()
var
tmp = (state.bits shr 16).int
i = 1
while i < state.huffmanTables[tableCurrent][table].maxCodes.len:
if tmp < state.huffmanTables[tableCurrent][table].maxCodes[i]:
break
inc i
let
fastId = (state.bits shr (32 - fastBits)) and ((1 shl fastBits) - 1)
fast = state.huffmanTables[tableCurrent][table].fast[fastId]
if fast < 255:
let size = state.huffmanTables[tableCurrent][table].sizes[fast].int
if size > state.bitCount:
failInvalid()
if i == 17 or i > state.bitCount:
failInvalid()
result = state.huffmanTables[tableCurrent][table].symbols[fast]
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 +
state.huffmanTables[tableCurrent][table].deltas[i]
result = state.huffmanTables[tableCurrent][table].symbols[symbolId]
if i == 17 or i > state.bitCount:
failInvalid()
state.bits = state.bits shl i
state.bitCount -= i
let symbolId = (state.bits shr (32 - i)).int +
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 =
(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:
state.fillBits()
@ -345,7 +370,9 @@ proc extendReceive(state: var DecoderState, t: int): int =
state.bitCount -= t
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
if t < 0:
failInvalid()

View file

@ -436,6 +436,8 @@ proc encodePng*(
else:
raise newException(PixieError, "Invalid PNG number of channels")
let data = cast[ptr UncheckedArray[uint8]](data)
# Add the PNG file signature
result.add([137.uint8, 80, 78, 71, 13, 10, 26, 10])
@ -456,7 +458,6 @@ proc encodePng*(
for x in 0 ..< width * channels:
# Move through the image data byte-by-byte
let
data = cast[ptr UncheckedArray[uint8]](data)
dataPos = y * width * channels + x
filteredPos = y * width * channels + y + 1 + x
var left, up: int

14
tests/benchmark_jpg.nim Normal file
View file

@ -0,0 +1,14 @@
import pixie/fileformats/jpg, pixie/fileformats/stb_image/stb_image, fidget/opengl/perf
let data = readFile("tests/images/jpg/jpeg420exif.jpg")
timeIt "pixie decode":
for i in 0 ..< 20:
discard decodeJpg(cast[seq[uint8]](data))
timeIt "stb_image decode":
for i in 0 ..< 20:
var
width: int
height: int
discard loadFromMemory(cast[seq[uint8]](data), width, height)

View file

@ -1,7 +1,7 @@
import pixie/fileformats/png, stb_image/read as stbi, stb_image/write as stbr,
fidget/opengl/perf, nimPNG
let data = readFile("tests/images/lenna.png")
let data = readFile("tests/images/png/lenna.png")
timeIt "pixie decode":
for i in 0 ..< 100:

View file

@ -12,8 +12,8 @@ proc stbDecode*(data: string): Image =
let
original = readFile("tests/images/jpg/jpeg420exif.jpg")
pixieDecoded = decodeJpg(original)
stbDecoded = stbDecode(original)
pixieDecoded = decodeJpg(original)
doAssert pixieDecoded.width == stbDecoded.width
doAssert pixieDecoded.height == stbDecoded.height