Merge pull request #260 from guzba/master

binding stuff, image isTransparent isOneColor, superImage
This commit is contained in:
treeform 2021-08-17 14:51:05 -07:00 committed by GitHub
commit 400f66c3f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 160 additions and 107 deletions

View file

@ -120,7 +120,7 @@ font.size = 20
let text = "Typesetting is the arrangement and composition of text in graphic design and publishing in both digital and traditional medias." let text = "Typesetting is the arrangement and composition of text in graphic design and publishing in both digital and traditional medias."
image.fillText(font.typeset(text, bounds = vec2(180, 180)), vec2(10, 10)) image.fillText(font.typeset(text, vec2(180, 180)), translate(vec2(10, 10)))
``` ```
![example output](examples/text.png) ![example output](examples/text.png)
@ -143,7 +143,7 @@ let spans = @[
newFont(typeface, 14, color(0.3125, 0.3125, 0.3125, 1))) newFont(typeface, 14, color(0.3125, 0.3125, 0.3125, 1)))
] ]
image.fillText(typeset(spans, bounds = vec2(180, 180)), vec2(10, 10)) image.fillText(typeset(spans, vec2(180, 180)), translate(vec2(10, 10)))
``` ```
![example output](examples/text_spans.png) ![example output](examples/text_spans.png)

View file

@ -8,5 +8,5 @@ font.size = 20
let text = "Typesetting is the arrangement and composition of text in graphic design and publishing in both digital and traditional medias." let text = "Typesetting is the arrangement and composition of text in graphic design and publishing in both digital and traditional medias."
image.fillText(font.typeset(text, bounds = vec2(180, 180)), vec2(10, 10)) image.fillText(font.typeset(text, vec2(180, 180)), translate(vec2(10, 10)))
image.writeFile("examples/text.png") image.writeFile("examples/text.png")

View file

@ -19,5 +19,5 @@ let spans = @[
newFont(typeface, 14, color(0.3125, 0.3125, 0.3125, 1))) newFont(typeface, 14, color(0.3125, 0.3125, 0.3125, 1)))
] ]
image.fillText(typeset(spans, bounds = vec2(180, 180)), vec2(10, 10)) image.fillText(typeset(spans, vec2(180, 180)), translate(vec2(10, 10)))
image.writeFile("examples/text_spans.png") image.writeFile("examples/text_spans.png")

View file

@ -505,9 +505,9 @@ proc circle*(ctx: Context, cx, cy, r: float32) {.inline.} =
## Adds a circle to the current path. ## Adds a circle to the current path.
ctx.path.circle(cx, cy, r) ctx.path.circle(cx, cy, r)
proc circle*(ctx: Context, center: Vec2, r: float32) {.inline.} = proc circle*(ctx: Context, circle: Circle) {.inline.} =
## Adds a circle to the current path. ## Adds a circle to the current path.
ctx.path.circle(center, r) ctx.path.circle(circle)
proc polygon*(ctx: Context, x, y, size: float32, sides: int) {.inline.} = proc polygon*(ctx: Context, x, y, size: float32, sides: int) {.inline.} =
## Adds an n-sided regular polygon at (x, y) of size to the current path. ## Adds an n-sided regular polygon at (x, y) of size to the current path.
@ -563,7 +563,7 @@ proc strokeEllipse*(ctx: Context, center: Vec2, rx, ry: float32) =
proc fillCircle*(ctx: Context, circle: Circle) = proc fillCircle*(ctx: Context, circle: Circle) =
## Draws a circle that is filled according to the current fillStyle ## Draws a circle that is filled according to the current fillStyle
let path = newPath() let path = newPath()
path.circle(circle.pos, circle.radius) path.circle(circle)
ctx.fill(path) ctx.fill(path)
proc fillCircle*(ctx: Context, center: Vec2, radius: float32) = proc fillCircle*(ctx: Context, center: Vec2, radius: float32) =
@ -576,7 +576,7 @@ proc strokeCircle*(ctx: Context, circle: Circle) =
## Draws a circle that is stroked (outlined) according to the current ## Draws a circle that is stroked (outlined) according to the current
## strokeStyle and other context settings. ## strokeStyle and other context settings.
let path = newPath() let path = newPath()
path.circle(circle.pos, circle.radius) path.circle(circle)
ctx.stroke(path) ctx.stroke(path)
proc strokeCircle*(ctx: Context, center: Vec2, radius: float32) = proc strokeCircle*(ctx: Context, center: Vec2, radius: float32) =

