Image processing |
To process images such as photos, we need to be able to load photo files into an image object, read and set pixels values of the image, and save the image back into a photo file.
We use the class java.awt.image.BufferedImage to store image data. You can create such an object by saying:
import java.awt.image.BufferedImage val img = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
Or you can load an image from a file using:
import javax.imageio.ImageIO val photo1 = ImageIO.read(java.io.File("photo.jpg"))
The result of this call is a again a BufferedImage object. You can find the width and height of this image using the following methods:
println("Photo size is ${photo1.width}, ${photo1.height}")
You can save an image object into a file using:
ImageIO.write(photo1, "jpg", java.io.File("test.jpg"))or, if you prefer PNG format:
ImageIO.write(photo1, "png", java.io.File("test.png"))
The pixels of a BufferedImage object can be read and changed using the getRGB and setRGB methods, see below.
The following small script reads a file photo.jpg, get its dimensions, creates a new empty image of the same size, copies the pixels from the old image img to the new image out (by mirroring them horizontally), draws a red line diagonally across the photo, and finally saves the new image in a file test.jpg (image.kts):
import java.io.File import javax.imageio.ImageIO import java.awt.image.BufferedImage fun phototest(img: BufferedImage): BufferedImage { // obtain width and height of image val w = img.width val h = img.height // create new image of the same size val out = BufferedImage(w, h, BufferedImage.TYPE_INT_RGB) // copy pixels (mirror horizontally) for (x in 0 until w) for (y in 0 until h) out.setRGB(x, y, img.getRGB(w - x - 1, y) and 0xffffff) // draw red diagonal line for (x in 0 until Math.min(h, w)) out.setRGB(x, x, 0xff0000) return out } fun test() { // read original image, and obtain width and height val photo1 = ImageIO.read(File("photo.jpg")) val photo2 = phototest(photo1) // save image to file "test.jpg" ImageIO.write(photo2, "jpg", File("test.jpg")) } test()
The method getRGB(x: Int, y: Int): Int returns the color of the pixel at position (x, y), the method setRGB(x: Int, y: Int, color: Int) sets the color of this pixel.
Colors are represented as Int objects. The three components red, green, and blue are "packed" together into one integer. Each component has 8 bits, and therefore can have a value between 0 and 255. The packed color is a 32-bit integer, whose bits look like this:
tttt tttt rrrr rrrr gggg gggg bbbb bbbbThe top 8 bits are either zero, or represent the "transparency" of the pixel. We will not use these transparency bits. The next 8 bits represent red, the next 8 bits represent green, and the last 8 bits represent blue. This is why this representation is called "RGB".
Given red, green, and blue components with values in the range 0 to 255, we can pack them together like this:
val color = (red * 65536) + (green * 256) + blueGiven a packed integer color, we can extract the three components as follows:
val red = (color and 0xff0000) / 65536 val green = (color and 0xff00) / 256 val blue = (color and 0xff)(The and operator here is the bitwise-and operator. It makes sure that only the bits we are interested in are used.)
Image processing |