diff --git a/src/pixie/images.nim b/src/pixie/images.nim index eef3c14..3af36ca 100644 --- a/src/pixie/images.nim +++ b/src/pixie/images.nim @@ -751,5 +751,35 @@ proc superImage*(image: Image, x, y, w, h: int): Image {.raises: [PixieError].} result = newImage(w, h) result.draw(image, translate(vec2(-x.float32, -y.float32)), OverwriteBlend) +proc cropAlpha*(image: Image): (Image, Rect) = + ## Crops the alpha off the edges of an image. + ## Returns the new cropped image and the rectangle it used for cropping. + var + xMin = image.width + xMax = 0 + yMin = image.height + yMax = 0 + # Find the crop coordinates. + for y in 0 ..< image.height: + for x in 0 ..< image.width: + if image.unsafe[x, y].a != 0: + xMin = min(xMin, x) + xMax = max(xMax, x + 1) + yMin = min(yMin, y) + yMax = max(yMax, y + 1) + if xMax <= xMin or yMax <= yMin: + raise newException(PixieError, "Cannot cropAlpha fully transparent image") + let + corpImage = newImage(xMax - xMin, yMax - yMin) + cropRect = rect( + xMin.float32, + yMin.float32, + corpImage.width.float32, + corpImage.height.float32 + ) + # Draw the bigger image into the cropped image. + corpImage.draw(image, translate(vec2(-xMin.float32, -yMin.float32))) + return (corpImage, cropRect) + when defined(release): {.pop.} diff --git a/tests/images/cropHeart.png b/tests/images/cropHeart.png new file mode 100644 index 0000000..ea21adb Binary files /dev/null and b/tests/images/cropHeart.png differ diff --git a/tests/test_images.nim b/tests/test_images.nim index 70756cd..bbdb751 100644 --- a/tests/test_images.nim +++ b/tests/test_images.nim @@ -231,3 +231,42 @@ block: let image = newImage(100, 100) image.fill("white") doAssert image[10, 10] == rgba(255, 255, 255, 255) + +block: + # Make sure cropAlpha rases error. + let image = newImage(100, 100) + var hadError = false + try: + discard image.cropAlpha() + except PixieError: + hadError = true + doAssert hadError + +block: + # Make sure cropAlpha does nothing to full images. + let image = newImage(100, 100) + image.fill(rgbx(255, 255, 255, 255)) + let (crop, rect) = image.cropAlpha() + doAssert crop.width == image.width + doAssert crop.height == image.height + doAssert rect == rect(0.0, 0.0, 100.0, 100.0) + +block: + let image = newImage(100, 100) + image.fillPath( + """ + M 20 60 + A 40 40 90 0 1 100 60 + A 40 40 90 0 1 180 60 + Q 180 120 100 180 + Q 20 120 20 60 + z + """, + parseHtmlColor("#FC427B").rgba, + scale(vec2(0.3, 0.3)) + ) + let (crop, rect) = image.cropAlpha() + doAssert crop.width == 48 + doAssert crop.height == 48 + doAssert rect == rect(6.0, 6.0, 48.0, 48.0) + crop.xray("tests/images/cropHeart.png")