Merge pull request #425 from guzba/master

random things
This commit is contained in:
treeform 2022-05-21 19:23:00 -07:00 committed by GitHub
commit fe1b1483a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 136 additions and 152 deletions

View file

@ -11,7 +11,7 @@ requires "chroma >= 0.2.5"
requires "zippy >= 0.9.7" requires "zippy >= 0.9.7"
requires "flatty >= 0.3.0" requires "flatty >= 0.3.0"
requires "nimsimd >= 1.0.0" requires "nimsimd >= 1.0.0"
requires "bumpy >= 1.1.0" requires "bumpy >= 1.1.1"
task bindings, "Generate bindings": task bindings, "Generate bindings":

View file

@ -21,18 +21,18 @@ converter autoPremultipliedAlpha*(c: ColorRGBA): ColorRGBX {.inline, raises: [].
proc decodeImage*(data: string): Image {.raises: [PixieError].} = proc decodeImage*(data: string): Image {.raises: [PixieError].} =
## Loads an image from memory. ## Loads an image from memory.
if data.len > 8 and data.readUint64(0) == cast[uint64](pngSignature): if data.len > 8 and data.readUint64(0) == cast[uint64](pngSignature):
decodePng(data) newImage(decodePng(data))
elif data.len > 2 and data.readUint16(0) == cast[uint16](jpegStartOfImage): elif data.len > 2 and data.readUint16(0) == cast[uint16](jpegStartOfImage):
decodeJpeg(data) decodeJpeg(data)
elif data.len > 2 and data.readStr(0, 2) == bmpSignature: elif data.len > 2 and data.readStr(0, 2) == bmpSignature:
decodeBmp(data) decodeBmp(data)
elif data.len > 5 and elif data.len > 5 and
(data.readStr(0, 5) == xmlSignature or data.readStr(0, 4) == svgSignature): (data.readStr(0, 5) == xmlSignature or data.readStr(0, 4) == svgSignature):
decodeSvg(data) newImage(parseSvg(data))
elif data.len > 6 and data.readStr(0, 6) in gifSignatures: elif data.len > 6 and data.readStr(0, 6) in gifSignatures:
decodeGif(data) decodeGif(data)
elif data.len > (14+8) and data.readStr(0, 4) == qoiSignature: elif data.len > (14+8) and data.readStr(0, 4) == qoiSignature:
decodeQoi(data) newImage(decodeQoi(data))
elif data.len > 9 and data.readStr(0, 2) in ppmSignatures: elif data.len > 9 and data.readStr(0, 2) in ppmSignatures:
decodePpm(data) decodePpm(data)
else: else:
@ -41,7 +41,7 @@ proc decodeImage*(data: string): Image {.raises: [PixieError].} =
proc decodeMask*(data: string): Mask {.raises: [PixieError].} = proc decodeMask*(data: string): Mask {.raises: [PixieError].} =
## Loads a mask from memory. ## Loads a mask from memory.
if data.len > 8 and data.readUint64(0) == cast[uint64](pngSignature): if data.len > 8 and data.readUint64(0) == cast[uint64](pngSignature):
newMask(decodePng(data)) newMask(newImage(decodePng(data)))
else: else:
raise newException(PixieError, "Unsupported mask file format") raise newException(PixieError, "Unsupported mask file format")

View file

@ -7,7 +7,6 @@ import bumpy, chroma, pixie/common, pixie/fonts, pixie/images, pixie/masks,
## https://developer.mozilla.org/en-US/docs/Web/API/ContextRenderingContext2D ## https://developer.mozilla.org/en-US/docs/Web/API/ContextRenderingContext2D
type type
BaselineAlignment* = enum BaselineAlignment* = enum
TopBaseline TopBaseline
HangingBaseline HangingBaseline

View file

@ -342,7 +342,7 @@ proc newImage*(png: Png): Image {.raises: [PixieError].} =
copyMem(result.data[0].addr, png.data[0].addr, png.data.len * 4) copyMem(result.data[0].addr, png.data[0].addr, png.data.len * 4)
result.data.toPremultipliedAlpha() result.data.toPremultipliedAlpha()
proc decodePngRaw*(data: string): Png {.raises: [PixieError].} = proc decodePng*(data: string): Png {.raises: [PixieError].} =
## Decodes the PNG data. ## Decodes the PNG data.
if data.len < (8 + (8 + 13 + 4) + 4): # Magic bytes + IHDR + IEND if data.len < (8 + (8 + 13 + 4) + 4): # Magic bytes + IHDR + IEND
failInvalid() failInvalid()
@ -450,10 +450,6 @@ proc decodePngRaw*(data: string): Png {.raises: [PixieError].} =
result.channels = 4 result.channels = 4
result.data = decodeImageData(data, header, palette, transparency, idats) result.data = decodeImageData(data, header, palette, transparency, idats)
proc decodePng*(data: string): Image {.raises: [PixieError].} =
## Decodes the PNG data into an Image.
newImage(decodePngRaw(data))
proc encodePng*( proc encodePng*(
width, height, channels: int, data: pointer, len: int width, height, channels: int, data: pointer, len: int
): string {.raises: [PixieError].} = ): string {.raises: [PixieError].} =

View file

@ -35,7 +35,7 @@ func newImage*(qoi: Qoi): Image =
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()
proc decodeQoiRaw*(data: string): Qoi {.raises: [PixieError].} = proc decodeQoi*(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")
@ -121,10 +121,6 @@ proc decodeQoiRaw*(data: string): Qoi {.raises: [PixieError].} =
raise newException(PixieError, "Invalid QOI padding") raise newException(PixieError, "Invalid QOI padding")
inc(p) inc(p)
proc decodeQoi*(data: string): Image {.raises: [PixieError].} =
## Decodes data in the QOI file format to an `Image`.
newImage(decodeQoiRaw(data))
proc encodeQoi*(qoi: Qoi): string {.raises: [PixieError].} = proc encodeQoi*(qoi: Qoi): string {.raises: [PixieError].} =
## Encodes raw QOI pixels to the QOI file format. ## Encodes raw QOI pixels to the QOI file format.

View file

@ -11,14 +11,15 @@ const
svgSignature* = "<svg" svgSignature* = "<svg"
type type
LinearGradient = object Svg* = ref object
x1, y1, x2, y2: float32 width*, height*: int
stops: seq[ColorStop] elements: seq[(Path, SvgProperties)]
linearGradients: Table[string, LinearGradient]
Ctx = object SvgProperties = object
display: bool display: bool
fillRule: WindingRule fillRule: WindingRule
fill: Paint fill: string
stroke: ColorRGBX stroke: ColorRGBX
strokeWidth: float32 strokeWidth: float32
strokeLineCap: LineCap strokeLineCap: LineCap
@ -26,9 +27,11 @@ type
strokeMiterLimit: float32 strokeMiterLimit: float32
strokeDashArray: seq[float32] strokeDashArray: seq[float32]
transform: Mat3 transform: Mat3
shouldStroke: bool opacity, fillOpacity, strokeOpacity: float32
opacity, strokeOpacity: float32
linearGradients: TableRef[string, LinearGradient] LinearGradient = object
x1, y1, x2, y2: float32
stops: seq[ColorStop]
template failInvalid() = template failInvalid() =
raise newException(PixieError, "Invalid SVG data") raise newException(PixieError, "Invalid SVG data")
@ -38,21 +41,17 @@ proc attrOrDefault(node: XmlNode, name, default: string): string =
if result.len == 0: if result.len == 0:
result = default result = default
proc initCtx(): Ctx = proc initSvgProperties(): SvgProperties =
result.display = true result.display = true
try: result.fill = "black"
result.fill = parseHtmlColor("black").rgbx
result.stroke = parseHtmlColor("black").rgbx
except:
raise currentExceptionAsPixieError()
result.strokeWidth = 1 result.strokeWidth = 1
result.transform = mat3() result.transform = mat3()
result.strokeMiterLimit = defaultMiterLimit result.strokeMiterLimit = defaultMiterLimit
result.opacity = 1 result.opacity = 1
result.fillOpacity = 1
result.strokeOpacity = 1 result.strokeOpacity = 1
result.linearGradients = newTable[string, LinearGradient]()
proc decodeCtxInternal(inherited: Ctx, node: XmlNode): Ctx = proc parseSvgProperties(node: XmlNode, inherited: SvgProperties): SvgProperties =
result = inherited result = inherited
proc splitArgs(s: string): seq[string] = proc splitArgs(s: string): seq[string] =
@ -162,36 +161,22 @@ proc decodeCtxInternal(inherited: Ctx, node: XmlNode): Ctx =
) )
if fill == "" or fill == "currentColor": if fill == "" or fill == "currentColor":
discard # Inherit result.fill = inherited.fill
elif fill == "none":
result.fill = ColorRGBX()
elif fill.startsWith("url("):
let id = fill[5 .. ^2]
if id in result.linearGradients:
let linearGradient = result.linearGradients[id]
result.fill = newPaint(LinearGradientPaint)
result.fill.gradientHandlePositions = @[
result.transform * vec2(linearGradient.x1, linearGradient.y1),
result.transform * vec2(linearGradient.x2, linearGradient.y2)
]
result.fill.gradientStops = linearGradient.stops
else:
raise newException(PixieError, "Missing SVG resource " & id)
else: else:
result.fill = parseHtmlColor(fill).rgbx result.fill = fill
if stroke == "": if stroke == "":
discard # Inherit discard # Inherit
elif stroke == "currentColor": elif stroke == "currentColor":
result.shouldStroke = true if result.stroke == rgbx(0, 0, 0, 0):
result.stroke = rgbx(0, 0, 0, 255)
elif stroke == "none": elif stroke == "none":
result.stroke = ColorRGBX() result.stroke = ColorRGBX()
else: else:
result.stroke = parseHtmlColor(stroke).rgbx result.stroke = parseHtmlColor(stroke).rgbx
result.shouldStroke = true
if fillOpacity.len > 0: if fillOpacity.len > 0:
result.fill.opacity = parseFloat(fillOpacity).clamp(0, 1) result.fillOpacity = parseFloat(fillOpacity).clamp(0, 1)
if strokeOpacity.len > 0: if strokeOpacity.len > 0:
result.strokeOpacity = parseFloat(strokeOpacity).clamp(0, 1) result.strokeOpacity = parseFloat(strokeOpacity).clamp(0, 1)
@ -202,10 +187,8 @@ proc decodeCtxInternal(inherited: Ctx, node: XmlNode): Ctx =
if strokeWidth.endsWith("px"): if strokeWidth.endsWith("px"):
strokeWidth = strokeWidth[0 .. ^3] strokeWidth = strokeWidth[0 .. ^3]
result.strokeWidth = parseFloat(strokeWidth) result.strokeWidth = parseFloat(strokeWidth)
result.shouldStroke = true if result.stroke == rgbx(0, 0, 0, 0):
result.stroke = rgbx(0, 0, 0, 255)
if result.stroke == ColorRGBX() or result.strokeWidth <= 0:
result.shouldStroke = false
if strokeLineCap == "": if strokeLineCap == "":
discard # Inherit discard # Inherit
@ -316,36 +299,9 @@ proc decodeCtxInternal(inherited: Ctx, node: XmlNode): Ctx =
else: else:
failInvalidTransform(transform) failInvalidTransform(transform)
proc decodeCtx(inherited: Ctx, node: XmlNode): Ctx = proc parseSvgElement(
try: node: XmlNode, svg: Svg, propertiesStack: var seq[SvgProperties]
decodeCtxInternal(inherited, node) ): seq[(Path, SvgProperties)] =
except PixieError as e:
raise e
except:
raise currentExceptionAsPixieError()
proc fill(img: Image, ctx: Ctx, path: Path) {.inline.} =
if ctx.display and ctx.opacity > 0:
let paint = newPaint(ctx.fill)
paint.opacity = paint.opacity * ctx.opacity
img.fillPath(path, paint, ctx.transform, ctx.fillRule)
proc stroke(img: Image, ctx: Ctx, path: Path) {.inline.} =
if ctx.display and ctx.opacity > 0:
let paint = newPaint(ctx.stroke)
paint.color.a *= (ctx.opacity * ctx.strokeOpacity)
img.strokePath(
path,
paint,
ctx.transform,
ctx.strokeWidth,
ctx.strokeLineCap,
ctx.strokeLineJoin,
miterLimit = ctx.strokeMiterLimit,
dashes = ctx.strokeDashArray
)
proc drawInternal(img: Image, node: XmlNode, ctxStack: var seq[Ctx]) =
if node.kind != xnElement: if node.kind != xnElement:
# Skip <!-- comments --> # Skip <!-- comments -->
return return
@ -359,25 +315,23 @@ proc drawInternal(img: Image, node: XmlNode, ctxStack: var seq[Ctx]) =
echo node echo node
of "g": of "g":
let ctx = decodeCtx(ctxStack[^1], node) let props = node.parseSvgProperties(propertiesStack[^1])
ctxStack.add(ctx) propertiesStack.add(props)
for child in node: for child in node:
img.drawInternal(child, ctxStack) result.add child.parseSvgElement(svg, propertiesStack)
discard ctxStack.pop() discard propertiesStack.pop()
of "path": of "path":
let let
d = node.attr("d") d = node.attr("d")
ctx = decodeCtx(ctxStack[^1], node) props = node.parseSvgProperties(propertiesStack[^1])
path = parsePath(d) path = parsePath(d)
img.fill(ctx, path) result.add (path, props)
if ctx.shouldStroke:
img.stroke(ctx, path)
of "line": of "line":
let let
ctx = decodeCtx(ctxStack[^1], node) props = node.parseSvgProperties(propertiesStack[^1])
x1 = parseFloat(node.attrOrDefault("x1", "0")) x1 = parseFloat(node.attrOrDefault("x1", "0"))
y1 = parseFloat(node.attrOrDefault("y1", "0")) y1 = parseFloat(node.attrOrDefault("y1", "0"))
x2 = parseFloat(node.attrOrDefault("x2", "0")) x2 = parseFloat(node.attrOrDefault("x2", "0"))
@ -387,12 +341,11 @@ proc drawInternal(img: Image, node: XmlNode, ctxStack: var seq[Ctx]) =
path.moveTo(x1, y1) path.moveTo(x1, y1)
path.lineTo(x2, y2) path.lineTo(x2, y2)
if ctx.shouldStroke: result.add (path, props)
img.stroke(ctx, path)
of "polyline", "polygon": of "polyline", "polygon":
let let
ctx = decodeCtx(ctxStack[^1], node) props = node.parseSvgProperties(propertiesStack[^1])
points = node.attr("points") points = node.attr("points")
var vecs: seq[Vec2] var vecs: seq[Vec2]
@ -421,14 +374,12 @@ proc drawInternal(img: Image, node: XmlNode, ctxStack: var seq[Ctx]) =
# and fill or not # and fill or not
if node.tag == "polygon": if node.tag == "polygon":
path.closePath() path.closePath()
img.fill(ctx, path)
if ctx.shouldStroke: result.add (path, props)
img.stroke(ctx, path)
of "rect": of "rect":
let let
ctx = decodeCtx(ctxStack[^1], node) props = node.parseSvgProperties(propertiesStack[^1])
x = parseFloat(node.attrOrDefault("x", "0")) x = parseFloat(node.attrOrDefault("x", "0"))
y = parseFloat(node.attrOrDefault("y", "0")) y = parseFloat(node.attrOrDefault("y", "0"))
width = parseFloat(node.attrOrDefault("width", "0")) width = parseFloat(node.attrOrDefault("width", "0"))
@ -462,13 +413,11 @@ proc drawInternal(img: Image, node: XmlNode, ctxStack: var seq[Ctx]) =
else: else:
path.rect(x, y, width, height) path.rect(x, y, width, height)
img.fill(ctx, path) result.add (path, props)
if ctx.shouldStroke:
img.stroke(ctx, path)
of "circle", "ellipse": of "circle", "ellipse":
let let
ctx = decodeCtx(ctxStack[^1], node) props = node.parseSvgProperties(propertiesStack[^1])
cx = parseFloat(node.attrOrDefault("cx", "0")) cx = parseFloat(node.attrOrDefault("cx", "0"))
cy = parseFloat(node.attrOrDefault("cy", "0")) cy = parseFloat(node.attrOrDefault("cy", "0"))
@ -483,16 +432,14 @@ proc drawInternal(img: Image, node: XmlNode, ctxStack: var seq[Ctx]) =
let path = newPath() let path = newPath()
path.ellipse(cx, cy, rx, ry) path.ellipse(cx, cy, rx, ry)
img.fill(ctx, path) result.add (path, props)
if ctx.shouldStroke:
img.stroke(ctx, path)
of "radialGradient": of "radialGradient":
discard discard
of "linearGradient": of "linearGradient":
let let
ctx = decodeCtx(ctxStack[^1], node) props = node.parseSvgProperties(propertiesStack[^1])
id = node.attr("id") id = node.attr("id")
gradientUnits = node.attr("gradientUnits") gradientUnits = node.attr("gradientUnits")
gradientTransform = node.attr("gradientTransform") gradientTransform = node.attr("gradientTransform")
@ -547,23 +494,15 @@ proc drawInternal(img: Image, node: XmlNode, ctxStack: var seq[Ctx]) =
else: else:
raise newException(PixieError, "Unexpected SVG tag: " & child.tag) raise newException(PixieError, "Unexpected SVG tag: " & child.tag)
ctx.linearGradients[id] = linearGradient svg.linearGradients[id] = linearGradient
else: else:
raise newException(PixieError, "Unsupported SVG tag: " & node.tag) raise newException(PixieError, "Unsupported SVG tag: " & node.tag)
proc draw(img: Image, node: XmlNode, ctxStack: var seq[Ctx]) = proc parseSvg*(
try:
drawInternal(img, node, ctxStack)
except PixieError as e:
raise e
except:
raise currentExceptionAsPixieError()
proc decodeSvg*(
data: string | XmlNode, width = 0, height = 0 data: string | XmlNode, width = 0, height = 0
): Image {.raises: [PixieError].} = ): Svg {.raises: [PixieError].} =
## Render SVG XML and return the image. Defaults to the SVG's view box size. ## Parse SVG XML. Defaults to the SVG's view box size.
try: try:
let root = parseXml(data) let root = parseXml(data)
if root.tag != "svg": if root.tag != "svg":
@ -577,27 +516,81 @@ proc decodeSvg*(
viewBoxWidth = parseInt(box[2]) viewBoxWidth = parseInt(box[2])
viewBoxHeight = parseInt(box[3]) viewBoxHeight = parseInt(box[3])
var rootCtx = initCtx() var rootProps = initSvgProperties()
rootCtx = decodeCtx(rootCtx, root) rootProps = root.parseSvgProperties(rootProps)
if viewBoxMinX != 0 or viewBoxMinY != 0: if viewBoxMinX != 0 or viewBoxMinY != 0:
let viewBoxMin = vec2(-viewBoxMinX.float32, -viewBoxMinY.float32) let viewBoxMin = vec2(-viewBoxMinX.float32, -viewBoxMinY.float32)
rootCtx.transform = rootCtx.transform * translate(viewBoxMin) rootprops.transform = rootprops.transform * translate(viewBoxMin)
result = Svg()
if width == 0 and height == 0: # Default to the view box size if width == 0 and height == 0: # Default to the view box size
result = newImage(viewBoxWidth, viewBoxHeight) result.width = viewBoxWidth
result.height = viewBoxHeight
else: else:
result = newImage(width, height) result.width = width
result.height = height
let let
scaleX = width.float32 / viewBoxWidth.float32 scaleX = width.float32 / viewBoxWidth.float32
scaleY = height.float32 / viewBoxHeight.float32 scaleY = height.float32 / viewBoxHeight.float32
rootCtx.transform = rootCtx.transform * scale(vec2(scaleX, scaleY)) rootprops.transform = rootprops.transform * scale(vec2(scaleX, scaleY))
var ctxStack = @[rootCtx] var propertiesStack = @[rootProps]
for node in root.items: for node in root.items:
result.draw(node, ctxStack) result.elements.add node.parseSvgElement(result, propertiesStack)
except PixieError as e: except PixieError as e:
raise e raise e
except: except:
raise newException(PixieError, "Unable to load SVG") raise currentExceptionAsPixieError()
proc newImage*(svg: Svg): Image {.raises: [PixieError].} =
## Render SVG and return the image.
result = newImage(svg.width, svg.height)
try:
for (path, props) in svg.elements:
if props.display and props.opacity > 0:
if props.fill != "none":
var paint: Paint
if props.fill.startsWith("url("):
let closingParen = props.fill.find(")", 5)
if closingParen == -1:
raise newException(PixieError, "Malformed fill: " & props.fill)
let id = props.fill[5 .. closingParen - 1]
if id in svg.linearGradients:
let linearGradient = svg.linearGradients[id]
paint = newPaint(LinearGradientPaint)
paint.gradientHandlePositions = @[
props.transform * vec2(linearGradient.x1, linearGradient.y1),
props.transform * vec2(linearGradient.x2, linearGradient.y2)
]
paint.gradientStops = linearGradient.stops
else:
raise newException(PixieError, "Missing SVG resource " & id)
else:
paint = parseHtmlColor(props.fill).rgbx
paint.opacity = props.fillOpacity * props.opacity
result.fillPath(path, paint, props.transform, props.fillRule)
if props.stroke != rgbx(0, 0, 0, 0) and props.strokeWidth > 0:
let paint = newPaint(props.stroke)
paint.color.a *= (props.opacity * props.strokeOpacity)
result.strokePath(
path,
paint,
props.transform,
props.strokeWidth,
props.strokeLineCap,
props.strokeLineJoin,
miterLimit = props.strokeMiterLimit,
dashes = props.strokeDashArray
)
except PixieError as e:
raise e
except:
raise currentExceptionAsPixieError()

View file

@ -637,11 +637,12 @@ proc polygon*(
if sides <= 2: if sides <= 2:
raise newException(PixieError, "Invalid polygon sides value") raise newException(PixieError, "Invalid polygon sides value")
path.moveTo(x + size * sin(0.0), y - size * cos(0.0)) path.moveTo(x + size * sin(0.0), y - size * cos(0.0))
for side in 1 .. sides: for side in 1 .. sides - 1:
path.lineTo( path.lineTo(
x + size * sin(side.float32 * 2.0 * PI / sides.float32), x + size * sin(side.float32 * 2.0 * PI / sides.float32),
y - size * cos(side.float32 * 2.0 * PI / sides.float32) y - size * cos(side.float32 * 2.0 * PI / sides.float32)
) )
path.closePath()
proc polygon*( proc polygon*(
path: Path, pos: Vec2, size: float32, sides: int path: Path, pos: Vec2, size: float32, sides: int

View file

@ -1,6 +1,6 @@
import benchy, jpegsuite, pixie/fileformats/jpg, strformat import benchy, jpegsuite, pixie/fileformats/jpeg, strformat
for file in jpegSuiteFiles: for file in jpegSuiteFiles:
let data = readFile(file) let data = readFile(file)
timeIt &"jpeg {(data.len div 1024)}k decode": timeIt &"jpeg {(data.len div 1024)}k decode":
discard decodeJpg(data) discard decodeJpeg(data)

View file

@ -2,5 +2,5 @@ import benchy, pixie/fileformats/svg
let data = readFile("tests/fileformats/svg/Ghostscript_Tiger.svg") let data = readFile("tests/fileformats/svg/Ghostscript_Tiger.svg")
timeIt "svg decode": timeIt "svg parse + render":
discard decodeSvg(data) discard newImage(parseSvg(data))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 782 KiB

After

Width:  |  Height:  |  Size: 787 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 MiB

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 519 KiB

After

Width:  |  Height:  |  Size: 519 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

After

Width:  |  Height:  |  Size: 3.9 MiB

View file

@ -35,7 +35,7 @@ proc renderEmojiSet(index: int) =
let (_, name, _) = splitFile(filePath) let (_, name, _) = splitFile(filePath)
var image: Image var image: Image
try: try:
image = decodeSvg(readFile(filePath), width, height) image = newImage(parseSvg(readFile(filePath), width, height))
except PixieError: except PixieError:
echo &"Failed decoding {name}" echo &"Failed decoding {name}"
image = newImage(width, height) image = newImage(width, height)

View file

@ -38,7 +38,7 @@ proc renderIconSet(index: int) =
for filePath in walkFiles(iconSet.path): for filePath in walkFiles(iconSet.path):
let let
(_, name, _) = splitFile(filePath) (_, name, _) = splitFile(filePath)
image = decodeSvg(readFile(filePath), width, height) image = newImage(parseSvg(readFile(filePath), width, height))
images.add((name, image)) images.add((name, image))

View file

@ -1,4 +1,4 @@
import chroma, pixie, pixie/fileformats/png, vmath import chroma, pixie, vmath
const heartShape = """ const heartShape = """
M 10,30 M 10,30
@ -18,7 +18,7 @@ block:
block: block:
let paint = newPaint(ImagePaint) let paint = newPaint(ImagePaint)
paint.image = decodePng(readFile("tests/fileformats/png/mandrill.png")) paint.image = readImage("tests/fileformats/png/mandrill.png")
paint.imageMat = scale(vec2(0.2, 0.2)) paint.imageMat = scale(vec2(0.2, 0.2))
let image = newImage(100, 100) let image = newImage(100, 100)
@ -27,7 +27,7 @@ block:
block: block:
let paint = newPaint(ImagePaint) let paint = newPaint(ImagePaint)
paint.image = decodePng(readFile("tests/fileformats/png/mandrill.png")) paint.image = readImage("tests/fileformats/png/mandrill.png")
paint.imageMat = scale(vec2(0.2, 0.2)) paint.imageMat = scale(vec2(0.2, 0.2))
paint.opacity = 0.5 paint.opacity = 0.5
@ -37,7 +37,7 @@ block:
block: block:
let paint = newPaint(TiledImagePaint) let paint = newPaint(TiledImagePaint)
paint.image = decodePng(readFile("tests/fileformats/png/mandrill.png")) paint.image = readImage("tests/fileformats/png/mandrill.png")
paint.imageMat = scale(vec2(0.02, 0.02)) paint.imageMat = scale(vec2(0.02, 0.02))
let image = newImage(100, 100) let image = newImage(100, 100)
@ -46,7 +46,7 @@ block:
block: block:
let paint = newPaint(TiledImagePaint) let paint = newPaint(TiledImagePaint)
paint.image = decodePng(readFile("tests/fileformats/png/mandrill.png")) paint.image = readImage("tests/fileformats/png/mandrill.png")
paint.imageMat = scale(vec2(0.02, 0.02)) paint.imageMat = scale(vec2(0.02, 0.02))
paint.opacity = 0.5 paint.opacity = 0.5

View file

@ -1,17 +1,17 @@
import pixie, pixie/fileformats/png, pixie/fileformats/qoi import pixie, pixie/fileformats/qoi
const tests = ["testcard", "testcard_rgba"] const tests = ["testcard", "testcard_rgba"]
for name in tests: for name in tests:
let let
input = decodeQoi(readFile("tests/fileformats/qoi/" & name & ".qoi")) input = readImage("tests/fileformats/qoi/" & name & ".qoi")
control = decodePng(readFile("tests/fileformats/qoi/" & name & ".png")) control = readImage("tests/fileformats/qoi/" & name & ".png")
doAssert input.data == control.data, "input mismatch of " & name doAssert input.data == control.data, "input mismatch of " & name
discard encodeQoi(control) discard encodeQoi(control)
for name in tests: for name in tests:
let let
input = decodeQoiRaw(readFile("tests/fileformats/qoi/" & name & ".qoi")) input = decodeQoi(readFile("tests/fileformats/qoi/" & name & ".qoi"))
output = decodeQoiRaw(encodeQoi(input)) output = decodeQoi(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

View file

@ -26,9 +26,8 @@ proc doDiff(rendered: Image, name: string) =
diffImage.writeFile(&"tests/fileformats/svg/diffs/{name}.png") diffImage.writeFile(&"tests/fileformats/svg/diffs/{name}.png")
for file in files: for file in files:
doDiff(decodeSvg(readFile(&"tests/fileformats/svg/{file}.svg")), file) doDiff(readImage(&"tests/fileformats/svg/{file}.svg"), file)
doDiff( block:
decodeSvg(readFile("tests/fileformats/svg/accessibility-outline.svg"), 512, 512), let svg = parseSvg(readFile("tests/fileformats/svg/accessibility-outline.svg"), 512, 512)
"accessibility-outline" doDiff(newImage(svg), "accessibility-outline")
)