Reputation: 768
I'm trying to scale a JPEG image and save it back using the following code, however, the resulting storage/test/thumbnail.jpg
file is just an empty file. I checked the same code with PNG
format and it works perfectly. However, for my use case I need a JPG image and not PNG.
import java.awt.geom.AffineTransform
import java.awt.image.AffineTransformOp
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
fun main() {
val file = File("storage/test/original.jpg")
val image = ImageIO.read(file.inputStream())
val thumbnail = thumbnailOf(image)
val thumbnailFile = File("storage/test/thumbnail.jpg")
thumbnailFile.parentFile.mkdirs()
thumbnailFile.outputStream().use { output ->
ImageIO.write(thumbnail, "JPEG", output)
}
}
fun thumbnailOf(image: BufferedImage): BufferedImage {
val width = image.width
val height = image.height
val ratio = width / height.toDouble()
if (ratio == 0.0) {
error("Cannot determine ratio for ($width*$height)")
}
val newWidth = 600
val newHeight = (newWidth / ratio).toInt()
val scaledImage = BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB)
val at = AffineTransform()
at.scale(newWidth / width.toDouble(), newHeight / height.toDouble())
val ato = AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC)
return ato.filter(image, scaledImage)
}
The best thing I was able to find so far is this answer https://stackoverflow.com/a/16026254/4112200 , which states that OpenJDK doesn't have a JPEG encoder. So, if that's the case, how can I add the JPEG encoder (or decoder) to my currently installed OpenJDK?
My currently installed OpenJDK
openjdk version "12" 2019-03-19
OpenJDK Runtime Environment (build 12+33)
OpenJDK 64-Bit Server VM (build 12+33, mixed mode, sharing)
Upvotes: 4
Views: 2062
Reputation: 768
Alright, here's how I have solved this.
For my case, the issue didn't have anything to do with JPEG support. JPEG is already supported, however, there were some bugs in my code in addition I used a different approach to scale the image.
val scaledImage = BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB)
ImageIO.write
cannot find an ImageWriter
that matches with BufferedImage.TYPE_INT_ARGB
and JPG
/ JPEG
. So, I changed it to BufferedImage.TYPE_INT_RGB
.
ato.filter(image, scaledImage)
Exception in thread "main" java.awt.image.ImagingOpException: Unable to transform src image
I don't know what's the reason for that exception and how to fix it, but using a Graphics2D
object to scale and render the image worked for me.
scale()
were inconsistent.The following is the final code where this works successfully, and how points 2 and 3 were fixed.
import java.awt.Graphics2D
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
fun main() {
val file = File("storage/test/original.jpg")
val image = ImageIO.read(file.inputStream())
val thumbnail = thumbnailOf(image)
val thumbnailFile = File("storage/test/thumbnail.jpg")
thumbnailFile.parentFile.mkdirs()
thumbnailFile.outputStream().use { output ->
ImageIO.write(thumbnail, "JPEG", output)
}
}
fun thumbnailOf(image: BufferedImage): BufferedImage {
val width = image.width
val height = image.height
val ratio = width / height.toDouble()
if (ratio == 0.0) {
error("Cannot determine ratio for ($width*$height)")
}
val newWidth = 600
val newHeight = (newWidth / ratio).toInt()
val scale = newWidth / width.toDouble()
val scaledImage = BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB)
val graph = scaledImage.graphics as Graphics2D
// graph.scale((newWidth / width).toDouble(), (newHeight / height).toDouble())
graph.scale(scale, scale)
// everything drawn with graph from now on will get scaled.
graph.drawImage(image, 0, 0, null)
graph.dispose()
return scaledImage
}
Upvotes: 2