Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
kermit = "2.0.8"
kotlin = "2.4.0"
kotlinx-coroutines = "1.11.0"
compose = "1.11.1"
compose = "1.12.0"
detekt = "1.23.8"
ktlint = "12.1.2"
nucleus = "2.4.4"
nucleus-plugin = "2.4.4"
nucleus = "2.5.0"
nucleus-plugin = "2.5.0"

[libraries]
kermit = { module = "co.touchlab:kermit", version.ref = "kermit" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.ImageComposeScene
import kotlinx.coroutines.Dispatchers
import org.jetbrains.skia.Bitmap
import org.jetbrains.skia.Data
import org.jetbrains.skia.EncodedImageFormat
import org.jetbrains.skia.FilterMipmap
import org.jetbrains.skia.FilterMode
Expand Down Expand Up @@ -84,7 +85,7 @@ object ComposableIconUtils {
throw e
}

val iconData =
val image =
if (iconRenderProperties.requiresScaling) {
scaledBitmap =
Bitmap().apply {
Expand All @@ -98,14 +99,12 @@ object ComposableIconUtils {
)

scaledImage = Image.makeFromBitmap(scaledBitmap)
scaledImage.encodeToData(EncodedImageFormat.PNG)
?: throw Exception("Failed to encode scaled image to PNG")
scaledImage
} else {
renderedIcon.encodeToData(EncodedImageFormat.PNG)
?: throw Exception("Failed to encode image to PNG")
renderedIcon
}

return iconData.bytes
return image.encodeToPngBytes()
} finally {
// Ensure proper cleanup
try {
Expand All @@ -119,6 +118,28 @@ object ComposableIconUtils {
}
}

/**
* Encodes an [Image] to PNG bytes, tolerating Skiko binary signature changes.
*
* Skiko 0.150 added a `pngCompressionLevel` parameter to [Image.encodeToData], which breaks
* the synthetic `$default` bridge across versions in both directions (see
* NucleusFramework/Nucleus#594). When the direct call fails with [NoSuchMethodError] because
* the runtime ships an older Skiko, fall back to the legacy two-argument overload via
* reflection.
*/
private fun Image.encodeToPngBytes(): ByteArray {
val data =
try {
encodeToData(EncodedImageFormat.PNG)
} catch (e: NoSuchMethodError) {
debugln { "[ComposableIconUtils] encodeToData signature mismatch, using legacy overload: ${e.message}" }
Image::class.java
.getMethod("encodeToData", EncodedImageFormat::class.java, Int::class.javaPrimitiveType)
.invoke(this, EncodedImageFormat.PNG, 100) as Data?
} ?: throw Exception("Failed to encode image to PNG")
return data.use { it.bytes }
}

/**
* Renders a Composable to an ICO file and returns the path to the file.
*
Expand Down
Loading