From 6bc03d9e9c5e65b7155b817afdeef29c7bcc2bf1 Mon Sep 17 00:00:00 2001 From: Giorgio Garofalo Date: Fri, 11 Aug 2023 22:21:34 +0200 Subject: [PATCH] imagelib: Implement setImageColor --- .../main/kotlin/pikt/error/ImageValueType.kt | 1 + .../src/main/kotlin/pikt/imagelib/AwtImage.kt | 23 +++- .../kotlin/pikt/imagelib/ImageFunctions.kt | 115 ++++++++++-------- .../kotlin/pikt/imagelib/WritableImage.kt | 10 ++ imagelib/src/main/resources/colors.properties | 3 +- 5 files changed, 94 insertions(+), 58 deletions(-) diff --git a/imagelib/src/main/kotlin/pikt/error/ImageValueType.kt b/imagelib/src/main/kotlin/pikt/error/ImageValueType.kt index 6b5c3be..7cb86da 100644 --- a/imagelib/src/main/kotlin/pikt/error/ImageValueType.kt +++ b/imagelib/src/main/kotlin/pikt/error/ImageValueType.kt @@ -7,4 +7,5 @@ object ImageValueType { const val IMAGE = "image" const val WRITABLE_IMAGE = "writable image" + const val COLOR = "color" } \ No newline at end of file diff --git a/imagelib/src/main/kotlin/pikt/imagelib/AwtImage.kt b/imagelib/src/main/kotlin/pikt/imagelib/AwtImage.kt index 3ba0e57..4f20ef5 100644 --- a/imagelib/src/main/kotlin/pikt/imagelib/AwtImage.kt +++ b/imagelib/src/main/kotlin/pikt/imagelib/AwtImage.kt @@ -7,7 +7,7 @@ import java.io.File import java.io.IOException import javax.imageio.ImageIO -private typealias AWTColor = java.awt.Color +private typealias AwtColor = java.awt.Color /** * [Image] implementation based on AWT [BufferedImage] for the JVM. @@ -22,12 +22,12 @@ class AwtImage(private val image: BufferedImage) : WritableImage { override val height: Int get() = image.height - override fun getColor(x: Int, y: Int): Color { + private fun checkCoordinates(x: Int, y: Int, reference: Any) { if (x < 0 || x >= image.width) { throw PiktIndexOutOfBoundsException( index = x, size = image.width, - reference = object {} + reference ) } @@ -35,12 +35,22 @@ class AwtImage(private val image: BufferedImage) : WritableImage { throw PiktIndexOutOfBoundsException( index = y, size = image.height, - reference = object {} + reference ) } + } + + override fun getColor(x: Int, y: Int): Color { + this.checkCoordinates(x, y, reference = object {}) val rgb = image.getRGB(x, y) - return AWTColor(rgb).toPiktColor() + return AwtColor(rgb).toPiktColor() + } + + override fun setColor(x: Int, y: Int, color: Color) { + this.checkCoordinates(x, y, reference = object {}) + + image.setRGB(x, y, color.toAwtColor().rgb) } override fun save(file: File) { @@ -53,7 +63,8 @@ class AwtImage(private val image: BufferedImage) : WritableImage { override fun toString() = "AwtImage (width=$width, height=$height)" - private fun AWTColor.toPiktColor() = Color(red, green, blue) + private fun AwtColor.toPiktColor() = Color(red, green, blue) + private fun Color.toAwtColor() = AwtColor(red, green, blue) companion object : ImageFactory { diff --git a/imagelib/src/main/kotlin/pikt/imagelib/ImageFunctions.kt b/imagelib/src/main/kotlin/pikt/imagelib/ImageFunctions.kt index 1d44cf5..5503746 100644 --- a/imagelib/src/main/kotlin/pikt/imagelib/ImageFunctions.kt +++ b/imagelib/src/main/kotlin/pikt/imagelib/ImageFunctions.kt @@ -1,5 +1,6 @@ package pikt.imagelib +import pikt.error.ImageValueType.COLOR import pikt.error.ImageValueType.IMAGE import pikt.error.ImageValueType.WRITABLE_IMAGE import pikt.error.PiktIOException @@ -12,6 +13,42 @@ import java.io.File // Top-level functions to access image methods from Pikt. // The only supported implementation is currently the AWT one for the JVM. +/** + * @throws PiktWrongArgumentTypeException if [image] is not an [Image], or is not a [WritableImage] and [requireWritable] is `true`. + */ +private fun checkImageType(image: Any, requireWritable: Boolean = false, reference: Any) { + if (image !is Image || (requireWritable && image !is WritableImage)) { + throw PiktWrongArgumentTypeException( + parameterName = "image", + argumentValue = image, + expectedType = if (requireWritable) WRITABLE_IMAGE else IMAGE, + reference + ) + } +} + +/** + * @throws PiktWrongArgumentTypeException if [x] and/or [y] are not numbers. + */ +private fun checkCoordinatesType(x: Any, y: Any, reference: Any) { + if (x !is Int) { + throw PiktWrongArgumentTypeException( + parameterName = "x", + argumentValue = x, + expectedType = NUMBER, + reference + ) + } + if (y !is Int) { + throw PiktWrongArgumentTypeException( + parameterName = "y", + argumentValue = y, + expectedType = NUMBER, + reference + ) + } +} + /** * Instantiates a new writable [Image]. * @param width image width as [Int] @@ -53,48 +90,24 @@ fun newImage(pathOrFile: Any): WritableImage = AwtImage.fromFile(newFile(pathOrF * @throws PiktIOException if the image could not be saved */ fun saveImage(image: Any, pathOrFile: Any) { - if (image !is WritableImage) { - throw PiktWrongArgumentTypeException( - parameterName = "image", - argumentValue = image, - expectedType = WRITABLE_IMAGE, - reference = object {} - ) - } - - image.save(newFile(pathOrFile)) + checkImageType(image, requireWritable = true, reference = object {}) + (image as WritableImage).save(newFile(pathOrFile)) } /** * @return width of [image] */ fun imageWidth(image: Any): Int { - if (image !is Image) { - throw PiktWrongArgumentTypeException( - parameterName = "image", - argumentValue = image, - expectedType = IMAGE, - reference = object {} - ) - } - - return image.width + checkImageType(image, reference = object {}) + return (image as Image).width } /** * @return height of [image] */ fun imageHeight(image: Any): Int { - if (image !is Image) { - throw PiktWrongArgumentTypeException( - parameterName = "image", - argumentValue = image, - expectedType = IMAGE, - reference = object {} - ) - } - - return image.height + checkImageType(image, reference = object {}) + return (image as Image).height } /** @@ -104,31 +117,31 @@ fun imageHeight(image: Any): Int { * @throws PiktIndexOutOfBoundsException if one of the coordinates is negative or greater than the image size */ fun getImageColor(image: Any, x: Any, y: Any): Color { - if (image !is Image) { - throw PiktWrongArgumentTypeException( - parameterName = "image", - argumentValue = image, - expectedType = IMAGE, - reference = object {} - ) - } + checkImageType(image, reference = object {}) + checkCoordinatesType(x, y, object {}) - if (x !is Int) { - throw PiktWrongArgumentTypeException( - parameterName = "x", - argumentValue = x, - expectedType = NUMBER, - reference = object {} - ) - } - if (y !is Int) { + return (image as Image).getColor(x as Int, y as Int) +} + +/** + * Changes the color of a pixel of the [image] at the given coordinates. + * @param x X coordinate + * @param y Y coordinate + * @param color color to set + * @throws PiktIndexOutOfBoundsException if one of the coordinates is negative or greater than the image size + */ +fun setImageColor(image: Any, x: Any, y: Any, color: Any) { + checkImageType(image, requireWritable = true, reference = object {}) + checkCoordinatesType(x, y, reference = object {}) + + if (color !is Color) { throw PiktWrongArgumentTypeException( - parameterName = "y", - argumentValue = y, - expectedType = NUMBER, + parameterName = "color", + argumentValue = color, + expectedType = COLOR, reference = object {} ) } - return image.getColor(x, y) + return (image as WritableImage).setColor(x as Int, y as Int, color) } \ No newline at end of file diff --git a/imagelib/src/main/kotlin/pikt/imagelib/WritableImage.kt b/imagelib/src/main/kotlin/pikt/imagelib/WritableImage.kt index 7759480..36642b7 100644 --- a/imagelib/src/main/kotlin/pikt/imagelib/WritableImage.kt +++ b/imagelib/src/main/kotlin/pikt/imagelib/WritableImage.kt @@ -1,6 +1,7 @@ package pikt.imagelib import pikt.error.PiktIOException +import pikt.error.PiktIndexOutOfBoundsException import java.io.File /** @@ -8,6 +9,15 @@ import java.io.File */ interface WritableImage : Image { + /** + * Changes the color of a pixel. + * @param x X coordinate + * @param y Y coordinate + * @param color color to set at the given coordinates + * @throws PiktIndexOutOfBoundsException if one of the coordinates is negative or greater than the image size + */ + fun setColor(x: Int, y: Int, color: Color) + /** * Saves this image to file. * @param file file to save the image to diff --git a/imagelib/src/main/resources/colors.properties b/imagelib/src/main/resources/colors.properties index 258c7f2..6acfed6 100644 --- a/imagelib/src/main/resources/colors.properties +++ b/imagelib/src/main/resources/colors.properties @@ -2,4 +2,5 @@ newImage=B41EFF saveImage=681EFF imageWidth= imageHeight= -getImageColor= \ No newline at end of file +getImageColor= +setImageColor= \ No newline at end of file