diff --git a/src/pixie/images.nim b/src/pixie/images.nim index 90e760c..b3b4cf8 100644 --- a/src/pixie/images.nim +++ b/src/pixie/images.nim @@ -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 + 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 + # 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) diff --git a/src/pixie/masks.nim b/src/pixie/masks.nim index ea7b718..3bf80be 100644 --- a/src/pixie/masks.nim +++ b/src/pixie/masks.nim @@ -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") + 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 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 + # 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. diff --git a/tests/images/drawPolygon.png b/tests/images/drawPolygon.png index f68adc1..b117fed 100644 Binary files a/tests/images/drawPolygon.png and b/tests/images/drawPolygon.png differ diff --git a/tests/images/strokePolygon.png b/tests/images/strokePolygon.png index e3b802a..b1597d7 100644 Binary files a/tests/images/strokePolygon.png and b/tests/images/strokePolygon.png differ diff --git a/tests/masks/drawPolygon.png b/tests/masks/drawPolygon.png index abd187e..c16c400 100644 Binary files a/tests/masks/drawPolygon.png and b/tests/masks/drawPolygon.png differ diff --git a/tests/masks/negativeSpread.png b/tests/masks/negativeSpread.png new file mode 100644 index 0000000..0dcc9f3 Binary files /dev/null and b/tests/masks/negativeSpread.png differ diff --git a/tests/masks/strokePolygon.png b/tests/masks/strokePolygon.png index c647585..3ba0712 100644 Binary files a/tests/masks/strokePolygon.png and b/tests/masks/strokePolygon.png differ diff --git a/tests/test_masks.nim b/tests/test_masks.nim index f0ae841..0b9d105 100644 --- a/tests/test_masks.nim +++ b/tests/test_masks.nim @@ -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)