From 9556ae51f262470b1fbb5fd9af2d8caeb3c1fa64 Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Fri, 8 May 2020 15:43:04 +0800 Subject: [PATCH] fix: ignore alpha channel on image conversion if image to convert targets a format that doesn't support transparency, but contains alpha channel, then the alpha channel will be ignore. Non-opaque images may produce visual artifacts. related to #153 --- .../infrastructure/image/ImageConverter.kt | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) 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 + } }