Skip to content

Commit c72054d

Browse files
committed
Added support for WebP scaling
Signed-off-by: Arnau Mora Gras <[email protected]>
1 parent 6ef7f6d commit c72054d

File tree

9 files changed

+63
-13
lines changed

9 files changed

+63
-13
lines changed

build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ dependencies {
6969
// Crowdin localization
7070
implementation(libs.crowdin)
7171

72+
// WebP image support
73+
implementation(libs.imageio.webp)
74+
7275

7376
testImplementation(libs.kotlin.test)
7477

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
crowdin = "1.14.1"
33
exposed = "0.47.0"
44
foojay-resolver = "0.8.0"
5+
imageio-webp = "0.1.6"
56
json = "20240205"
67
kotlin = "1.9.22"
78
kotlinx-kover = "0.7.6"
@@ -13,6 +14,7 @@ sqlite = "3.44.0.0"
1314

1415
[libraries]
1516
crowdin = { module = "com.github.crowdin:crowdin-api-client-java", version.ref = "crowdin" }
17+
imageio-webp = { module = "org.sejda.imageio:webp-imageio", version.ref = "imageio-webp" }
1618
json = { module = "org.json:json", version.ref = "json" }
1719
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
1820
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }

package/version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.32
1+
1.0.33

src/main/kotlin/server/endpoints/files/DownloadFileEndpoint.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ object DownloadFileEndpoint : EndpointBase("/download/{uuid}") {
4141
call.response.header("Content-Type", contentType)
4242
}
4343

