Merge pull request #399 from treeform/dev

Negative Spread
This commit is contained in:
treeform 2022-03-20 13:03:30 -07:00 committed by GitHub
commit e67a43ee7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 93 additions and 53 deletions

View file

@ -434,30 +434,19 @@ proc applyOpacity*(target: Image | Mask, opacity: float32) {.raises: [].} =
for j in i ..< target.data.len: for j in i ..< target.data.len:
target.data[j] = ((target.data[j] * opacity) div 255).uint8 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. ## Inverts all of the colors and alpha.
var i: int var i: int
when defined(amd64) and not defined(pixieNoSimd): when defined(amd64) and not defined(pixieNoSimd):
let vec255 = mm_set1_epi8(cast[int8](255)) let vec255 = mm_set1_epi8(cast[int8](255))
when type(target) is Image:
let byteLen = target.data.len * 4 let byteLen = target.data.len * 4
else:
let byteLen = target.data.len
for _ in 0 ..< byteLen div 16: for _ in 0 ..< byteLen div 16:
when type(target) is Image:
let index = i div 4 let index = i div 4
else:
let index = i
var values = mm_loadu_si128(target.data[index].addr) var values = mm_loadu_si128(target.data[index].addr)
values = mm_sub_epi8(vec255, values) values = mm_sub_epi8(vec255, values)
mm_storeu_si128(target.data[index].addr, values) mm_storeu_si128(target.data[index].addr, values)
i += 16 i += 16
when type(target) is Image:
for j in i div 4 ..< target.data.len: for j in i div 4 ..< target.data.len:
var rgba = target.data[j] var rgba = target.data[j]
rgba.r = 255 - rgba.r rgba.r = 255 - rgba.r
@ -470,9 +459,6 @@ proc invert*(target: Image | Mask) {.raises: [].} =
# is not a valid premultiplied alpha color. # is not a valid premultiplied alpha color.
# We need to convert back to premultiplied alpha after inverting. # We need to convert back to premultiplied alpha after inverting.
target.data.toPremultipliedAlpha() target.data.toPremultipliedAlpha()
else:
for j in i ..< target.data.len:
target.data[j] = (255 - target.data[j]).uint8
proc blur*( proc blur*(
image: Image, radius: float32, outOfBounds: SomeColor = color(0, 0, 0, 0) image: Image, radius: float32, outOfBounds: SomeColor = color(0, 0, 0, 0)

View file

@ -234,13 +234,28 @@ proc getValueSmooth*(mask: Mask, x, y: float32): uint8 {.raises: [].} =
else: else:
topMix 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].} = proc spread*(mask: Mask, spread: float32) {.raises: [PixieError].} =
## Grows the mask by spread. ## Grows the mask by spread.
let spread = round(spread).int let spread = round(spread).int
if spread == 0: if spread == 0:
return return
if spread < 0: elif spread > 0:
raise newException(PixieError, "Cannot apply negative spread")
# Spread in the X direction. Store with dimensions swapped for reading later. # Spread in the X direction. Store with dimensions swapped for reading later.
let spreadX = newMask(mask.height, mask.width) let spreadX = newMask(mask.height, mask.width)
@ -267,6 +282,34 @@ proc spread*(mask: Mask, spread: float32) {.raises: [PixieError].} =
break break
mask.unsafe[x, y] = maxValue 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: [].} = proc ceil*(mask: Mask) {.raises: [].} =
## A value of 0 stays 0. Anything else turns into 255. ## A value of 0 stays 0. Anything else turns into 255.
var i: int var i: int

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 853 B

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -92,6 +92,17 @@ block:
a.writeFile("tests/masks/spread.png") 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: block:
let mask = newMask(100, 100) let mask = newMask(100, 100)