Добавить поддержку кодировщика / декодера JPEG в установленный OpenJDK - PullRequest
1 голос
/ 11 марта 2020

Я пытаюсь масштабировать изображение JPEG и сохранить его обратно, используя следующий код, однако полученный storage/test/thumbnail.jpg файл является просто пустым файлом. Я проверил тот же код в формате PNG, и он отлично работает. Однако для моего случая использования мне нужно изображение JPG, а не 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)
}

Лучшее, что мне удалось найти, - это ответ { ссылка }, в котором говорится, что OpenJDK не имеет кодировщика JPEG. Итак, если это так, как я могу добавить кодировщик JPEG (или декодер) в мой установленный в настоящее время OpenJDK?

Мой установленный в настоящее время OpenJDK

openjdk version "12" 2019-03-19
OpenJDK Runtime Environment (build 12+33)
OpenJDK 64-Bit Server VM (build 12+33, mixed mode, sharing)

1 Ответ

1 голос
/ 11 марта 2020

Хорошо, вот как я решил это.

В моем случае проблема не имела никакого отношения к поддержке JPEG. JPEG уже поддерживается, однако в моем коде были некоторые ошибки, кроме того, я использовал другой подход к масштабированию изображения.

  1. Первая ошибка в этой строке:
val scaledImage = BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB)

ImageIO.write не может найти ImageWriter, который соответствует BufferedImage.TYPE_INT_ARGB и JPG / JPEG. Итак, я изменил его на BufferedImage.TYPE_INT_RGB.

Исправление приводит к тому, что исключение выдается на ato.filter(image, scaledImage)
Exception in thread "main" java.awt.image.ImagingOpException: Unable to transform src image

Я не знаю, в чем причина этого исключения и как его исправить, но с использованием Graphics2D объект для масштабирования и рендеринга изображения работал для меня.

Несмотря на то, что создан правильный файл изображения, но он содержит только черный фон. И это потому, что предоставленные значения scale() были несовместимы.

Ниже приведен окончательный код, в котором это работает успешно, и как были исправлены точки 2 и 3.

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
}
...