This commit is contained in:
Ryan Oldenburg 2020-11-21 19:56:49 -06:00
parent 641b2b79fa
commit df0756941c

View file

@ -5,6 +5,14 @@ import flatty/binny, pixie/common, pixie/images
const const
jpgStartOfImage* = [0xFF.uint8, 0xD8] jpgStartOfImage* = [0xFF.uint8, 0xD8]
type
Component = object
id, samplingFactors, quantizationTable: uint8
Jpg = object
width, height: int
components: array[3, Component]
template failInvalid() = template failInvalid() =
raise newException(PixieError, "Invalid JPG buffer, unable to load") raise newException(PixieError, "Invalid JPG buffer, unable to load")
@ -21,7 +29,7 @@ proc readSegmentLen(data: seq[uint8], pos: int): int =
proc skipSegment(data: seq[uint8], pos: var int) {.inline.} = proc skipSegment(data: seq[uint8], pos: var int) {.inline.} =
pos += readSegmentLen(data, pos) pos += readSegmentLen(data, pos)
proc decodeSOF(data: seq[uint8], pos: var int) = proc decodeSOF(jpg: var Jpg, data: seq[uint8], pos: var int) =
let segmentLen = readSegmentLen(data, pos) let segmentLen = readSegmentLen(data, pos)
pos += 2 pos += 2
@ -36,21 +44,31 @@ proc decodeSOF(data: seq[uint8], pos: var int) =
pos += 6 pos += 6
if width <= 0:
raise newException(PixieError, "Invalid JPG width")
if height <= 0:
raise newException(PixieError, "Invalid JPG height")
if precision != 8: if precision != 8:
raise newException(PixieError, "Unsupported JPG bit depth") raise newException(PixieError, "Unsupported JPG bit depth")
if components != 3: if components != 3:
raise newException(PixieError, "Unsupported JPG channel count") raise newException(PixieError, "Unsupported JPG channel count")
debugEcho width, " x ", height jpg.width = width
jpg.height = height
if 8 + components * 3 != segmentLen: if 8 + components * 3 != segmentLen:
failInvalid() failInvalid()
for i in 0 ..< 3: for i in 0 ..< 3:
discard jpg.components[i] = Component(
id: data[pos],
pos += components * 3 samplingFactors: data[pos + 1],
quantizationTable: data[pos + 2]
)
pos += 3
proc decodeDHT(data: seq[uint8], pos: var int) = proc decodeDHT(data: seq[uint8], pos: var int) =
skipSegment(data, pos) skipSegment(data, pos)
@ -58,9 +76,6 @@ proc decodeDHT(data: seq[uint8], pos: var int) =
proc decodeDQT(data: seq[uint8], pos: var int) = proc decodeDQT(data: seq[uint8], pos: var int) =
skipSegment(data, pos) skipSegment(data, pos)
proc decodeDRI(data: seq[uint8], pos: var int) =
skipSegment(data, pos)
proc decodeSOS(data: seq[uint8], pos: var int) = proc decodeSOS(data: seq[uint8], pos: var int) =
let segmentLen = readSegmentLen(data, pos) let segmentLen = readSegmentLen(data, pos)
pos += 2 pos += 2
@ -83,16 +98,17 @@ proc decodeSOS(data: seq[uint8], pos: var int) =
failInvalid() failInvalid()
if data[pos] == 0xFF: if data[pos] == 0xFF:
inc pos if pos + 1 == data.len:
if pos == data.len:
failInvalid() failInvalid()
if data[pos] == 0xD9: # End of Image: if data[pos + 1] == 0xD9: # End of Image:
inc pos pos += 2
break break
elif data[pos] == 0x00: elif data[pos + 1] == 0x00:
discard # Skip this byte discard # Skip the 0x00 byte
else: else:
failInvalid() failInvalid()
else:
discard
inc pos inc pos
@ -105,7 +121,9 @@ proc decodeJpg*(data: seq[uint8]): Image =
if data.readUint16(0) != cast[uint16](jpgStartOfImage): if data.readUint16(0) != cast[uint16](jpgStartOfImage):
failInvalid() failInvalid()
var pos: int var
jpg: Jpg
pos: int
while true: while true:
if pos + 2 > data.len: if pos + 2 > data.len:
failInvalid() failInvalid()
@ -120,15 +138,14 @@ proc decodeJpg*(data: seq[uint8]): Image =
of 0xD8: # Start of Image of 0xD8: # Start of Image
discard discard
of 0xC0: # Start of Frame of 0xC0: # Start of Frame
decodeSOF(data, pos) jpg.decodeSOF(data, pos)
of 0xC2: # Start of Frame of 0xC2: # Start of Frame
raise newException(PixieError, "Progressive JPG not supported") raise newException(PixieError, "Progressive JPG not supported")
of 0xC4: # Define Huffman Tables of 0xC4: # Define Huffman Tables
decodeDHT(data, pos) decodeDHT(data, pos)
of 0xDB: # Define Quantanization Table(s) of 0xDB: # Define Quantanization Table(s)
decodeDQT(data, pos) decodeDQT(data, pos)
of 0xDD: # Define Restart Interval # of 0xDD: # Define Restart Interval
decodeDRI(data, pos)
of 0xDA: # Start of Scan of 0xDA: # Start of Scan
decodeSOS(data, pos) decodeSOS(data, pos)
break break
@ -141,7 +158,7 @@ proc decodeJpg*(data: seq[uint8]): Image =
# Skip APPn segments # Skip APPn segments
skipSegment(data, pos) skipSegment(data, pos)
else: else:
raise newException(PixieError, "Unsupported JPG segemnt") raise newException(PixieError, "Unsupported JPG segment")
raise newException(PixieError, "Decoding JPG not supported yet") raise newException(PixieError, "Decoding JPG not supported yet")