Merge pull request #433 from guzba/master
update zippy dep, -d:lto + gcc >= 11 fix, decode image dimensions, small things
This commit is contained in:
commit
4a7b5a1e74
|
@ -93,6 +93,9 @@ exportObject ColorStop:
|
|||
exportObject TextMetrics:
|
||||
discard
|
||||
|
||||
exportObject ImageDimensions:
|
||||
discard
|
||||
|
||||
exportSeq seq[float32]:
|
||||
discard
|
||||
|
||||
|
@ -310,7 +313,10 @@ exportRefObject Context:
|
|||
isPointInStroke(Context, Path, float32, float32)
|
||||
|
||||
exportProcs:
|
||||
decodeImage
|
||||
decodeImageDimensions
|
||||
readImage
|
||||
readImageDimensions
|
||||
readmask
|
||||
readTypeface
|
||||
readFont
|
||||
|
|
|
@ -8,7 +8,7 @@ srcDir = "src"
|
|||
requires "nim >= 1.4.8"
|
||||
requires "vmath >= 1.1.4"
|
||||
requires "chroma >= 0.2.5"
|
||||
requires "zippy >= 0.9.9"
|
||||
requires "zippy >= 0.9.11"
|
||||
requires "flatty >= 0.3.3"
|
||||
requires "nimsimd >= 1.0.0"
|
||||
requires "bumpy >= 1.1.1"
|
||||
|
|
|
@ -18,6 +18,25 @@ converter autoPremultipliedAlpha*(c: ColorRGBA): ColorRGBX {.inline, raises: [].
|
|||
## Convert a straight alpha RGBA to a premultiplied alpha RGBA.
|
||||
c.rgbx()
|
||||
|
||||
proc decodeImageDimensions*(
|
||||
data: string
|
||||
): ImageDimensions {.raises: [PixieError].} =
|
||||
## Decodes an image's dimensions from memory.
|
||||
if data.len > 8 and data.readUint64(0) == cast[uint64](pngSignature):
|
||||
decodePngDimensions(data)
|
||||
elif data.len > 2 and data.readUint16(0) == cast[uint16](jpegStartOfImage):
|
||||
decodeJpegDimensions(data)
|
||||
elif data.len > 2 and data.readStr(0, 2) == bmpSignature:
|
||||
decodeBmpDimensions(data)
|
||||
elif data.len > 6 and data.readStr(0, 6) in gifSignatures:
|
||||
decodeGifDimensions(data)
|
||||
elif data.len > (14+8) and data.readStr(0, 4) == qoiSignature:
|
||||
decodeQoiDimensions(data)
|
||||
elif data.len > 9 and data.readStr(0, 2) in ppmSignatures:
|
||||
decodePpmDimensions(data)
|
||||
else:
|
||||
raise newException(PixieError, "Unsupported image file format")
|
||||
|
||||
proc decodeImage*(data: string): Image {.raises: [PixieError].} =
|
||||
## Loads an image from memory.
|
||||
if data.len > 8 and data.readUint64(0) == cast[uint64](pngSignature):
|
||||
|
@ -45,6 +64,15 @@ proc decodeMask*(data: string): Mask {.raises: [PixieError].} =
|
|||
else:
|
||||
raise newException(PixieError, "Unsupported mask file format")
|
||||
|
||||
proc readImageDimensions*(
|
||||
filePath: string
|
||||
): ImageDimensions {.inline, raises: [PixieError].} =
|
||||
## Loads an image from a file.
|
||||
try:
|
||||
decodeImageDimensions(readFile(filePath))
|
||||
except IOError as e:
|
||||
raise newException(PixieError, e.msg, e)
|
||||
|
||||
proc readImage*(filePath: string): Image {.inline, raises: [PixieError].} =
|
||||
## Loads an image from a file.
|
||||
try:
|
||||
|
|
|
@ -28,6 +28,9 @@ type
|
|||
SubtractMaskBlend ## Inverse mask
|
||||
ExcludeMaskBlend
|
||||
|
||||
ImageDimensions* = object
|
||||
width*, height*: int
|
||||
|
||||
proc mix*(a, b: uint8, t: float32): uint8 {.inline, raises: [].} =
|
||||
## Linearly interpolate between a and b using t.
|
||||
let t = round(t * 255).uint32
|
||||
|
|
|
@ -227,6 +227,21 @@ proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
|||
|
||||
decodeDib(data[14].unsafeAddr, data.len - 14)
|
||||
|
||||
proc decodeBmpDimensions*(
|
||||
data: string
|
||||
): ImageDimensions {.raises: [PixieError].} =
|
||||
## Decodes the BMP dimensions.
|
||||
|
||||
if data.len < 26:
|
||||
failInvalid()
|
||||
|
||||
# BMP Header
|
||||
if data[0 .. 1] != "BM":
|
||||
failInvalid()
|
||||
|
||||
result.width = data.readInt32(18).int
|
||||
result.height = abs(data.readInt32(22)).int
|
||||
|
||||
proc encodeBmp*(image: Image): string {.raises: [].} =
|
||||
## Encodes an image into the BMP file format.
|
||||
|
||||
|
|
|
@ -178,5 +178,18 @@ proc decodeGif*(data: string): Image {.raises: [PixieError].} =
|
|||
else:
|
||||
raise newException(PixieError, "Invalid GIF block type")
|
||||
|
||||
proc decodeGifDimensions*(
|
||||
data: string
|
||||
): ImageDimensions {.raises: [PixieError].} =
|
||||
## Decodes the GIF dimensions.
|
||||
if data.len < 10:
|
||||
failInvalid()
|
||||
|
||||
if data[0 .. 5] notin gifSignatures:
|
||||
raise newException(PixieError, "Invalid GIF file signature")
|
||||
|
||||
result.width = data.readInt16(6).int
|
||||
result.height = data.readInt16(8).int
|
||||
|
||||
when defined(release):
|
||||
{.pop.}
|
||||
|
|
|
@ -68,6 +68,7 @@ type
|
|||
len, pos: int
|
||||
bitsBuffered: int
|
||||
bitBuffer: uint32
|
||||
foundSOF: bool
|
||||
imageHeight, imageWidth: int
|
||||
progressive: bool
|
||||
quantizationTables: array[4, array[64, uint8]]
|
||||
|
@ -243,6 +244,10 @@ proc decodeDHT(state: var DecoderState) =
|
|||
|
||||
proc decodeSOF0(state: var DecoderState) =
|
||||
## Decode start of Frame
|
||||
if state.foundSOF:
|
||||
failInvalid()
|
||||
state.foundSOF = true
|
||||
|
||||
var len = state.readUint16be().int - 2
|
||||
|
||||
let precision = state.readUint8()
|
||||
|
@ -1056,7 +1061,7 @@ proc decodeJpeg*(data: string): Image {.raises: [PixieError].} =
|
|||
state.decodeDHT()
|
||||
of 0xD8:
|
||||
# SOI - Start of Image
|
||||
continue
|
||||
discard
|
||||
of 0xD9:
|
||||
# EOI - End of Image
|
||||
break
|
||||
|
@ -1094,5 +1099,63 @@ proc decodeJpeg*(data: string): Image {.raises: [PixieError].} =
|
|||
|
||||
state.buildImage()
|
||||
|
||||
proc decodeJpegDimensions*(
|
||||
data: string
|
||||
): ImageDimensions {.raises: [PixieError].} =
|
||||
## Decodes the JPEG dimensions.
|
||||
|
||||
var state = DecoderState()
|
||||
state.buffer = cast[ptr UncheckedArray[uint8]](data.cstring)
|
||||
state.len = data.len
|
||||
|
||||
while true:
|
||||
if state.readUint8() != 0xFF:
|
||||
failInvalid("invalid chunk marker")
|
||||
|
||||
let chunkId = state.readUint8()
|
||||
case chunkId:
|
||||
of 0xD8:
|
||||
# SOI - Start of Image
|
||||
discard
|
||||
of 0xC0:
|
||||
# Start Of Frame (Baseline DCT)
|
||||
state.decodeSOF0()
|
||||
break
|
||||
of 0xC1:
|
||||
# Start Of Frame (Extended sequential DCT)
|
||||
state.decodeSOF1()
|
||||
break
|
||||
of 0xC2:
|
||||
# Start Of Frame (Progressive DCT)
|
||||
state.decodeSOF2()
|
||||
break
|
||||
of 0xDB:
|
||||
# Define Quantization Table(s)
|
||||
state.skipChunk()
|
||||
of 0XE0:
|
||||
# Application-specific
|
||||
state.skipChunk()
|
||||
of 0xE1:
|
||||
# Exif/APP1
|
||||
state.decodeExif()
|
||||
of 0xE2..0xEF:
|
||||
# Application-specific
|
||||
state.skipChunk()
|
||||
of 0xFE:
|
||||
# Comment
|
||||
state.skipChunk()
|
||||
else:
|
||||
failInvalid("invalid chunk " & chunkId.toHex())
|
||||
|
||||
case state.orientation:
|
||||
of 0, 1, 2, 3, 4:
|
||||
result.width = state.imageWidth
|
||||
result.height = state.imageHeight
|
||||
of 5, 6, 7, 8:
|
||||
result.width = state.imageHeight
|
||||
result.height = state.imageWidth
|
||||
else:
|
||||
failInvalid("invalid orientation")
|
||||
|
||||
when defined(release):
|
||||
{.pop.}
|
||||
|
|
|
@ -90,7 +90,7 @@ proc decodePalette(data: string): seq[ColorRGB] =
|
|||
result.setLen(data.len div 3)
|
||||
|
||||
for i in 0 ..< data.len div 3:
|
||||
result[i] = cast[ptr ColorRGB](data[i * 3].unsafeAddr)[]
|
||||
copyMem(result[i].addr, data[i * 3].unsafeAddr, 3)
|
||||
|
||||
proc unfilter(
|
||||
uncompressed: string, height, rowBytes, bpp: int
|
||||
|
@ -262,21 +262,20 @@ proc decodeImageData(
|
|||
|
||||
# While we can read an extra byte safely, do so. Much faster.
|
||||
for i in 0 ..< header.height * header.width - 1:
|
||||
var rgba = cast[ptr ColorRGBA](unfiltered[i * 3].unsafeAddr)[]
|
||||
rgba.a = 255
|
||||
if rgba == special:
|
||||
rgba.a = 0
|
||||
result[i] = rgba
|
||||
copyMem(result[i].addr, unfiltered[i * 3].unsafeAddr, 4)
|
||||
result[i].a = 255
|
||||
if result[i] == special:
|
||||
result[i].a = 0
|
||||
else:
|
||||
# While we can read an extra byte safely, do so. Much faster.
|
||||
# var rgba: ColorRGBA
|
||||
for i in 0 ..< header.height * header.width - 1:
|
||||
var rgba = cast[ptr ColorRGBA](unfiltered[i * 3].unsafeAddr)[]
|
||||
rgba.a = 255
|
||||
result[i] = rgba
|
||||
copyMem(result[i].addr, unfiltered[i * 3].unsafeAddr, 4)
|
||||
result[i].a = 255
|
||||
|
||||
let
|
||||
lastOffset = header.height * header.width - 1
|
||||
rgb = cast[ptr array[3, uint8]](unfiltered[lastOffset * 3].unsafeAddr)[]
|
||||
let lastOffset = header.height * header.width - 1
|
||||
var rgb: array[3, uint8]
|
||||
copyMem(rgb.addr, unfiltered[lastOffset * 3].unsafeAddr, 3)
|
||||
var rgba = ColorRGBA(r: rgb[0], g: rgb[1], b: rgb[2], a: 255)
|
||||
if rgba == special:
|
||||
rgba.a = 0
|
||||
|
@ -342,6 +341,26 @@ proc newImage*(png: Png): Image {.raises: [PixieError].} =
|
|||
copyMem(result.data[0].addr, png.data[0].addr, png.data.len * 4)
|
||||
result.data.toPremultipliedAlpha()
|
||||
|
||||
proc decodePngDimensions*(
|
||||
data: string
|
||||
): ImageDimensions {.raises: [PixieError].} =
|
||||
## Decodes the PNG dimensions.
|
||||
if data.len < (8 + (8 + 13 + 4) + 4): # Magic bytes + IHDR + IEND
|
||||
failInvalid()
|
||||
|
||||
# PNG file signature
|
||||
let signature = cast[array[8, uint8]](data.readUint64(0))
|
||||
if signature != pngSignature:
|
||||
failInvalid()
|
||||
|
||||
# First chunk must be IHDR
|
||||
if data.readUint32(8).swap() != 13 or data.readStr(12, 4) != "IHDR":
|
||||
failInvalid()
|
||||
|
||||
let header = decodeHeader(data[16 ..< 16 + 13])
|
||||
result.width = header.width
|
||||
result.height = header.height
|
||||
|
||||
proc decodePng*(data: string): Png {.raises: [PixieError].} =
|
||||
## Decodes the PNG data.
|
||||
if data.len < (8 + (8 + 13 + 4) + 4): # Magic bytes + IHDR + IEND
|
||||
|
|
|
@ -135,6 +135,14 @@ proc decodePpm*(data: string): Image {.raises: [PixieError].} =
|
|||
else:
|
||||
decodeP6Data(data[header.dataOffset .. ^1], header.maxVal)
|
||||
|
||||
proc decodePpmDimensions*(
|
||||
data: string
|
||||
): ImageDimensions {.raises: [PixieError].} =
|
||||
## Decodes the PPM dimensions.
|
||||
let header = decodeHeader(data)
|
||||
result.width = header.width
|
||||
result.height = header.height
|
||||
|
||||
proc encodePpm*(image: Image): string {.raises: [].} =
|
||||
## Encodes an image into the PPM file format (version P6).
|
||||
|
||||
|
|
|
@ -121,6 +121,16 @@ proc decodeQoi*(data: string): Qoi {.raises: [PixieError].} =
|
|||
raise newException(PixieError, "Invalid QOI padding")
|
||||
inc(p)
|
||||
|
||||
proc decodeQoiDimensions*(
|
||||
data: string
|
||||
): ImageDimensions {.raises: [PixieError].} =
|
||||
## Decodes the QOI dimensions.
|
||||
if data.len <= 12 or data[0 .. 3] != qoiSignature:
|
||||
raise newException(PixieError, "Invalid QOI header")
|
||||
|
||||
result.width = data.readUint32(4).swap().int
|
||||
result.height = data.readUint32(8).swap().int
|
||||
|
||||
proc encodeQoi*(qoi: Qoi): string {.raises: [PixieError].} =
|
||||
## Encodes raw QOI pixels to the QOI file format.
|
||||
|
||||
|
|
|
@ -304,14 +304,13 @@ proc minifyBy2*(image: Image, power = 1): Image {.raises: [PixieError].} =
|
|||
b = src.unsafe[x * 2 + 1, y * 2 + 0]
|
||||
c = src.unsafe[x * 2 + 1, y * 2 + 1]
|
||||
d = src.unsafe[x * 2 + 0, y * 2 + 1]
|
||||
rgba = rgbx(
|
||||
mixed = rgbx(
|
||||
((a.r.uint32 + b.r + c.r + d.r) div 4).uint8,
|
||||
((a.g.uint32 + b.g + c.g + d.g) div 4).uint8,
|
||||
((a.b.uint32 + b.b + c.b + d.b) div 4).uint8,
|
||||
((a.a.uint32 + b.a + c.a + d.a) div 4).uint8
|
||||
)
|
||||
|
||||
result.unsafe[x, y] = rgba
|
||||
result.unsafe[x, y] = mixed
|
||||
|
||||
if srcWidthIsOdd:
|
||||
let rgbx = mix(
|
||||
|
@ -382,6 +381,8 @@ proc magnifyBy2*(image: Image, power = 1): Image {.raises: [PixieError].} =
|
|||
proc applyOpacity*(target: Image | Mask, opacity: float32) {.raises: [].} =
|
||||
## Multiplies alpha of the image by opacity.
|
||||
let opacity = round(255 * opacity).uint16
|
||||
if opacity == 255:
|
||||
return
|
||||
|
||||
if opacity == 0:
|
||||
when type(target) is Image:
|
||||
|
@ -434,12 +435,12 @@ proc applyOpacity*(target: Image | Mask, opacity: float32) {.raises: [].} =
|
|||
|
||||
when type(target) is Image:
|
||||
for j in i div 4 ..< target.data.len:
|
||||
var rgba = target.data[j]
|
||||
rgba.r = ((rgba.r * opacity) div 255).uint8
|
||||
rgba.g = ((rgba.g * opacity) div 255).uint8
|
||||
rgba.b = ((rgba.b * opacity) div 255).uint8
|
||||
rgba.a = ((rgba.a * opacity) div 255).uint8
|
||||
target.data[j] = rgba
|
||||
var rgbx = target.data[j]
|
||||
rgbx.r = ((rgbx.r * opacity) div 255).uint8
|
||||
rgbx.g = ((rgbx.g * opacity) div 255).uint8
|
||||
rgbx.b = ((rgbx.b * opacity) div 255).uint8
|
||||
rgbx.a = ((rgbx.a * opacity) div 255).uint8
|
||||
target.data[j] = rgbx
|
||||
else:
|
||||
for j in i ..< target.data.len:
|
||||
target.data[j] = ((target.data[j] * opacity) div 255).uint8
|
||||
|
|
|
@ -71,11 +71,11 @@ proc fillUnsafe*(
|
|||
else:
|
||||
when sizeof(int) == 8:
|
||||
# Fill 8 bytes at a time when possible
|
||||
let
|
||||
var
|
||||
u32 = cast[uint32](rgbx)
|
||||
u64 = cast[uint64]([u32, u32])
|
||||
for _ in 0 ..< len div 2:
|
||||
cast[ptr uint64](data[i].addr)[] = u64
|
||||
copyMem(data[i].addr, u64.addr, 8)
|
||||
i += 2
|
||||
# Fill whatever is left the slow way
|
||||
for j in i ..< start + len:
|
||||
|
|
|
@ -2,5 +2,5 @@ import benchy, pixie/fileformats/gif
|
|||
|
||||
let data = readFile("tests/fileformats/gif/audrey.gif")
|
||||
|
||||
timeIt "pixie decode":
|
||||
keep decodeGif(data)
|
||||
timeIt "gif decode":
|
||||
discard decodeGif(data)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import chroma, os, pixie, pixie/fileformats/bmp, strutils
|
||||
import os, pixie/fileformats/bmp
|
||||
|
||||
# block:
|
||||
# var image = newImage(4, 2)
|
||||
|
@ -32,9 +32,9 @@ import chroma, os, pixie, pixie/fileformats/bmp, strutils
|
|||
|
||||
block:
|
||||
for bits in [32, 24]:
|
||||
let image = decodeBmp(readFile(
|
||||
"tests/fileformats/bmp/knight." & $bits & ".master.bmp"
|
||||
))
|
||||
let
|
||||
path = "tests/fileformats/bmp/knight." & $bits & ".master.bmp"
|
||||
image = decodeBmp(readFile(path))
|
||||
writeFile("tests/fileformats/bmp/knight." & $bits & ".bmp", encodeBmp(image))
|
||||
|
||||
block:
|
||||
|
@ -46,5 +46,9 @@ block:
|
|||
block:
|
||||
for file in walkFiles("tests/fileformats/bmp/bmpsuite/*"):
|
||||
# echo file
|
||||
let image = decodeBmp(readFile(file))
|
||||
let
|
||||
image = decodeBmp(readFile(file))
|
||||
dimensions = decodeBmpDimensions(readFile(file))
|
||||
#image.writeFile(file.replace("bmpsuite", "output") & ".png")
|
||||
doAssert image.width == dimensions.width
|
||||
doAssert image.height == dimensions.height
|
||||
|
|
|
@ -1,13 +1,37 @@
|
|||
import pixie, pixie/fileformats/gif
|
||||
|
||||
var img = decodeGIF(readFile("tests/fileformats/gif/3x5.gif"))
|
||||
img.writeFile("tests/fileformats/gif/3x5.png")
|
||||
block:
|
||||
let
|
||||
path = "tests/fileformats/gif/3x5.gif"
|
||||
image = decodeGIF(readFile(path))
|
||||
dimensions = decodeGifDimensions(readFile(path))
|
||||
image.writeFile("tests/fileformats/gif/3x5.png")
|
||||
doAssert image.width == dimensions.width
|
||||
doAssert image.height == dimensions.height
|
||||
|
||||
var img2 = decodeGIF(readFile("tests/fileformats/gif/audrey.gif"))
|
||||
img2.writeFile("tests/fileformats/gif/audrey.png")
|
||||
block:
|
||||
let
|
||||
path = "tests/fileformats/gif/audrey.gif"
|
||||
image = decodeGIF(readFile(path))
|
||||
dimensions = decodeGifDimensions(readFile(path))
|
||||
image.writeFile("tests/fileformats/gif/audrey.png")
|
||||
doAssert image.width == dimensions.width
|
||||
doAssert image.height == dimensions.height
|
||||
|
||||
var img3 = decodeGIF(readFile("tests/fileformats/gif/sunflower.gif"))
|
||||
img3.writeFile("tests/fileformats/gif/sunflower.png")
|
||||
block:
|
||||
let
|
||||
path = "tests/fileformats/gif/sunflower.gif"
|
||||
image = decodeGIF(readFile(path))
|
||||
dimensions = decodeGifDimensions(readFile(path))
|
||||
image.writeFile("tests/fileformats/gif/sunflower.png")
|
||||
doAssert image.width == dimensions.width
|
||||
doAssert image.height == dimensions.height
|
||||
|
||||
var img4 = readImage("tests/fileformats/gif/sunflower.gif")
|
||||
doAssert img3.data == img4.data
|
||||
block:
|
||||
let
|
||||
path = "tests/fileformats/gif/sunflower.gif"
|
||||
image = decodeGIF(readFile(path))
|
||||
dimensions = decodeGifDimensions(readFile(path))
|
||||
image.writeFile("tests/fileformats/gif/sunflower.png")
|
||||
doAssert image.width == dimensions.width
|
||||
doAssert image.height == dimensions.height
|
||||
|
|
|
@ -203,6 +203,17 @@ block:
|
|||
image.fill(rgba(255, 255, 255, 255))
|
||||
doAssert not image.isTransparent()
|
||||
|
||||
block:
|
||||
let image = newImage(100, 100)
|
||||
image.fill(rgba(255, 255, 255, 255))
|
||||
doAssert image.isOpaque()
|
||||
|
||||
block:
|
||||
let image = newImage(100, 100)
|
||||
image.fill(rgba(255, 255, 255, 255))
|
||||
image[9, 13] = rgbx(250, 250, 250, 250)
|
||||
doAssert not image.isOpaque()
|
||||
|
||||
block:
|
||||
let a = newImage(400, 400)
|
||||
let b = newImage(156, 434)
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import jpegsuite, pixie
|
||||
import jpegsuite, pixie, pixie/fileformats/jpeg
|
||||
|
||||
for file in jpegSuiteFiles:
|
||||
let img = readImage(file)
|
||||
let
|
||||
image = readImage(file)
|
||||
dimensions = decodeJpegDimensions(readFile(file))
|
||||
doAssert image.width == dimensions.width
|
||||
doAssert image.height == dimensions.height
|
||||
|
|
|
@ -33,3 +33,9 @@ block:
|
|||
|
||||
block:
|
||||
discard readImage("tests/fileformats/png/trailing_data.png")
|
||||
|
||||
block:
|
||||
let dimensions =
|
||||
decodeImageDimensions(readFile("tests/fileformats/png/mandrill.png"))
|
||||
doAssert dimensions.width == 512
|
||||
doAssert dimensions.height == 512
|
||||
|
|
|
@ -2,13 +2,22 @@ import pixie/fileformats/ppm
|
|||
|
||||
block:
|
||||
for format in @["p3", "p6"]:
|
||||
let image = decodePpm(readFile(
|
||||
"tests/fileformats/ppm/feep." & $format & ".master.ppm"
|
||||
))
|
||||
let
|
||||
path = "tests/fileformats/ppm/feep." & $format & ".master.ppm"
|
||||
image = decodePpm(readFile(path))
|
||||
dimensions = decodePpmDimensions(readFile(path))
|
||||
writeFile("tests/fileformats/ppm/feep." & $format & ".ppm", encodePpm(image))
|
||||
doAssert image.width == dimensions.width
|
||||
doAssert image.height == dimensions.height
|
||||
|
||||
let image = decodePpm(readFile("tests/fileformats/ppm/feep.p3.hidepth.master.ppm"))
|
||||
block:
|
||||
let
|
||||
path = "tests/fileformats/ppm/feep.p3.hidepth.master.ppm"
|
||||
image = decodePpm(readFile(path))
|
||||
dimensions = decodePpmDimensions(readFile(path))
|
||||
writeFile("tests/fileformats/ppm/feep.p3.hidepth.ppm", encodePpm(image))
|
||||
doAssert image.width == dimensions.width
|
||||
doAssert image.height == dimensions.height
|
||||
|
||||
# produced output should be identical to P6 master
|
||||
let p6Master = readFile("tests/fileformats/ppm/feep.p6.master.ppm")
|
||||
|
|
|
@ -4,14 +4,19 @@ const tests = ["testcard", "testcard_rgba"]
|
|||
|
||||
for name in tests:
|
||||
let
|
||||
input = readImage("tests/fileformats/qoi/" & name & ".qoi")
|
||||
path = "tests/fileformats/qoi/" & name & ".qoi"
|
||||
input = readImage(path)
|
||||
control = readImage("tests/fileformats/qoi/" & name & ".png")
|
||||
dimensions = decodeQoiDimensions(readFile(path))
|
||||
doAssert input.data == control.data, "input mismatch of " & name
|
||||
doAssert input.width == dimensions.width
|
||||
doAssert input.height == dimensions.height
|
||||
discard encodeQoi(control)
|
||||
|
||||
for name in tests:
|
||||
let
|
||||
input = decodeQoi(readFile("tests/fileformats/qoi/" & name & ".qoi"))
|
||||
path = "tests/fileformats/qoi/" & name & ".qoi"
|
||||
input = decodeQoi(readFile(path))
|
||||
output = decodeQoi(encodeQoi(input))
|
||||
doAssert output.data.len == input.data.len
|
||||
doAssert output.data == input.data
|
||||
|
|
Loading…
Reference in a new issue