diff --git a/docs/pixie.html b/docs/pixie.html
index cab9ece..d2fc582 100644
--- a/docs/pixie.html
+++ b/docs/pixie.html
@@ -538,7 +538,7 @@ Strokes a polygon.
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:34 UTC
diff --git a/docs/pixie/blends.html b/docs/pixie/blends.html
index a3f5abc..ca725e9 100644
--- a/docs/pixie/blends.html
+++ b/docs/pixie/blends.html
@@ -283,7 +283,7 @@ Is there a blend masking function with SIMD support?
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:33 UTC
diff --git a/docs/pixie/common.html b/docs/pixie/common.html
index 24522ff..f1b9a0c 100644
--- a/docs/pixie/common.html
+++ b/docs/pixie/common.html
@@ -196,7 +196,7 @@ Linearly interpolate between a and b using t.
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:33 UTC
diff --git a/docs/pixie/fileformats/bmp.html b/docs/pixie/fileformats/bmp.html
index 3ba126d..d790cad 100644
--- a/docs/pixie/fileformats/bmp.html
+++ b/docs/pixie/fileformats/bmp.html
@@ -182,7 +182,7 @@ Encodes an image into the BMP file format.
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:33 UTC
diff --git a/docs/pixie/fileformats/jpg.html b/docs/pixie/fileformats/jpg.html
index de97893..c754435 100644
--- a/docs/pixie/fileformats/jpg.html
+++ b/docs/pixie/fileformats/jpg.html
@@ -182,7 +182,7 @@ Encodes Image into a JPEG data string.
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:34 UTC
diff --git a/docs/pixie/fileformats/png.html b/docs/pixie/fileformats/png.html
index 1ae53fd..68e8924 100644
--- a/docs/pixie/fileformats/png.html
+++ b/docs/pixie/fileformats/png.html
@@ -201,7 +201,7 @@ Encodes the mask data into the PNG file format.
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:34 UTC
diff --git a/docs/pixie/fileformats/svg.html b/docs/pixie/fileformats/svg.html
index bc25c55..fc64e7b 100644
--- a/docs/pixie/fileformats/svg.html
+++ b/docs/pixie/fileformats/svg.html
@@ -171,7 +171,7 @@ Render SVG file and return the image. Defaults to the SVG's view box size.
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:34 UTC
diff --git a/docs/pixie/images.html b/docs/pixie/images.html
index c9e47b6..b0506df 100644
--- a/docs/pixie/images.html
+++ b/docs/pixie/images.html
@@ -231,7 +231,7 @@ function main() {
blur
- blur,Image,float32
+ title="blur(image: Image; radius: float32; outOfBounds = ColorRGBX())">blur,Image,float32
dataIndex
@@ -451,7 +451,8 @@ Inverts all of the colors and alpha.
-proc blur(image: Image; radius: float32) {...}{.raises: [PixieError], tags: [].}
+proc blur(image: Image; radius: float32; outOfBounds = ColorRGBX()) {...}{.
+ raises: [PixieError], tags: [].}
-
Applies Gaussian blur to the image given a radius.
@@ -577,7 +578,7 @@ Create a shadow of the image with the offset, spread and blur.
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:33 UTC
diff --git a/docs/pixie/images.idx b/docs/pixie/images.idx
index 9d0229e..a89b63a 100644
--- a/docs/pixie/images.idx
+++ b/docs/pixie/images.idx
@@ -19,7 +19,7 @@ minifyBy2 pixie/images.html#minifyBy2,Image,int images: minifyBy2(image: Image;
magnifyBy2 pixie/images.html#magnifyBy2,Image,int images: magnifyBy2(image: Image; power = 1): Image
applyOpacity pixie/images.html#applyOpacity,,float32 images: applyOpacity(target: Image | Mask; opacity: float32)
invert pixie/images.html#invert images: invert(target: Image | Mask)
-blur pixie/images.html#blur,Image,float32 images: blur(image: Image; radius: float32)
+blur pixie/images.html#blur,Image,float32 images: blur(image: Image; radius: float32; outOfBounds = ColorRGBX())
newMask pixie/images.html#newMask,Image images: newMask(image: Image): Mask
getRgbaSmooth pixie/images.html#getRgbaSmooth,Image,float32,float32 images: getRgbaSmooth(image: Image; x, y: float32; wrapped = false): ColorRGBX
draw pixie/images.html#draw,Image,Image,Mat3 images: draw(a, b: Image; mat: Mat3; blendMode = bmNormal)
diff --git a/docs/pixie/internal.html b/docs/pixie/internal.html
index d08b156..750b4f7 100644
--- a/docs/pixie/internal.html
+++ b/docs/pixie/internal.html
@@ -178,7 +178,7 @@ Unpack the first 32 bits into 4 rgba(0, 0, 0, value)
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:33 UTC
diff --git a/docs/pixie/masks.html b/docs/pixie/masks.html
index 187f214..7eaa940 100644
--- a/docs/pixie/masks.html
+++ b/docs/pixie/masks.html
@@ -367,7 +367,7 @@ Applies Gaussian blur to the image given a radius.
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:33 UTC
diff --git a/docs/pixie/paints.html b/docs/pixie/paints.html
index a8805f9..e140875 100644
--- a/docs/pixie/paints.html
+++ b/docs/pixie/paints.html
@@ -243,7 +243,7 @@ Angular gradient.
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:34 UTC
diff --git a/docs/pixie/paths.html b/docs/pixie/paths.html
index bc5cfea..3fd741e 100644
--- a/docs/pixie/paths.html
+++ b/docs/pixie/paths.html
@@ -662,7 +662,7 @@ Return elements in pairs: (1st, 2nd), (2nd, 3rd) ... (n - 1, last).
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:34 UTC
diff --git a/docs/theindex.html b/docs/theindex.html
index d1c4bad..14839db 100644
--- a/docs/theindex.html
+++ b/docs/theindex.html
@@ -134,7 +134,7 @@ function main() {
blur:
@@ -921,7 +921,7 @@ function main() {
- Made with Nim. Generated: 2021-02-27 00:46:16 UTC
+ Made with Nim. Generated: 2021-02-27 01:24:34 UTC
diff --git a/examples/blur.png b/examples/blur.png
index a56cd1b..7cd2b83 100644
Binary files a/examples/blur.png and b/examples/blur.png differ
diff --git a/examples/shadow.png b/examples/shadow.png
index 4bcbae3..3553a89 100644
Binary files a/examples/shadow.png and b/examples/shadow.png differ
diff --git a/pixie.nimble b/pixie.nimble
index cd3cadb..59427fc 100644
--- a/pixie.nimble
+++ b/pixie.nimble
@@ -1,4 +1,4 @@
-version = "1.0.1"
+version = "1.0.2"
author = "Andre von Houck and Ryan Oldenburg"
description = "Full-featured 2d graphics library for Nim."
license = "MIT"
diff --git a/src/pixie/images.nim b/src/pixie/images.nim
index 008319c..f2d9f14 100644
--- a/src/pixie/images.nim
+++ b/src/pixie/images.nim
@@ -317,7 +317,7 @@ proc invert*(target: Image | Mask) =
for j in i ..< target.data.len:
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.
let radius = round(radius).int
if radius == 0:
@@ -325,9 +325,7 @@ proc blur*(image: Image, radius: float32) =
let lookup = gaussianLookup(radius)
- # TODO support offBounds for images.
-
- template `*`(sample: ColorRGBX, a: uint32): array[4, uint32] =
+ proc `*`(sample: ColorRGBX, a: uint32): array[4, uint32] {.inline.} =
[
sample.r * a,
sample.g * a,
@@ -354,18 +352,14 @@ proc blur*(image: Image, radius: float32) =
for y in 0 ..< image.height:
for x in 0 ..< image.width:
var values: array[4, uint32]
- if image.inside(x - radius, y) and image.inside(x + radius, y):
- for step in -radius .. radius:
- let
- sample = image.getRgbaUnsafe(x + step, y)
- a = lookup[step + radius].uint32
- values += sample * a
- else:
- for step in -radius .. radius:
- let
- sample = image[x + step, y]
- a = lookup[step + radius].uint32
- values += sample * a
+ for xx in x - radius ..< min(x + radius, 0):
+ values += outOfBounds * lookup[xx - x + radius]
+
+ for xx in max(x - radius, 0) ..< min(x + radius, image.width):
+ values += image.getRgbaUnsafe(xx, y) * lookup[xx - x + radius]
+
+ for xx in max(x - radius, image.width) ..< x + radius:
+ values += outOfBounds * lookup[xx - x + radius]
blurX.setRgbaUnsafe(x, y, values.rgbx())
@@ -373,18 +367,14 @@ proc blur*(image: Image, radius: float32) =
for y in 0 ..< image.height:
for x in 0 ..< image.width:
var values: array[4, uint32]
- if image.inside(x, y - radius) and image.inside(x, y + radius):
- for step in -radius .. radius:
- let
- sample = blurX.getRgbaUnsafe(x, y + step)
- a = lookup[step + radius].uint32
- values += sample * a
- else:
- for step in -radius .. radius:
- let
- sample = blurX[x, y + step]
- a = lookup[step + radius].uint32
- values += sample * a
+ for yy in y - radius ..< min(y + radius, 0):
+ values += outOfBounds * lookup[yy - y + radius]
+
+ for yy in max(y - radius, 0) ..< min(y + radius, image.height):
+ values += blurX.getRgbaUnsafe(x, yy) * lookup[yy - y + radius]
+
+ for yy in max(y - radius, image.height) ..< y + radius:
+ values += outOfBounds * lookup[yy - y + radius]
image.setRgbaUnsafe(x, y, values.rgbx())
diff --git a/src/pixie/masks.nim b/src/pixie/masks.nim
index 57f14ee..ec8ac7f 100644
--- a/src/pixie/masks.nim
+++ b/src/pixie/masks.nim
@@ -167,18 +167,14 @@ proc blur*(mask: Mask, radius: float32, outOfBounds: uint8 = 0) =
for y in 0 ..< mask.height:
for x in 0 ..< mask.width:
var value: uint32
- if mask.inside(x - radius, y) and mask.inside(x + radius, y):
- for step in -radius .. radius:
- let sample = mask.getValueUnsafe(x + step, y)
- value += sample * lookup[step + radius].uint32
- else:
- for step in -radius .. radius:
- var sample: uint32
- if mask.inside(x + step, y):
- sample = mask.getValueUnsafe(x + step, y)
- else:
- sample = outOfBounds
- value += sample * lookup[step + radius].uint32
+ for xx in x - radius ..< min(x + radius, 0):
+ value += outOfBounds * lookup[xx - x + radius]
+
+ for xx in max(x - radius, 0) ..< min(x + radius, mask.width):
+ value += mask.getValueUnsafe(xx, y) * lookup[xx - x + radius]
+
+ for xx in max(x - radius, mask.width) ..< x + radius:
+ value += outOfBounds * lookup[xx - x + radius]
blurX.setValueUnsafe(x, y, (value div 1024 div 255).uint8)
@@ -186,19 +182,14 @@ proc blur*(mask: Mask, radius: float32, outOfBounds: uint8 = 0) =
for y in 0 ..< mask.height:
for x in 0 ..< mask.width:
var value: uint32
- if mask.inside(x, y - radius) and mask.inside(x, y + radius):
- for step in -radius .. radius:
- let sample = blurX.getValueUnsafe(x, y + step)
- value += sample * lookup[step + radius].uint32
- else:
- for step in -radius .. radius:
- var sample: uint32
- if blurX.inside(x, y + step):
- sample = blurX.getValueUnsafe(x, y + step)
- else:
- sample = outOfBounds
- let a = lookup[step + radius].uint32
- value += sample * a
+ for yy in y - radius ..< min(y + radius, 0):
+ value += outOfBounds * lookup[yy - y + radius]
+
+ for yy in max(y - radius, 0) ..< min(y + radius, mask.height):
+ value += blurX.getValueUnsafe(x, yy) * lookup[yy - y + radius]
+
+ for yy in max(y - radius, mask.height) ..< y + radius:
+ value += outOfBounds * lookup[yy - y + radius]
mask.setValueUnsafe(x, y, (value div 1024 div 255).uint8)
diff --git a/tests/images/imageblur20.png b/tests/images/imageblur20.png
index 9704d36..828c71e 100644
Binary files a/tests/images/imageblur20.png and b/tests/images/imageblur20.png differ
diff --git a/tests/images/imageblur20oob.png b/tests/images/imageblur20oob.png
new file mode 100644
index 0000000..f964ef0
Binary files /dev/null and b/tests/images/imageblur20oob.png differ
diff --git a/tests/images/maskblur20.png b/tests/images/maskblur20.png
index bab2143..e255e76 100644
Binary files a/tests/images/maskblur20.png and b/tests/images/maskblur20.png differ
diff --git a/tests/test_images.nim b/tests/test_images.nim
index 08fa617..07b83a7 100644
--- a/tests/test_images.nim
+++ b/tests/test_images.nim
@@ -111,3 +111,10 @@ block:
image.fillRect(rect(25, 25, 50, 50), rgba(255, 255, 255, 255))
image.blur(20)
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")