Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 15 additions & 29 deletions src/pixie/images.nim
Original file line number Diff line number Diff line change
Expand Up @@ -434,45 +434,31 @@ proc applyOpacity*(target: Image | Mask, opacity: float32) {.raises: [].} =
for j in i ..< target.data.len:
target.data[j] = ((target.data[j] * opacity) div 255).uint8

proc invert*(target: Image | Mask) {.raises: [].} =
proc invert*(target: Image) {.raises: [].} =
## Inverts all of the colors and alpha.
var i: int
when defined(amd64) and not defined(pixieNoSimd):
let vec255 = mm_set1_epi8(cast[int8](255))

when type(target) is Image:
let byteLen = target.data.len * 4
else:
let byteLen = target.data.len

let byteLen = target.data.len * 4
for _ in 0 ..< byteLen div 16:
when type(target) is Image:
let index = i div 4
else:
let index = i

let index = i div 4
var values = mm_loadu_si128(target.data[index].addr)
values = mm_sub_epi8(vec255, values)
mm_storeu_si128(target.data[index].addr, values)

i += 16

when type(target) is Image:
for j in i div 4 ..< target.data.len:
var rgba = target.data[j]
rgba.r = 255 - rgba.r
rgba.g = 255 - rgba.g
rgba.b = 255 - rgba.b
rgba.a = 255 - rgba.a
target.data[j] = rgba

# Inverting rgbx(50, 100, 150, 200) becomes rgbx(205, 155, 105, 55). This
# is not a valid premultiplied alpha color.
# We need to convert back to premultiplied alpha after inverting.
target.data.toPremultipliedAlpha()
else:
for j in i ..< target.data.len:
target.data[j] = (255 - target.data[j]).uint8
for j in i div 4 ..< target.data.len:
var rgba = target.data[j]
rgba.r = 255 - rgba.r
rgba.g = 255 - rgba.g
rgba.b = 255 - rgba.b
rgba.a = 255 - rgba.a
target.data[j] = rgba

# Inverting rgbx(50, 100, 150, 200) becomes rgbx(205, 155, 105, 55). This
# is not a valid premultiplied alpha color.
# We need to convert back to premultiplied alpha after inverting.
target.data.toPremultipliedAlpha()

proc blur*(
image: Image, radius: float32, outOfBounds: SomeColor = color(0, 0, 0, 0)
Expand Down
97 changes: 70 additions & 27 deletions src/pixie/masks.nim
Original file line number Diff line number Diff line change
Expand Up @@ -234,38 +234,81 @@ proc getValueSmooth*(mask: Mask, x, y: float32): uint8 {.raises: [].} =
else:
topMix

proc invert*(mask: Mask) {.raises: [].} =
## Inverts all of the values - creates a negative of the mask.
var i: int
when defined(amd64) and not defined(pixieNoSimd):
let vec255 = mm_set1_epi8(cast[int8](255))
let byteLen = mask.data.len
for _ in 0 ..< byteLen div 16:
let index = i
var values = mm_loadu_si128(mask.data[index].addr)
values = mm_sub_epi8(vec255, values)
mm_storeu_si128(mask.data[index].addr, values)
i += 16

for j in i ..< mask.data.len:
mask.data[j] = (255 - mask.data[j]).uint8

proc spread*(mask: Mask, spread: float32) {.raises: [PixieError].} =
## Grows the mask by spread.
let spread = round(spread).int
if spread == 0:
return
if spread < 0:
raise newException(PixieError, "Cannot apply negative spread")

# Spread in the X direction. Store with dimensions swapped for reading later.
let spreadX = newMask(mask.height, mask.width)
for y in 0 ..< mask.height:
for x in 0 ..< mask.width:
var maxValue: uint8
for xx in max(x - spread, 0) .. min(x + spread, mask.width - 1):
let value = mask.unsafe[xx, y]
if value > maxValue:
maxValue = value
if maxValue == 255:
break
spreadX.unsafe[y, x] = maxValue

# Spread in the Y direction and modify mask.
for y in 0 ..< mask.height:
for x in 0 ..< mask.width:
var maxValue: uint8
for yy in max(y - spread, 0) .. min(y + spread, mask.height - 1):
let value = spreadX.unsafe[yy, x]
if value > maxValue:
maxValue = value
if maxValue == 255:
break
mask.unsafe[x, y] = maxValue
elif spread > 0:

# Spread in the X direction. Store with dimensions swapped for reading later.
let spreadX = newMask(mask.height, mask.width)
for y in 0 ..< mask.height:
for x in 0 ..< mask.width:
var maxValue: uint8
for xx in max(x - spread, 0) .. min(x + spread, mask.width - 1):
let value = mask.unsafe[xx, y]
if value > maxValue:
maxValue = value
if maxValue == 255:
break
spreadX.unsafe[y, x] = maxValue

# Spread in the Y direction and modify mask.
for y in 0 ..< mask.height:
for x in 0 ..< mask.width:
var maxValue: uint8
for yy in max(y - spread, 0) .. min(y + spread, mask.height - 1):
let value = spreadX.unsafe[yy, x]
if value > maxValue:
maxValue = value
if maxValue == 255:
break
mask.unsafe[x, y] = maxValue

elif spread < 0:

# Spread in the X direction. Store with dimensions swapped for reading later.
let spread = -spread
let spreadX = newMask(mask.height, mask.width)
for y in 0 ..< mask.height:
for x in 0 ..< mask.width:
var maxValue: uint8 = 255
for xx in max(x - spread, 0) .. min(x + spread, mask.width - 1):
let value = mask.unsafe[xx, y]
if value < maxValue:
maxValue = value
if maxValue == 0:
break
spreadX.unsafe[y, x] = maxValue

# Spread in the Y direction and modify mask.
for y in 0 ..< mask.height:
for x in 0 ..< mask.width:
var maxValue: uint8 = 255
for yy in max(y - spread, 0) .. min(y + spread, mask.height - 1):
let value = spreadX.unsafe[yy, x]
if value < maxValue:
maxValue = value
if maxValue == 0:
break
mask.unsafe[x, y] = maxValue

proc ceil*(mask: Mask) {.raises: [].} =
## A value of 0 stays 0. Anything else turns into 255.
Expand Down
Binary file modified tests/images/drawPolygon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/images/strokePolygon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/masks/drawPolygon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/masks/negativeSpread.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/masks/strokePolygon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions tests/test_masks.nim
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ block:

a.writeFile("tests/masks/spread.png")

block:
let path = newPath()
path.rect(40, 40, 20, 20)

let a = newMask(100, 100)
a.fillPath(path)

a.spread(-5)

a.writeFile("tests/masks/negativeSpread.png")

block:
let mask = newMask(100, 100)

Expand Down