diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageConverter.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageConverter.kt index 7ad987d33..f04594848 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageConverter.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageConverter.kt @@ -3,6 +3,8 @@ package org.gotson.komga.infrastructure.image import mu.KotlinLogging import net.coobird.thumbnailator.Thumbnails import org.springframework.stereotype.Service +import java.awt.Color +import java.awt.image.BufferedImage import java.io.ByteArrayOutputStream import javax.imageio.ImageIO @@ -23,11 +25,25 @@ class ImageConverter { logger.info { "Supported write mediaTypes: $supportedWriteMediaTypes" } } + private val supportsTransparency = listOf("png") + fun convertImage(imageBytes: ByteArray, format: String): ByteArray = - ByteArrayOutputStream().use { + ByteArrayOutputStream().use { baos -> val image = ImageIO.read(imageBytes.inputStream()) - ImageIO.write(image, format, it) - it.toByteArray() + + val result = if (!supportsTransparency.contains(format) && containsAlphaChannel(image)) { + if (containsTransparency(image)) logger.info { "Image contains alpha channel but is not opaque, visual artifacts may appear" } + else logger.info { "Image contains alpha channel but is opaque, conversion should not generate any visual artifacts" } + BufferedImage(image.width, image.height, BufferedImage.TYPE_INT_RGB).also { + it.createGraphics().drawImage(image, 0, 0, Color.WHITE, null) + } + } else { + image + } + + ImageIO.write(result, format, baos) + + baos.toByteArray() } fun resizeImage(imageBytes: ByteArray, format: String, size: Int): ByteArray = @@ -38,4 +54,17 @@ class ImageConverter { .toOutputStream(it) it.toByteArray() } + + private fun containsAlphaChannel(image: BufferedImage): Boolean = + image.colorModel.hasAlpha() + + private fun containsTransparency(image: BufferedImage): Boolean { + for (x in 0 until image.width) { + for (y in 0 until image.height) { + val pixel = image.getRGB(x, y) + if (pixel shr 24 == 0x00) return true + } + } + return false + } }