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. 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? 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. 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. 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. 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. 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. 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:
@@ -921,7 +921,7 @@ function main() { 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")