simpler + out of bounds color for image blur

This commit is contained in:
Ryan Oldenburg 2021-02-26 19:10:48 -06:00
parent 851c15f943
commit 004182a122
6 changed files with 64 additions and 50 deletions

View file

@ -317,7 +317,7 @@ proc invert*(target: Image | Mask) =
for j in i ..< target.data.len: for j in i ..< target.data.len:
target.data[j] = (255 - target.data[j]).uint8 target.data[j] = (255 - target.data[j]).uint8
proc blur*(image: Image, radius: float32) = proc blur*(image: Image, radius: float32, outOfBounds = ColorRGBX()) =
## Applies Gaussian blur to the image given a radius. ## Applies Gaussian blur to the image given a radius.
let radius = round(radius).int let radius = round(radius).int
if radius == 0: if radius == 0:
@ -354,18 +354,23 @@ proc blur*(image: Image, radius: float32) =
for y in 0 ..< image.height: for y in 0 ..< image.height:
for x in 0 ..< image.width: for x in 0 ..< image.width:
var values: array[4, uint32] var values: array[4, uint32]
if image.inside(x - radius, y) and image.inside(x + radius, y): for xx in x - radius ..< min(x + radius, 0):
for step in -radius .. radius: let
let sample = outOfBounds
sample = image.getRgbaUnsafe(x + step, y) a = lookup[xx - x + radius].uint32
a = lookup[step + radius].uint32 values += sample * a
values += sample * a
else: for xx in max(x - radius, 0) ..< min(x + radius, image.width):
for step in -radius .. radius: let
let sample = image.getRgbaUnsafe(xx, y)
sample = image[x + step, y] a = lookup[xx - x + radius].uint32
a = lookup[step + radius].uint32 values += sample * a
values += sample * a
for xx in max(x - radius, image.width) ..< x + radius:
let
sample = outOfBounds
a = lookup[xx - x + radius].uint32
values += sample * a
blurX.setRgbaUnsafe(x, y, values.rgbx()) blurX.setRgbaUnsafe(x, y, values.rgbx())
@ -373,18 +378,23 @@ proc blur*(image: Image, radius: float32) =
for y in 0 ..< image.height: for y in 0 ..< image.height:
for x in 0 ..< image.width: for x in 0 ..< image.width:
var values: array[4, uint32] var values: array[4, uint32]
if image.inside(x, y - radius) and image.inside(x, y + radius): for yy in y - radius ..< min(y + radius, 0):
for step in -radius .. radius: let
let sample = outOfBounds
sample = blurX.getRgbaUnsafe(x, y + step) a = lookup[yy - y + radius].uint32
a = lookup[step + radius].uint32 values += sample * a
values += sample * a
else: for yy in max(y - radius, 0) ..< min(y + radius, image.height):
for step in -radius .. radius: let
let sample = blurX.getRgbaUnsafe(x, yy)
sample = blurX[x, y + step] a = lookup[yy - y + radius].uint32
a = lookup[step + radius].uint32 values += sample * a
values += sample * a
for yy in max(y - radius, image.height) ..< y + radius:
let
sample = outOfBounds
a = lookup[yy - y + radius].uint32
values += sample * a
image.setRgbaUnsafe(x, y, values.rgbx()) image.setRgbaUnsafe(x, y, values.rgbx())

View file

@ -167,18 +167,17 @@ proc blur*(mask: Mask, radius: float32, outOfBounds: uint8 = 0) =
for y in 0 ..< mask.height: for y in 0 ..< mask.height:
for x in 0 ..< mask.width: for x in 0 ..< mask.width:
var value: uint32 var value: uint32
if mask.inside(x - radius, y) and mask.inside(x + radius, y): for xx in x - radius ..< min(x + radius, 0):
for step in -radius .. radius: let sample = outOfBounds
let sample = mask.getValueUnsafe(x + step, y) value += sample * lookup[xx - x + radius].uint32
value += sample * lookup[step + radius].uint32
else: for xx in max(x - radius, 0) ..< min(x + radius, mask.width):
for step in -radius .. radius: let sample = mask.getValueUnsafe(xx, y)
var sample: uint32 value += sample * lookup[xx - x + radius].uint32
if mask.inside(x + step, y):
sample = mask.getValueUnsafe(x + step, y) for xx in max(x - radius, mask.width) ..< x + radius:
else: let sample = outOfBounds
sample = outOfBounds value += sample * lookup[xx - x + radius].uint32
value += sample * lookup[step + radius].uint32
blurX.setValueUnsafe(x, y, (value div 1024 div 255).uint8) blurX.setValueUnsafe(x, y, (value div 1024 div 255).uint8)
@ -186,19 +185,17 @@ proc blur*(mask: Mask, radius: float32, outOfBounds: uint8 = 0) =
for y in 0 ..< mask.height: for y in 0 ..< mask.height:
for x in 0 ..< mask.width: for x in 0 ..< mask.width:
var value: uint32 var value: uint32
if mask.inside(x, y - radius) and mask.inside(x, y + radius): for yy in y - radius ..< min(y + radius, 0):
for step in -radius .. radius: let sample = outOfBounds
let sample = blurX.getValueUnsafe(x, y + step) value += sample * lookup[yy - y + radius].uint32
value += sample * lookup[step + radius].uint32
else: for yy in max(y - radius, 0) ..< min(y + radius, mask.height):
for step in -radius .. radius: let sample = blurX.getValueUnsafe(x, yy)
var sample: uint32 value += sample * lookup[yy - y + radius].uint32
if blurX.inside(x, y + step):
sample = blurX.getValueUnsafe(x, y + step) for yy in max(y - radius, mask.height) ..< y + radius:
else: let sample = outOfBounds
sample = outOfBounds value += sample * lookup[yy - y + radius].uint32
let a = lookup[step + radius].uint32
value += sample * a
mask.setValueUnsafe(x, y, (value div 1024 div 255).uint8) mask.setValueUnsafe(x, y, (value div 1024 div 255).uint8)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -111,3 +111,10 @@ block:
image.fillRect(rect(25, 25, 50, 50), rgba(255, 255, 255, 255)) image.fillRect(rect(25, 25, 50, 50), rgba(255, 255, 255, 255))
image.blur(20) image.blur(20)
image.writeFile("tests/images/imageblur20.png") image.writeFile("tests/images/imageblur20.png")
block:
let image = newImage(100, 100)
image.fill(rgba(0, 0, 0, 255))
image.fillRect(rect(25, 25, 50, 50), rgba(255, 255, 255, 255))
image.blur(20, rgba(0, 0, 0, 255))
image.writeFile("tests/images/imageblur20oob.png")