44-
if (listOf("png", "jpeg", "jpg").any { file.extension.equals(it, true) }) {
44+
if (ImageUtils.supportedExtensions.any { file.extension.equals(it, true) }) {
4545
// File is image, resizing is supported
4646
if (width != null || height != null) {
4747
// Respond the image resized

src/main/kotlin/utils/ImageUtils.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ object ImageUtils {
1717
private const val TRUNCATED_BYTE_A: Byte = (0xff).toByte()
1818
private const val TRUNCATED_BYTE_B: Byte = (0xd9).toByte()
1919

20+
val supportedExtensions = listOf("png", "jpeg", "jpg", "webp")
21+
2022
/**
2123
* Verifies the integrity of an image file.
2224
*
@@ -66,7 +68,7 @@ object ImageUtils {
6668
var truncated: Boolean? = null
6769
}
6870

69-
suspend fun scale(imageFile: File, width: Int?, height: Int?, outputStream: OutputStream) {
71+
suspend fun scale(imageFile: File, width: Int?, height: Int?, outputStream: OutputStream, format: String = "webp") {
7072
withContext(Dispatchers.IO) {
7173
check(width != null || height != null) { "Must provide either width, height or both, but not none." }
7274

@@ -93,7 +95,7 @@ object ImageUtils {
9395
val imageBuff = BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB)
9496
imageBuff.graphics.drawImage(scaledImage, 0, 0, Color(0, 0, 0), null)
9597

96-
ImageIO.write(imageBuff, "jpg", outputStream)
98+
ImageIO.write(imageBuff, format, outputStream)
9799
}
98100
}
99101
}

src/test/kotlin/server/DataProvider.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ object DataProvider {
3636
skipDisplayName: Boolean = false,
3737
skipWebUrl: Boolean = false,
3838
skipImage: Boolean = false,
39+
imageFile: String = "/images/alcoi.jpg",
3940
assertion: suspend HttpResponse.() -> Int? = {
4041
var areaId: Int? = null
4142
assertSuccess(HttpStatusCode.Created) { data ->
@@ -46,7 +47,7 @@ object DataProvider {
4647
areaId
4748
}
4849
): Int? {
49-
val image = this::class.java.getResourceAsStream("/images/alcoi.jpg")!!.use {
50+
val image = this::class.java.getResourceAsStream(imageFile)!!.use {
5051
it.readBytes()
5152
}
5253

src/test/kotlin/server/endpoints/files/TestFileDownloading.kt

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ import server.DataProvider
1818
import server.base.ApplicationTestBase
1919

2020
class TestFileDownloading : ApplicationTestBase() {
21-
private suspend inline fun ApplicationTestBuilder.provideImageFile(block: (imageUUID: String) -> Unit) {
22-
val areaId = DataProvider.provideSampleArea()
21+
private suspend inline fun ApplicationTestBuilder.provideImageFile(
22+
imageFile: String = "/images/alcoi.jpg",
23+
block: (imageUUID: String) -> Unit
24+
) {
25+
val areaId = DataProvider.provideSampleArea(imageFile = imageFile)
2326

2427
var image: String? = null
2528

@@ -95,4 +98,27 @@ class TestFileDownloading : ApplicationTestBase() {
9598
}
9699
}
97100
}
101+
102+
@Test
103+
fun `test downloading resized files (webp)`() = test {
104+
provideImageFile("/images/alcoi.webp") { image ->
105+
val tempFile = File.createTempFile("eaic", null)
106+
val response = get("/download/$image?height=200")
107+
assertTrue(
108+
response.status.isSuccess(),
109+
"Got a non-successful response from server. Status: ${response.status}"
110+
)
111+
112+
val channel = response.bodyAsChannel()
113+
channel.copyAndClose(tempFile.writeChannel())
114+
115+
try {
116+
val img: BufferedImage? = ImageIO.read(tempFile)
117+
assertNotNull(img)
118+
assertEquals(200, img.height)
119+
} finally {
120+
tempFile.delete()
121+
}
122+
}
123+
}
98124
}

src/test/kotlin/utils/ImageUtilsTest.kt

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import io.ktor.test.dispatcher.testSuspend
44
import java.awt.image.BufferedImage
55
import java.io.ByteArrayOutputStream
66
import java.io.File
7+
import java.nio.file.Files
78
import javax.imageio.ImageIO
89
import kotlin.test.Test
910
import kotlin.test.assertEquals
@@ -19,23 +20,35 @@ class ImageUtilsTest {
1920
}
2021
}
2122

22-
private fun testResize(width: Int? = null, height: Int? = null) = testSuspend {
23+
private fun testResize(
24+
resource: String,
25+
width: Int? = null,
26+
height: Int? = null,
27+
format: String = "webp"
28+
) = testSuspend {
29+
val name = resource.substringAfterLast('/')
30+
val nameWithoutExtension = name.substringBeforeLast('.')
2331
// Create temp files
24-
val file = File.createTempFile("test_scaling_original-", "-alcoi.jpg")
25-
val fileScaled = File.createTempFile("test_scaling_resized-", "-alcoi.avif")
32+
val file = File.createTempFile("test_scaling_original-", "-$name")
33+
val fileScaled = File.createTempFile("test_scaling_resized-", "-$nameWithoutExtension.$format")
2634
// Store the original image size
2735
val (originalWidth, originalHeight) = 1578 to 720
2836
val originalRatio = originalWidth.toDouble() / originalHeight
2937
try {
3038
// Create the resource as File
31-
this::class.java.getResourceAsStream("/images/alcoi.jpg")!!.use { input ->
39+
this::class.java.getResourceAsStream(resource)!!.use { input ->
3240
file.outputStream().use { output -> input.copyTo(output) }
3341
}
3442
fileScaled.outputStream().use { output ->
3543
ImageUtils.scale(file, width, height, output)
3644
}
3745
println("Scaled file: ${fileScaled.absolutePath}")
46+
3847
assertTrue(fileScaled.exists())
48+
49+
val mimeType = Files.probeContentType(fileScaled.toPath())
50+
assertEquals("image/$format", mimeType)
51+
3952
val img: BufferedImage? = ImageIO.read(fileScaled)
4053
assertNotNull(img)
4154
val (scaledWidth, scaledHeight) = img.width to img.height
@@ -54,8 +67,11 @@ class ImageUtilsTest {
5467

5568

5669
@Test
57-
fun `test image scaling - change width`() = testResize(width = 100)
70+
fun `test image scaling - change width`() = testResize("/images/alcoi.jpg", width = 100)
71+
72+
@Test
73+
fun `test image scaling - change height`() = testResize("/images/alcoi.jpg", height = 100)
5874

5975
@Test
60-
fun `test image scaling - change height`() = testResize(height = 100)
76+
fun `test image scaling (webp)`() = testResize("/images/alcoi.webp", width = 100)
6177
}
400 KB
Loading

0 commit comments

Comments
 (0)