View file

@ -437,7 +437,7 @@ proc parseSvgFont*(buf: string): Typeface =
proc textUber( proc textUber(
target: Image | Mask, target: Image | Mask,
arrangement: Arrangement, arrangement: Arrangement,
transform: Vec2 | Mat3 = vec2(0, 0), transform = mat3(),
strokeWidth = 1.0, strokeWidth = 1.0,
lineCap = lcButt, lineCap = lcButt,
lineJoin = ljMiter, lineJoin = ljMiter,
@ -518,7 +518,7 @@ proc textUber(
proc fillText*( proc fillText*(
target: Image | Mask, target: Image | Mask,
arrangement: Arrangement, arrangement: Arrangement,
transform: Vec2 | Mat3 = vec2(0, 0) transform = mat3()
) {.inline.} = ) {.inline.} =
## Fills the text arrangement. ## Fills the text arrangement.
textUber( textUber(
@ -531,7 +531,7 @@ proc fillText*(
target: Image | Mask, target: Image | Mask,
font: Font, font: Font,
text: string, text: string,
transform: Vec2 | Mat3 = vec2(0, 0), transform = mat3(),
bounds = vec2(0, 0), bounds = vec2(0, 0),
hAlign = haLeft, hAlign = haLeft,
vAlign = vaTop vAlign = vaTop
@ -546,7 +546,7 @@ proc fillText*(
proc strokeText*( proc strokeText*(
target: Image | Mask, target: Image | Mask,
arrangement: Arrangement, arrangement: Arrangement,
transform: Vec2 | Mat3 = vec2(0, 0), transform = mat3(),
strokeWidth = 1.0, strokeWidth = 1.0,
lineCap = lcButt, lineCap = lcButt,
lineJoin = ljMiter, lineJoin = ljMiter,
@ -570,7 +570,7 @@ proc strokeText*(
target: Image | Mask, target: Image | Mask,
font: Font, font: Font,
text: string, text: string,
transform: Vec2 | Mat3 = vec2(0, 0), transform = mat3(),
strokeWidth = 1.0, strokeWidth = 1.0,
bounds = vec2(0, 0), bounds = vec2(0, 0),
hAlign = haLeft, hAlign = haLeft,

View file

@ -126,6 +126,41 @@ proc fill*(image: Image, color: SomeColor) {.inline.} =
## Fills the image with the parameter color. ## Fills the image with the parameter color.
fillUnsafe(image.data, color, 0, image.data.len) fillUnsafe(image.data, color, 0, image.data.len)
proc isOneColor(image: Image, color: ColorRGBX): bool =
## Checks if the entire image is color.
result = true
let color = image.getRgbaUnsafe(0, 0)
var i: int
when defined(amd64) and not defined(pixieNoSimd):
let colorVec = mm_set1_epi32(cast[int32](color))
for j in countup(0, image.data.len - 16, 16):
let
values0 = mm_loadu_si128(image.data[j].addr)
values1 = mm_loadu_si128(image.data[j + 4].addr)
values2 = mm_loadu_si128(image.data[j + 8].addr)
values3 = mm_loadu_si128(image.data[j + 12].addr)
values01 = mm_or_si128(values0, values1)
values23 = mm_or_si128(values2, values3)
values = mm_or_si128(values01, values23)
mask = mm_movemask_epi8(mm_cmpeq_epi8(values, colorVec))
if mask != uint16.high.int:
return false
i += 16
for j in i ..< image.data.len:
if image.data[j] != color:
return false
proc isOneColor*(image: Image): bool =
## Checks if the entire image is the same color.
image.isOneColor(image.getRgbaUnsafe(0, 0))
proc isTransparent*(image: Image): bool =
## Checks if this image is fully transparent or not.
image.isOneColor(rgbx(0, 0, 0, 0))
proc flipHorizontal*(image: Image) = proc flipHorizontal*(image: Image) =
## Flips the image around the Y axis. ## Flips the image around the Y axis.
let w = image.width div 2 let w = image.width div 2
@ -170,30 +205,6 @@ proc subImage*(image: Image, x, y, w, h: int): Image =
w * 4 w * 4
) )
proc superImage*(image: Image, x, y, w, h: int): Image =
## Either cuts a sub image or returns a super image with padded transparency.
if x >= 0 and x + w <= image.width and y >= 0 and y + h <= image.height:
result = image.subImage(x, y, w, h)
elif abs(x) >= image.width or abs(y) >= image.height:
# Nothing to copy, just an empty new image
result = newImage(w, h)
else:
let
readOffsetX = max(x, 0)
readOffsetY = max(y, 0)
writeOffsetX = max(0 - x, 0)
writeOffsetY = max(0 - y, 0)
copyWidth = max(min(image.width, w) - abs(x), 0)
copyHeight = max(min(image.height, h) - abs(y), 0)
result = newImage(w, h)
for y2 in 0 ..< copyHeight:
copyMem(
result.data[result.dataIndex(writeOffsetX, writeOffsetY + y2)].addr,
image.data[image.dataIndex(readOffsetX, readOffsetY + y2)].addr,
copyWidth * 4
)
proc diff*(master, image: Image): (float32, Image) = proc diff*(master, image: Image): (float32, Image) =
## Compares the parameters and returns a score and image of the difference. ## Compares the parameters and returns a score and image of the difference.
let let
@ -815,7 +826,7 @@ proc drawUber(a, b: Image | Mask, mat = mat3(), blendMode = bmNormal) =
zeroMem(a.data[a.dataIndex(xMax, y)].addr, 4 * (a.width - xMax)) zeroMem(a.data[a.dataIndex(xMax, y)].addr, 4 * (a.width - xMax))
proc draw*( proc draw*(
a, b: Image, transform: Mat3 = mat3(), blendMode = bmNormal a, b: Image, transform = mat3(), blendMode = bmNormal
) {.inline.} = ) {.inline.} =
## Draws one image onto another using matrix with color blending. ## Draws one image onto another using matrix with color blending.
when type(transform) is Vec2: when type(transform) is Vec2:
@ -824,7 +835,7 @@ proc draw*(
a.drawUber(b, transform, blendMode) a.drawUber(b, transform, blendMode)
proc draw*( proc draw*(
a, b: Mask, transform: Mat3 = mat3(), blendMode = bmMask a, b: Mask, transform = mat3(), blendMode = bmMask
) {.inline.} = ) {.inline.} =
## Draws a mask onto a mask using a matrix with color blending. ## Draws a mask onto a mask using a matrix with color blending.
when type(transform) is Vec2: when type(transform) is Vec2:
@ -833,7 +844,7 @@ proc draw*(
a.drawUber(b, transform, blendMode) a.drawUber(b, transform, blendMode)
proc draw*( proc draw*(
image: Image, mask: Mask, transform: Mat3 = mat3(), blendMode = bmMask image: Image, mask: Mask, transform = mat3(), blendMode = bmMask
) {.inline.} = ) {.inline.} =
## Draws a mask onto an image using a matrix with color blending. ## Draws a mask onto an image using a matrix with color blending.
when type(transform) is Vec2: when type(transform) is Vec2:
@ -842,7 +853,7 @@ proc draw*(
image.drawUber(mask, transform, blendMode) image.drawUber(mask, transform, blendMode)
proc draw*( proc draw*(
mask: Mask, image: Image, transform: Mat3 = mat3(), blendMode = bmMask mask: Mask, image: Image, transform = mat3(), blendMode = bmMask
) {.inline.} = ) {.inline.} =
## Draws a image onto a mask using a matrix with color blending. ## Draws a image onto a mask using a matrix with color blending.
when type(transform) is Vec2: when type(transform) is Vec2:
@ -882,5 +893,13 @@ proc shadow*(
result.fill(color) result.fill(color)
result.draw(shifted, blendMode = bmMask) result.draw(shifted, blendMode = bmMask)
proc superImage*(image: Image, x, y, w, h: int): Image =
## Either cuts a sub image or returns a super image with padded transparency.
if x >= 0 and x + w <= image.width and y >= 0 and y + h <= image.height:
result = image.subImage(x, y, w, h)
else:
result = newImage(w, h)
result.draw(image, translate(vec2(-x.float32, -y.float32)), bmOverwrite)
when defined(release): when defined(release):
{.pop.} {.pop.}

View file

@ -17,13 +17,13 @@ type
## Line join type for strokes. ## Line join type for strokes.
ljMiter, ljRound, ljBevel ljMiter, ljRound, ljBevel
PathCommandKind* = enum PathCommandKind = enum
## Type of path commands ## Type of path commands
Close, Close,
Move, Line, HLine, VLine, Cubic, SCubic, Quad, TQuad, Arc, Move, Line, HLine, VLine, Cubic, SCubic, Quad, TQuad, Arc,
RMove, RLine, RHLine, RVLine, RCubic, RSCubic, RQuad, RTQuad, RArc RMove, RLine, RHLine, RVLine, RCubic, RSCubic, RQuad, RTQuad, RArc
PathCommand* = object PathCommand = object
## Binary version of an SVG command. ## Binary version of an SVG command.
kind: PathCommandKind kind: PathCommandKind
numbers: seq[float32] numbers: seq[float32]
@ -50,15 +50,12 @@ proc newPath*(): Path =
## Create a new Path. ## Create a new Path.
Path() Path()
proc pixelScale(transform: Vec2 | Mat3): float32 = proc pixelScale(transform: Mat3): float32 =
## What is the largest scale factor of this transform? ## What is the largest scale factor of this transform?
when type(transform) is Vec2: max(
return 1.0 vec2(transform[0, 0], transform[0, 1]).length,
else: vec2(transform[1, 0], transform[1, 1]).length
max( )
vec2(transform[0, 0], transform[0, 1]).length,
vec2(transform[1, 0], transform[1, 1]).length
)
proc isRelative(kind: PathCommandKind): bool = proc isRelative(kind: PathCommandKind): bool =
kind in { kind in {
@ -507,12 +504,6 @@ proc rect*(path: Path, x, y, w, h: float32, clockwise = true) =
path.lineTo(x + w, y) path.lineTo(x + w, y)
path.closePath() path.closePath()
proc rect*(path: Path, pos: Vec2, wh: Vec2, clockwise = true) {.inline.} =
## Adds a rectangle.
## Clockwise param can be used to subtract a rect from a path when using
## even-odd winding rule.
path.rect(pos.x, pos.y, wh.x, wh.y, clockwise)
proc rect*(path: Path, rect: Rect, clockwise = true) {.inline.} = proc rect*(path: Path, rect: Rect, clockwise = true) {.inline.} =
## Adds a rectangle. ## Adds a rectangle.
## Clockwise param can be used to subtract a rect from a path when using ## Clockwise param can be used to subtract a rect from a path when using
@ -590,14 +581,6 @@ proc roundedRect*(
path.closePath() path.closePath()
proc roundedRect*(
path: Path, pos, wh: Vec2, nw, ne, se, sw: float32, clockwise = true
) {.inline.} =
## Adds a rounded rectangle.
## Clockwise param can be used to subtract a rect from a path when using
## even-odd winding rule.
path.roundedRect(pos.x, pos.y, wh.x, wh.y, nw, ne, se, sw, clockwise)
proc roundedRect*( proc roundedRect*(
path: Path, rect: Rect, nw, ne, se, sw: float32, clockwise = true path: Path, rect: Rect, nw, ne, se, sw: float32, clockwise = true
) {.inline.} = ) {.inline.} =
@ -627,10 +610,6 @@ proc circle*(path: Path, cx, cy, r: float32) {.inline.} =
## Adds a circle. ## Adds a circle.
path.ellipse(cx, cy, r, r) path.ellipse(cx, cy, r, r)
proc circle*(path: Path, center: Vec2, r: float32) {.inline.} =
## Adds a circle.
path.ellipse(center.x, center.y, r, r)
proc circle*(path: Path, circle: Circle) {.inline.} = proc circle*(path: Path, circle: Circle) {.inline.} =
## Adds a circle. ## Adds a circle.
path.ellipse(circle.pos.x, circle.pos.y, circle.radius, circle.radius) path.ellipse(circle.pos.x, circle.pos.y, circle.radius, circle.radius)
@ -648,7 +627,7 @@ proc polygon*(path: Path, pos: Vec2, size: float32, sides: int) {.inline.} =
## Adds a n-sided regular polygon at (x, y) with the parameter size. ## Adds a n-sided regular polygon at (x, y) with the parameter size.
path.polygon(pos.x, pos.y, size, sides) path.polygon(pos.x, pos.y, size, sides)
proc commandsToShapes*( proc commandsToShapes(
path: Path, closeSubpaths = false, pixelScale: float32 = 1.0 path: Path, closeSubpaths = false, pixelScale: float32 = 1.0
): seq[seq[Vec2]] = ): seq[seq[Vec2]] =
## Converts SVG-like commands to sequences of vectors. ## Converts SVG-like commands to sequences of vectors.
@ -1750,22 +1729,16 @@ proc parseSomePath(
elif type(path) is Path: elif type(path) is Path:
path.commandsToShapes(closeSubpaths, pixelScale) path.commandsToShapes(closeSubpaths, pixelScale)
proc transform(shapes: var seq[seq[Vec2]], transform: Vec2 | Mat3) = proc transform(shapes: var seq[seq[Vec2]], transform: Mat3) =
when type(transform) is Vec2: if transform != mat3():
if transform != vec2(): for shape in shapes.mitems:
for shape in shapes.mitems: for segment in shape.mitems:
for segment in shape.mitems: segment = transform * segment
segment += transform
else:
if transform != mat3():
for shape in shapes.mitems:
for segment in shape.mitems:
segment = transform * segment
proc fillPath*( proc fillPath*(
mask: Mask, mask: Mask,
path: SomePath, path: SomePath,
transform: Vec2 | Mat3 = vec2(), transform = mat3(),
windingRule = wrNonZero, windingRule = wrNonZero,
blendMode = bmNormal blendMode = bmNormal
) = ) =
@ -1778,7 +1751,7 @@ proc fillPath*(
image: Image, image: Image,
path: SomePath, path: SomePath,
paint: Paint, paint: Paint,
transform: Vec2 | Mat3 = vec2(), transform = mat3(),
windingRule = wrNonZero windingRule = wrNonZero
) = ) =
## Fills a path. ## Fills a path.
@ -1827,7 +1800,7 @@ proc fillPath*(
proc strokePath*( proc strokePath*(
mask: Mask, mask: Mask,
path: SomePath, path: SomePath,
transform: Vec2 | Mat3 = vec2(), transform = mat3(),
strokeWidth = 1.0, strokeWidth = 1.0,
lineCap = lcButt, lineCap = lcButt,
lineJoin = ljMiter, lineJoin = ljMiter,
@ -1851,7 +1824,7 @@ proc strokePath*(
image: Image, image: Image,
path: SomePath, path: SomePath,
paint: Paint, paint: Paint,
transform: Vec2 | Mat3 = vec2(), transform = mat3(),
strokeWidth = 1.0, strokeWidth = 1.0,
lineCap = lcButt, lineCap = lcButt,
lineJoin = ljMiter, lineJoin = ljMiter,
@ -1948,7 +1921,7 @@ proc overlaps(
proc fillOverlaps*( proc fillOverlaps*(
path: Path, path: Path,
test: Vec2, test: Vec2,
transform: Vec2 | Mat3 = vec2(), ## Applied to the path, not the test point. transform = mat3(), ## Applied to the path, not the test point.
windingRule = wrNonZero windingRule = wrNonZero
): bool = ): bool =
## Returns whether or not the specified point is contained in the current path. ## Returns whether or not the specified point is contained in the current path.
@ -1959,7 +1932,7 @@ proc fillOverlaps*(
proc strokeOverlaps*( proc strokeOverlaps*(
path: Path, path: Path,
test: Vec2, test: Vec2,
transform: Vec2 | Mat3 = vec2(), ## Applied to the path, not the test point. transform = mat3(), ## Applied to the path, not the test point.
strokeWidth = 1.0, strokeWidth = 1.0,
lineCap = lcButt, lineCap = lcButt,
lineJoin = ljMiter, lineJoin = ljMiter,

View file

@ -17,6 +17,14 @@ timeIt "fill_rgba":
image.fill(rgba(63, 127, 191, 191)) image.fill(rgba(63, 127, 191, 191))
doAssert image[0, 0] == rgba(63, 127, 191, 191) doAssert image[0, 0] == rgba(63, 127, 191, 191)
image.fill(rgba(100, 0, 100, 100))
timeIt "isOneColor":
doAssert image.isOneColor()
image.fill(rgba(0, 0, 0, 0))
timeIt "isTransparent":
doAssert image.isTransparent()
reset() reset()
timeIt "subImage": timeIt "subImage":

Binary file not shown.

Before

Width:  |  Height:  |  Size: 519 B

After

Width:  |  Height:  |  Size: 520 B

View file

@ -154,7 +154,7 @@ block:
let image = newImage(200, 100) let image = newImage(200, 100)
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.fillText(font, "First line") image.fillText(font, "First line")
image.fillText(font, "Second line", vec2(0, font.defaultLineHeight)) image.fillText(font, "Second line", translate(vec2(0, font.defaultLineHeight)))
doDiff(image, "basic7") doDiff(image, "basic7")
@ -826,7 +826,7 @@ block:
let arrangement = typeset(spans, bounds = vec2(360, 360)) let arrangement = typeset(spans, bounds = vec2(360, 360))
image.fillText(arrangement, vec2(20, 20)) image.fillText(arrangement, translate(vec2(20, 20)))
doDiff(image, "spans5") doDiff(image, "spans5")
@ -965,7 +965,7 @@ block:
let arrangement = typeset(spans, bounds = vec2(360, 360)) let arrangement = typeset(spans, bounds = vec2(360, 360))
image.fillText(arrangement, vec2(20, 20)) image.fillText(arrangement, translate(vec2(20, 20)))
doDiff(image, "spans6") doDiff(image, "spans6")

View file

@ -164,3 +164,36 @@ block:
image.fillPath(p, rgba(255, 0, 0, 255)) image.fillPath(p, rgba(255, 0, 0, 255))
newImage(newMask(image)).writeFile("tests/images/mask2image.png") newImage(newMask(image)).writeFile("tests/images/mask2image.png")
block:
let image = newImage(100, 100)
doAssert image.isOneColor()
block:
let image = newImage(100, 100)
image.fill(rgba(255, 255, 255, 255))
doAssert image.isOneColor()
block:
let image = newImage(100, 100)
image.fill(rgba(1, 2, 3, 4))
doAssert image.isOneColor()
block:
let image = newImage(100, 100)
image[99, 99] = rgba(255, 255, 255, 255)
doAssert not image.isOneColor()
block:
let image = newImage(100, 100)
doAssert image.isTransparent()
block:
let image = newImage(100, 100)
image.fill(rgba(255, 255, 255, 0))
doAssert image.isTransparent()
block:
let image = newImage(100, 100)
image[99, 99] = rgba(255, 255, 255, 255)
doAssert not image.isTransparent()

View file

@ -213,7 +213,9 @@ block:
image = newImage(60, 60) image = newImage(60, 60)
path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20 Z") path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20 Z")
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath(path, rgba(0, 0, 0, 255), vec2(10, 10), 10, lcRound, ljRound) image.strokePath(
path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, lcRound, ljRound
)
image.writeFile("tests/images/paths/boxRound.png") image.writeFile("tests/images/paths/boxRound.png")
@ -222,7 +224,9 @@ block:
image = newImage(60, 60) image = newImage(60, 60)
path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20 Z") path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20 Z")
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath(path, rgba(0, 0, 0, 255), vec2(10, 10), 10, lcRound, ljBevel) image.strokePath(
path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, lcRound, ljBevel
)
image.writeFile("tests/images/paths/boxBevel.png") image.writeFile("tests/images/paths/boxBevel.png")
@ -231,7 +235,9 @@ block:
image = newImage(60, 60) image = newImage(60, 60)
path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20 Z") path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20 Z")
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath(path, rgba(0, 0, 0, 255), vec2(10, 10), 10, lcRound, ljMiter) image.strokePath(
path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, lcRound, ljMiter
)
image.writeFile("tests/images/paths/boxMiter.png") image.writeFile("tests/images/paths/boxMiter.png")
@ -240,7 +246,9 @@ block:
image = newImage(60, 60) image = newImage(60, 60)
path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20") path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20")
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath(path, rgba(0, 0, 0, 255), vec2(10, 10), 10, lcButt, ljBevel) image.strokePath(
path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, lcButt, ljBevel
)
image.writeFile("tests/images/paths/lcButt.png") image.writeFile("tests/images/paths/lcButt.png")
@ -249,7 +257,9 @@ block:
image = newImage(60, 60) image = newImage(60, 60)
path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20") path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20")
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath(path, rgba(0, 0, 0, 255), vec2(10, 10), 10, lcRound, ljBevel) image.strokePath(
path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, lcRound, ljBevel
)
image.writeFile("tests/images/paths/lcRound.png") image.writeFile("tests/images/paths/lcRound.png")
@ -258,7 +268,9 @@ block:
image = newImage(60, 60) image = newImage(60, 60)
path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20") path = parsePath("M 3 3 L 20 3 L 20 20 L 3 20")
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath(path, rgba(0, 0, 0, 255), vec2(10, 10), 10, lcSquare, ljBevel) image.strokePath(
path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, lcSquare, ljBevel
)
image.writeFile("tests/images/paths/lcSquare.png") image.writeFile("tests/images/paths/lcSquare.png")
@ -269,31 +281,31 @@ block:
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath( image.strokePath(
path, rgba(0, 0, 0, 255), vec2(5, 5), 10, lcButt, ljBevel, path, rgba(0, 0, 0, 255), translate(vec2(5, 5)), 10, lcButt, ljBevel,
) )
image.strokePath( image.strokePath(
path, rgba(0, 0, 0, 255), vec2(5, 25), 10, lcButt, ljBevel, path, rgba(0, 0, 0, 255), translate(vec2(5, 25)), 10, lcButt, ljBevel,
dashes = @[2.float32, 2] dashes = @[2.float32, 2]
) )
image.strokePath( image.strokePath(
path, rgba(0, 0, 0, 255), vec2(5, 45), 10, lcButt, ljBevel, path, rgba(0, 0, 0, 255), translate(vec2(5, 45)), 10, lcButt, ljBevel,
dashes = @[4.float32, 4] dashes = @[4.float32, 4]
) )
image.strokePath( image.strokePath(
path, rgba(0, 0, 0, 255), vec2(5, 65), 10, lcButt, ljBevel, path, rgba(0, 0, 0, 255), translate(vec2(5, 65)), 10, lcButt, ljBevel,
dashes = @[2.float32, 4, 6, 2] dashes = @[2.float32, 4, 6, 2]
) )
image.strokePath( image.strokePath(
path, rgba(0, 0, 0, 255), vec2(5, 85), 10, lcButt, ljBevel, path, rgba(0, 0, 0, 255), translate(vec2(5, 85)), 10, lcButt, ljBevel,
dashes = @[1.float32] dashes = @[1.float32]
) )
image.strokePath( image.strokePath(
path, rgba(0, 0, 0, 255), vec2(5, 105), 10, lcButt, ljBevel, path, rgba(0, 0, 0, 255), translate(vec2(5, 105)), 10, lcButt, ljBevel,
dashes = @[1.float32, 2, 3, 4, 5, 6, 7, 8, 9] dashes = @[1.float32, 2, 3, 4, 5, 6, 7, 8, 9]
) )
@ -311,7 +323,7 @@ block:
path.lineTo(sin(th)*20, cos(th)*20) path.lineTo(sin(th)*20, cos(th)*20)
image.strokePath( image.strokePath(
path, rgba(0, 0, 0, 255), vec2(30, 30), 8, lcButt, ljMiter, path, rgba(0, 0, 0, 255), translate(vec2(30, 30)), 8, lcButt, ljMiter,
miterLimit = limit miterLimit = limit
) )
image.writeFile(&"tests/images/paths/miterLimit_{angle.int}deg_{limit:0.2f}num.png") image.writeFile(&"tests/images/paths/miterLimit_{angle.int}deg_{limit:0.2f}num.png")
@ -340,28 +352,36 @@ block:
image = newImage(60, 60) image = newImage(60, 60)
path = parsePath("M 3 3 L 3 3 L 3 3") path = parsePath("M 3 3 L 3 3 L 3 3")
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath(path, rgba(0, 0, 0, 255), vec2(10, 10), 10, lcSquare, ljMiter) image.strokePath(
path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, lcSquare, ljMiter
)
block: block:
let let
image = newImage(60, 60) image = newImage(60, 60)
path = parsePath("L 0 0 L 0 0") path = parsePath("L 0 0 L 0 0")
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath(path, rgba(0, 0, 0, 255), vec2(10, 10), 10, lcSquare, ljMiter) image.strokePath(
path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, lcSquare, ljMiter
)
block: block:
let let
image = newImage(60, 60) image = newImage(60, 60)
path = parsePath("L 1 1") path = parsePath("L 1 1")
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath(path, rgba(0, 0, 0, 255), vec2(10, 10), 10, lcSquare, ljMiter) image.strokePath(
path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, lcSquare, ljMiter
)
block: block:
let let
image = newImage(60, 60) image = newImage(60, 60)
path = parsePath("L 0 0") path = parsePath("L 0 0")
image.fill(rgba(255, 255, 255, 255)) image.fill(rgba(255, 255, 255, 255))
image.strokePath(path, rgba(0, 0, 0, 255), vec2(10, 10), 10, lcSquare, ljMiter) image.strokePath(
path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, lcSquare, ljMiter
)
block: block:
let image = newImage(100, 100) let image = newImage(100, 100)