Skip to content

Commit

Permalink
imagelib: Implement setImageColor
Browse files Browse the repository at this point in the history
  • Loading branch information
iamgio committed Aug 11, 2023
1 parent 7880f9b commit 6bc03d9
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 58 deletions.
1 change: 1 addition & 0 deletions imagelib/src/main/kotlin/pikt/error/ImageValueType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ object ImageValueType {

const val IMAGE = "image"
const val WRITABLE_IMAGE = "writable image"
const val COLOR = "color"
}
23 changes: 17 additions & 6 deletions imagelib/src/main/kotlin/pikt/imagelib/AwtImage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -22,25 +22,35 @@ 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
)
}

if (y < 0 || y >= image.height) {
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) {
Expand All @@ -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<AwtImage> {

Expand Down
115 changes: 64 additions & 51 deletions imagelib/src/main/kotlin/pikt/imagelib/ImageFunctions.kt
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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]
Expand Down Expand Up @@ -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
}

/**
Expand All @@ -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)
}
10 changes: 10 additions & 0 deletions imagelib/src/main/kotlin/pikt/imagelib/WritableImage.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
package pikt.imagelib

import pikt.error.PiktIOException
import pikt.error.PiktIndexOutOfBoundsException
import java.io.File

/**
* An image that can be modified and saved on 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
Expand Down
3 changes: 2 additions & 1 deletion imagelib/src/main/resources/colors.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ newImage=B41EFF
saveImage=681EFF
imageWidth=
imageHeight=
getImageColor=
getImageColor=
setImageColor=

0 comments on commit 6bc03d9

Please sign in to comment.