qoi consistent style pass
This commit is contained in:
parent
a8cd3bfd3b
commit
91abc684ad
|
@ -34,6 +34,7 @@ Format | Read | Write |
|
||||||
PNG | ✅ | ✅ |
|
PNG | ✅ | ✅ |
|
||||||
JPEG | ✅ | |
|
JPEG | ✅ | |
|
||||||
BMP | ✅ | ✅ |
|
BMP | ✅ | ✅ |
|
||||||
|
QOI | ✅ | ✅ |
|
||||||
GIF | ✅ | |
|
GIF | ✅ | |
|
||||||
SVG | ✅ | |
|
SVG | ✅ | |
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import bumpy, chroma, flatty/binny, os, pixie/common, pixie/contexts,
|
import bumpy, chroma, flatty/binny, os, pixie/common, pixie/contexts,
|
||||||
pixie/fileformats/bmp, pixie/fileformats/gif, pixie/fileformats/jpg,
|
pixie/fileformats/bmp, pixie/fileformats/gif, pixie/fileformats/jpg,
|
||||||
pixie/fileformats/png, pixie/fileformats/qoi, pixie/fileformats/svg,
|
pixie/fileformats/png, pixie/fileformats/qoi, pixie/fileformats/svg,
|
||||||
pixie/fonts, pixie/images, pixie/masks, pixie/paints, pixie/paths,
|
pixie/fonts, pixie/images, pixie/masks, pixie/paints, pixie/paths, strutils, vmath
|
||||||
strutils, vmath
|
|
||||||
|
|
||||||
export bumpy, chroma, common, contexts, fonts, images, masks, paints, paths, vmath
|
export bumpy, chroma, common, contexts, fonts, images, masks, paints, paths, vmath
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import std/endians, chroma, flatty/binny
|
import chroma, flatty/binny, pixie/common, pixie/images, pixie/internal
|
||||||
import pixie/[common, images, internal]
|
|
||||||
|
|
||||||
# See: https://qoiformat.org/qoi-specification.pdf
|
# See: https://qoiformat.org/qoi-specification.pdf
|
||||||
|
|
||||||
|
@ -15,158 +14,150 @@ const
|
||||||
opRun = 0b11000000'u8
|
opRun = 0b11000000'u8
|
||||||
|
|
||||||
type
|
type
|
||||||
Colorspace* = enum sRBG = 0, linear = 1
|
Colorspace* = enum
|
||||||
|
sRBG = 0
|
||||||
|
Linear = 1
|
||||||
|
|
||||||
Qoi* = ref object
|
Qoi* = ref object
|
||||||
## Raw QOI image data.
|
## Raw QOI image data.
|
||||||
data*: seq[ColorRGBA]
|
|
||||||
width*, height*, channels*: int
|
width*, height*, channels*: int
|
||||||
colorspace*: Colorspace
|
colorspace*: Colorspace
|
||||||
|
data*: seq[ColorRGBA]
|
||||||
|
|
||||||
Index = array[indexLen, ColorRGBA]
|
Index = array[indexLen, ColorRGBA]
|
||||||
|
|
||||||
func hash(p: ColorRGBA): int =
|
func hash(p: ColorRGBA): int =
|
||||||
(p.r.int * 3 + p.g.int * 5 + p.b.int * 7 + p.a.int * 11) mod indexLen
|
(p.r.int * 3 + p.g.int * 5 + p.b.int * 7 + p.a.int * 11) mod indexLen
|
||||||
|
|
||||||
func toImage*(qoi: Qoi): Image =
|
func newImage*(qoi: Qoi): Image =
|
||||||
## Converts raw QOI data to `Image`.
|
## Converts raw QOI data to `Image`.
|
||||||
result = newImage(qoi.width, qoi.height)
|
result = newImage(qoi.width, qoi.height)
|
||||||
copyMem(result.data[0].addr, qoi.data[0].addr, qoi.data.len * 4)
|
copyMem(result.data[0].addr, qoi.data[0].addr, qoi.data.len * 4)
|
||||||
result.data.toPremultipliedAlpha()
|
result.data.toPremultipliedAlpha()
|
||||||
|
|
||||||
func toQoi*(img: Image; channels: range[3..4]): Qoi =
|
proc decodeQoiRaw*(data: string): Qoi {.raises: [PixieError].} =
|
||||||
## Converts an `Image` to raw QOI data.
|
|
||||||
result = Qoi(
|
|
||||||
data: newSeq[ColorRGBA](img.data.len),
|
|
||||||
width: img.width,
|
|
||||||
height: img.height,
|
|
||||||
channels: channels)
|
|
||||||
result.data.toStraightAlpha()
|
|
||||||
|
|
||||||
proc decompressQoi*(data: string): Qoi {.raises: [PixieError].} =
|
|
||||||
## Decompress QOI file format data.
|
## Decompress QOI file format data.
|
||||||
if data.len <= 14 or data[0 .. 3] != qoiSignature:
|
if data.len <= 14 or data[0 .. 3] != qoiSignature:
|
||||||
raise newException(PixieError, "Invalid QOI header")
|
raise newException(PixieError, "Invalid QOI header")
|
||||||
var
|
|
||||||
width, height: uint32
|
let
|
||||||
channels, colorspace: uint8
|
width = data.readUint32(4).swap()
|
||||||
block:
|
height = data.readUint32(8).swap()
|
||||||
when cpuEndian == bigEndian:
|
channels = data.readUint8(12)
|
||||||
width = data.readUint32(4)
|
colorspace = data.readUint8(13)
|
||||||
height = data.readUint32(8)
|
|
||||||
else:
|
|
||||||
var (wBe, hBe) = (data.readUint32(4), data.readUint32(8))
|
|
||||||
swapEndian32(addr width, addr wBe)
|
|
||||||
swapEndian32(addr height, addr hBe)
|
|
||||||
channels = data.readUint8(12)
|
|
||||||
colorspace = data.readUint8(13)
|
|
||||||
if channels notin {3, 4} or colorspace notin {0, 1}:
|
if channels notin {3, 4} or colorspace notin {0, 1}:
|
||||||
raise newException(PixieError, "Invalid QOI header")
|
raise newException(PixieError, "Invalid QOI header")
|
||||||
|
|
||||||
if width.int * height.int > uint32.high.int:
|
if width.int * height.int > uint32.high.int:
|
||||||
raise newException(PixieError, "QOI is too large to decode")
|
raise newException(PixieError, "QOI is too large to decode")
|
||||||
|
|
||||||
result = Qoi(
|
result = Qoi()
|
||||||
data: newSeq[ColorRGBA](int width * height),
|
result.width = width.int
|
||||||
width: int width,
|
result.height = height.int
|
||||||
height: int height,
|
result.channels = channels.int
|
||||||
channels: int channels,
|
result.colorspace = colorspace.Colorspace
|
||||||
colorspace: Colorspace colorspace)
|
result.data.setLen(result.width * result.height)
|
||||||
|
|
||||||
var
|
var
|
||||||
index: Index
|
index: Index
|
||||||
p = 14
|
p = 14
|
||||||
run: uint8
|
run: uint8
|
||||||
px = rgba(0, 0, 0, 0xff)
|
px = rgba(0, 0, 0, 255)
|
||||||
|
|
||||||
for dst in result.data.mitems:
|
for dst in result.data.mitems:
|
||||||
if p > data.len-8:
|
if p > data.len - 8:
|
||||||
raise newException(PixieError, "Underrun of QOI decoder")
|
raise newException(PixieError, "Underrun of QOI decoder")
|
||||||
|
|
||||||
if run > 0:
|
if run > 0:
|
||||||
dec(run)
|
dec run
|
||||||
else:
|
else:
|
||||||
let b0 = data.readUint8(p)
|
let b0 = data.readUint8(p)
|
||||||
inc(p)
|
inc p
|
||||||
case b0
|
|
||||||
|
case b0:
|
||||||
of opRgb:
|
of opRgb:
|
||||||
px.r = data.readUint8(p+0)
|
px.r = data.readUint8(p + 0)
|
||||||
px.g = data.readUint8(p+1)
|
px.g = data.readUint8(p + 1)
|
||||||
px.b = data.readUint8(p+2)
|
px.b = data.readUint8(p + 2)
|
||||||
inc(p, 3)
|
p += 3
|
||||||
of opRgba:
|
of opRgba:
|
||||||
px.r = data.readUint8(p+0)
|
px.r = data.readUint8(p + 0)
|
||||||
px.g = data.readUint8(p+1)
|
px.g = data.readUint8(p + 1)
|
||||||
px.b = data.readUint8(p+2)
|
px.b = data.readUint8(p + 2)
|
||||||
px.a = data.readUint8(p+3)
|
px.a = data.readUint8(p + 3)
|
||||||
inc(p, 4)
|
p += 4
|
||||||
else:
|
else:
|
||||||
case b0 and opMask2
|
case b0 and opMask2:
|
||||||
of opIndex:
|
of opIndex:
|
||||||
px = index[b0]
|
px = index[b0]
|
||||||
of opDiff:
|
of opDiff:
|
||||||
px.r = px.r + uint8((b0 shr 4) and 0x03) - 2
|
px.r = px.r + ((b0 shr 4) and 0x03).uint8 - 2
|
||||||
px.g = px.g + uint8((b0 shr 2) and 0x03) - 2
|
px.g = px.g + ((b0 shr 2) and 0x03).uint8 - 2
|
||||||
px.b = px.b + uint8((b0 shr 0) and 0x03) - 2
|
px.b = px.b + ((b0 shr 0) and 0x03).uint8 - 2
|
||||||
of opLuma:
|
of opLuma:
|
||||||
let b1 = data.readUint8(p)
|
let
|
||||||
inc(p)
|
b1 = data.readUint8(p)
|
||||||
let vg = (b0.uint8 and 0x3f) - 32
|
vg = (b0.uint8 and 0x3f) - 32
|
||||||
px.r = px.r + vg - 8 + ((b1 shr 4) and 0x0f)
|
px.r = px.r + vg - 8 + ((b1 shr 4) and 0x0f)
|
||||||
px.g = px.g + vg
|
px.g = px.g + vg
|
||||||
px.b = px.b + vg - 8 + ((b1 shr 0) and 0x0f)
|
px.b = px.b + vg - 8 + ((b1 shr 0) and 0x0f)
|
||||||
|
inc p
|
||||||
of opRun:
|
of opRun:
|
||||||
run = b0 and 0x3f
|
run = b0 and 0x3f
|
||||||
else: assert false
|
else:
|
||||||
|
raise newException(PixieError, "Unexpected QOI op")
|
||||||
|
|
||||||
index[hash(px)] = px
|
index[hash(px)] = px
|
||||||
|
|
||||||
dst = px
|
dst = px
|
||||||
|
|
||||||
while p < data.len:
|
while p < data.len:
|
||||||
case data[p]
|
case data[p]:
|
||||||
of '\0': discard
|
of '\0':
|
||||||
of '\1': break # ignore trailing data
|
discard
|
||||||
|
of '\1':
|
||||||
|
break # ignore trailing data
|
||||||
else:
|
else:
|
||||||
raise newException(PixieError, "Invalid QOI padding")
|
raise newException(PixieError, "Invalid QOI padding")
|
||||||
inc(p)
|
inc(p)
|
||||||
|
|
||||||
proc decodeQoi*(data: string): Image {.raises: [PixieError].} =
|
proc decodeQoi*(data: string): Image {.raises: [PixieError].} =
|
||||||
## Decodes data in the QOI file format to an `Image`.
|
## Decodes data in the QOI file format to an `Image`.
|
||||||
decompressQoi(data).toImage()
|
newImage(decodeQoiRaw(data))
|
||||||
|
|
||||||
proc decodeQoi*(data: seq[uint8]): Image {.inline, raises: [PixieError].} =
|
proc encodeQoi*(qoi: Qoi): string {.raises: [PixieError].} =
|
||||||
## Decodes data in the QOI file format to an `Image`.
|
|
||||||
decodeQoi(cast[string](data))
|
|
||||||
|
|
||||||
proc compressQoi*(qoi: Qoi): string =
|
|
||||||
## Encodes raw QOI pixels to the QOI file format.
|
## Encodes raw QOI pixels to the QOI file format.
|
||||||
|
|
||||||
|
if qoi.width.int * qoi.height.int > uint32.high.int:
|
||||||
|
raise newException(PixieError, "QOI is too large to encode")
|
||||||
|
|
||||||
|
# Allocate a buffer 3/4 the size of the pathological encoding
|
||||||
result = newStringOfCap(14 + 8 + qoi.data.len * 3)
|
result = newStringOfCap(14 + 8 + qoi.data.len * 3)
|
||||||
# allocate a buffer 3/4 the size of the pathological encoding
|
|
||||||
result.add(qoiSignature)
|
result.add(qoiSignature)
|
||||||
when cpuEndian == bigEndian:
|
result.addUint32(qoi.width.uint32.swap())
|
||||||
result.addUint32(uint32 qoi.width)
|
result.addUint32(qoi.height.uint32.swap())
|
||||||
result.addUint32(uint32 qoi.height)
|
result.addUint8(qoi.channels.uint8)
|
||||||
else:
|
result.addUint8(qoi.colorspace.uint8)
|
||||||
var
|
|
||||||
(wLe, hLe) = (uint32 qoi.width, uint32 qoi.height)
|
|
||||||
result.setLen(12)
|
|
||||||
swapEndian32(addr result[4], addr wLe)
|
|
||||||
swapEndian32(addr result[8], addr hLe)
|
|
||||||
result.addUint8(uint8 qoi.channels)
|
|
||||||
result.addUint8(uint8 qoi.colorspace)
|
|
||||||
|
|
||||||
var
|
var
|
||||||
index: Index
|
index: Index
|
||||||
run: uint8
|
run: uint8
|
||||||
pxPrev = rgba(0, 0, 0, 0xff)
|
pxPrev = rgba(0, 0, 0, 255)
|
||||||
|
|
||||||
for off, px in qoi.data:
|
for off, px in qoi.data:
|
||||||
if px == pxPrev:
|
if px == pxPrev:
|
||||||
inc run
|
inc run
|
||||||
if run == 62 or off == qoi.data.high:
|
if run == 62 or off == qoi.data.high:
|
||||||
result.addUint8(opRun or pred(run))
|
result.addUint8(opRun or (run - 1))
|
||||||
reset run
|
run = 0
|
||||||
else:
|
else:
|
||||||
if run > 0:
|
if run > 0:
|
||||||
result.addUint8(opRun or pred(run))
|
result.addUint8(opRun or (run - 1))
|
||||||
reset run
|
run = 0
|
||||||
|
|
||||||
let i = hash(px)
|
let i = hash(px)
|
||||||
if index[i] == px: result.addUint8(opIndex or uint8(i))
|
if index[i] == px:
|
||||||
|
result.addUint8(opIndex or uint8(i))
|
||||||
else:
|
else:
|
||||||
index[i] = px
|
index[i] = px
|
||||||
if px.a == pxPrev.a:
|
if px.a == pxPrev.a:
|
||||||
|
@ -179,16 +170,14 @@ proc compressQoi*(qoi: Qoi): string =
|
||||||
if (vr > -3) and (vr < 2) and
|
if (vr > -3) and (vr < 2) and
|
||||||
(vg > -3) and (vg < 2) and
|
(vg > -3) and (vg < 2) and
|
||||||
(vb > -3) and (vb < 2):
|
(vb > -3) and (vb < 2):
|
||||||
let b = opDiff or uint8(
|
let b = opDiff or
|
||||||
((vr + 2) shl 4) or
|
(((vr + 2) shl 4) or ((vg + 2) shl 2) or ((vb + 2) shl 0)).uint8
|
||||||
((vg + 2) shl 2) or
|
|
||||||
((vb + 2) shl 0))
|
|
||||||
result.addUint8(b)
|
result.addUint8(b)
|
||||||
elif vgr > -9 and vgr < 8 and
|
elif vgr > -9 and vgr < 8 and
|
||||||
vg > -33 and vg < 32 and
|
vg > -33 and vg < 32 and
|
||||||
vgb > -9 and vgb < 8:
|
vgb > -9 and vgb < 8:
|
||||||
result.addUint8(opLuma or uint8(vg + 32))
|
result.addUint8(opLuma or (vg + 32).uint8)
|
||||||
result.addUint8(uint8 ((vgr + 8) shl 4) or (vgb + 8))
|
result.addUint8((((vgr + 8) shl 4) or (vgb + 8)).uint8)
|
||||||
else:
|
else:
|
||||||
result.addUint8(opRgb)
|
result.addUint8(opRgb)
|
||||||
result.addUint8(px.r)
|
result.addUint8(px.r)
|
||||||
|
@ -200,10 +189,23 @@ proc compressQoi*(qoi: Qoi): string =
|
||||||
result.addUint8(px.g)
|
result.addUint8(px.g)
|
||||||
result.addUint8(px.b)
|
result.addUint8(px.b)
|
||||||
result.addUint8(px.a)
|
result.addUint8(px.a)
|
||||||
|
|
||||||
pxPrev = px
|
pxPrev = px
|
||||||
for _ in 0..6: result.addUint8(0x00)
|
|
||||||
|
for _ in 0 .. 6:
|
||||||
|
result.addUint8(0x00)
|
||||||
|
|
||||||
result.addUint8(0x01)
|
result.addUint8(0x01)
|
||||||
|
|
||||||
proc encodeQoi*(img: Image): string {.raises: [].} =
|
proc encodeQoi*(image: Image): string {.raises: [PixieError].} =
|
||||||
## Encodes an image to the QOI file format.
|
## Encodes an image to the QOI file format.
|
||||||
compressQoi(toQoi(img, 4))
|
let qoi = Qoi()
|
||||||
|
qoi.width = image.width
|
||||||
|
qoi.height = image.height
|
||||||
|
qoi.channels = 4
|
||||||
|
qoi.data.setLen(image.data.len)
|
||||||
|
|
||||||
|
copyMem(qoi.data[0].addr, image.data[0].addr, image.data.len * 4)
|
||||||
|
qoi.data.toStraightAlpha()
|
||||||
|
|
||||||
|
encodeQoi(qoi)
|
||||||
|
|
|
@ -838,11 +838,14 @@ proc drawUber(
|
||||||
when type(b) is Image:
|
when type(b) is Image:
|
||||||
for q in [0, 4, 8, 12]:
|
for q in [0, 4, 8, 12]:
|
||||||
let sourceVec = mm_loadu_si128(b.data[b.dataIndex(sx + q, sy)].addr)
|
let sourceVec = mm_loadu_si128(b.data[b.dataIndex(sx + q, sy)].addr)
|
||||||
if mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, mm_setzero_si128())) != 0xffff:
|
if mm_movemask_epi8(mm_cmpeq_epi8(sourceVec,
|
||||||
if (mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, vec255)) and 0x8888) == 0x8888:
|
mm_setzero_si128())) != 0xffff:
|
||||||
|
if (mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, vec255)) and
|
||||||
|
0x8888) == 0x8888:
|
||||||
mm_storeu_si128(a.data[a.dataIndex(x + q, y)].addr, sourceVec)
|
mm_storeu_si128(a.data[a.dataIndex(x + q, y)].addr, sourceVec)
|
||||||
else:
|
else:
|
||||||
let backdropVec = mm_loadu_si128(a.data[a.dataIndex(x + q, y)].addr)
|
let backdropVec = mm_loadu_si128(a.data[a.dataIndex(x +
|
||||||
|
q, y)].addr)
|
||||||
mm_storeu_si128(
|
mm_storeu_si128(
|
||||||
a.data[a.dataIndex(x + q, y)].addr,
|
a.data[a.dataIndex(x + q, y)].addr,
|
||||||
blendNormalInlineSimd(backdropVec, sourceVec)
|
blendNormalInlineSimd(backdropVec, sourceVec)
|
||||||
|
@ -851,11 +854,14 @@ proc drawUber(
|
||||||
var values = mm_loadu_si128(b.data[b.dataIndex(sx, sy)].addr)
|
var values = mm_loadu_si128(b.data[b.dataIndex(sx, sy)].addr)
|
||||||
for q in [0, 4, 8, 12]:
|
for q in [0, 4, 8, 12]:
|
||||||
let sourceVec = unpackAlphaValues(values)
|
let sourceVec = unpackAlphaValues(values)
|
||||||
if mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, mm_setzero_si128())) != 0xffff:
|
if mm_movemask_epi8(mm_cmpeq_epi8(sourceVec,
|
||||||
if (mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, vec255)) and 0x8888) == 0x8888:
|
mm_setzero_si128())) != 0xffff:
|
||||||
|
if (mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, vec255)) and
|
||||||
|
0x8888) == 0x8888:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
let backdropVec = mm_loadu_si128(a.data[a.dataIndex(x + q, y)].addr)
|
let backdropVec = mm_loadu_si128(a.data[a.dataIndex(x +
|
||||||
|
q, y)].addr)
|
||||||
mm_storeu_si128(
|
mm_storeu_si128(
|
||||||
a.data[a.dataIndex(x + q, y)].addr,
|
a.data[a.dataIndex(x + q, y)].addr,
|
||||||
blendNormalInlineSimd(backdropVec, sourceVec)
|
blendNormalInlineSimd(backdropVec, sourceVec)
|
||||||
|
@ -886,8 +892,10 @@ proc drawUber(
|
||||||
when type(b) is Image:
|
when type(b) is Image:
|
||||||
for q in [0, 4, 8, 12]:
|
for q in [0, 4, 8, 12]:
|
||||||
let sourceVec = mm_loadu_si128(b.data[b.dataIndex(sx + q, sy)].addr)
|
let sourceVec = mm_loadu_si128(b.data[b.dataIndex(sx + q, sy)].addr)
|
||||||
if mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, mm_setzero_si128())) == 0xffff:
|
if mm_movemask_epi8(mm_cmpeq_epi8(sourceVec,
|
||||||
mm_storeu_si128(a.data[a.dataIndex(x + q, y)].addr, mm_setzero_si128())
|
mm_setzero_si128())) == 0xffff:
|
||||||
|
mm_storeu_si128(a.data[a.dataIndex(x + q, y)].addr,
|
||||||
|
mm_setzero_si128())
|
||||||
elif mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, vec255)) != 0xffff:
|
elif mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, vec255)) != 0xffff:
|
||||||
let backdropVec = mm_loadu_si128(a.data[a.dataIndex(x + q, y)].addr)
|
let backdropVec = mm_loadu_si128(a.data[a.dataIndex(x + q, y)].addr)
|
||||||
mm_storeu_si128(
|
mm_storeu_si128(
|
||||||
|
@ -898,9 +906,12 @@ proc drawUber(
|
||||||
var values = mm_loadu_si128(b.data[b.dataIndex(sx, sy)].addr)
|
var values = mm_loadu_si128(b.data[b.dataIndex(sx, sy)].addr)
|
||||||
for q in [0, 4, 8, 12]:
|
for q in [0, 4, 8, 12]:
|
||||||
let sourceVec = unpackAlphaValues(values)
|
let sourceVec = unpackAlphaValues(values)
|
||||||
if mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, mm_setzero_si128())) == 0xffff:
|
if mm_movemask_epi8(mm_cmpeq_epi8(sourceVec,
|
||||||
mm_storeu_si128(a.data[a.dataIndex(x + q, y)].addr, mm_setzero_si128())
|
mm_setzero_si128())) == 0xffff:
|
||||||
elif (mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, vec255)) and 0x8888) != 0x8888:
|
mm_storeu_si128(a.data[a.dataIndex(x + q, y)].addr,
|
||||||
|
mm_setzero_si128())
|
||||||
|
elif (mm_movemask_epi8(mm_cmpeq_epi8(sourceVec, vec255)) and
|
||||||
|
0x8888) != 0x8888:
|
||||||
let backdropVec = mm_loadu_si128(a.data[a.dataIndex(x + q, y)].addr)
|
let backdropVec = mm_loadu_si128(a.data[a.dataIndex(x + q, y)].addr)
|
||||||
mm_storeu_si128(
|
mm_storeu_si128(
|
||||||
a.data[a.dataIndex(x + q, y)].addr,
|
a.data[a.dataIndex(x + q, y)].addr,
|
||||||
|
|
|
@ -3,4 +3,4 @@ import benchy, pixie/fileformats/qoi
|
||||||
let data = readFile("tests/fileformats/qoi/testcard_rgba.qoi")
|
let data = readFile("tests/fileformats/qoi/testcard_rgba.qoi")
|
||||||
|
|
||||||
timeIt "pixie decode":
|
timeIt "pixie decode":
|
||||||
keep decodeQOI(data)
|
keep decodeQoi(data)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import random, pixie
|
import pixie, random
|
||||||
|
|
||||||
randomize()
|
randomize()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import std/[random, strformat]
|
import pixie/common, pixie/fileformats/qoi, std/random, strformat
|
||||||
import pixie/[common, fileformats/qoi]
|
|
||||||
|
|
||||||
randomize()
|
randomize()
|
||||||
|
|
||||||
|
@ -9,17 +8,18 @@ for i in 0 ..< 10_000:
|
||||||
var data = original
|
var data = original
|
||||||
let
|
let
|
||||||
pos = rand(data.len)
|
pos = rand(data.len)
|
||||||
value = rand(255).char
|
value = rand(255).uint8
|
||||||
data[pos] = value
|
data[pos] = value.char
|
||||||
|
echo &"{i} {pos} {value}"
|
||||||
try:
|
try:
|
||||||
let img = decodeQOI(data)
|
let img = decodeQoi(data)
|
||||||
doAssert img.height > 0 and img.width > 0
|
doAssert img.height > 0 and img.width > 0
|
||||||
except PixieError:
|
except PixieError:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
data = data[0 ..< pos]
|
data = data[0 ..< pos]
|
||||||
try:
|
try:
|
||||||
let img = decodeQOI(data)
|
let img = decodeQoi(data)
|
||||||
doAssert img.height > 0 and img.width > 0
|
doAssert img.height > 0 and img.width > 0
|
||||||
except PixieError:
|
except PixieError:
|
||||||
discard
|
discard
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
import pixie, pixie/fileformats/qoi, pixie/fileformats/png
|
import pixie, pixie/fileformats/png, pixie/fileformats/qoi
|
||||||
|
|
||||||
const tests = ["testcard", "testcard_rgba"]
|
const tests = ["testcard", "testcard_rgba"]
|
||||||
|
|
||||||
for name in tests:
|
for name in tests:
|
||||||
var input = decodeQoi(readFile("tests/fileformats/qoi/" & name & ".qoi"))
|
let
|
||||||
var control = decodePng(readFile("tests/fileformats/qoi/" & name & ".png"))
|
input = decodeQoi(readFile("tests/fileformats/qoi/" & name & ".qoi"))
|
||||||
doAssert(input.data == control.data, "input mismatch of " & name)
|
control = decodePng(readFile("tests/fileformats/qoi/" & name & ".png"))
|
||||||
|
doAssert input.data == control.data, "input mismatch of " & name
|
||||||
|
|
||||||
|
decodeQoi(control.encodeQoi()).writeFile("tmp.png")
|
||||||
|
|
||||||
for name in tests:
|
for name in tests:
|
||||||
var
|
let
|
||||||
input: Qoi = decompressQoi(readFile("tests/fileformats/qoi/" & name & ".qoi"))
|
input = decodeQoiRaw(readFile("tests/fileformats/qoi/" & name & ".qoi"))
|
||||||
output: Qoi = decompressQoi(compressQoi(input))
|
output = decodeQoiRaw(encodeQoi(input))
|
||||||
doAssert(output.data.len == input.data.len)
|
doAssert output.data.len == input.data.len
|
||||||
doAssert(output.data == input.data)
|
doAssert output.data == input.data
|
||||||
|
|
Loading…
Reference in a new issue