My name is Seiko, an Android software engineer.
- 🌱 I'm currently learning ComposeUI
- 📫 How to reach me:
- Email: [email protected]
- ⚡ I'm not a computer major, just like programming.
Compose Image library for Kotlin Multiplatform.
Home Page: https://qdsfdhvh.github.io/compose-imageloader/
License: MIT License
My name is Seiko, an Android software engineer.
The documentation doesn't show how to set an image. I've tried ChatGTP solutions and other solutions like below (which has worked finally) but it does work when given a URL to the image, only works when the below type of data is given.Hence it would be useful if doc showed how to create an Image using this library.
CompositionLocalProvider{
val url = "data:image/jpeg;base64,/9j/4"
val painter = rememberAsyncImagePainter(url)
Image(painter, null)
}
Hi after adding compose-imageloader dependency in my compose multiplatform project, i m getting following error in web app console and app is not loading anything:
caught Error: Error loading module 'compose-instagram-clone-multiplatform'. Its dependency '@js-joda/core' was not found. Please, check whether '@js-joda/core' is loaded prior to 'compose-instagram-clone-multiplatform'.
where compose-instagram-clone-multiplatform is my project name just for clarifications.
If i remove this dependency , it works fine. any idea about this issue?
Hi
val painter = rememberImagePainter(
url = "https://example.com/image",
imageLoader = generateImageLoader()
)
Image(
modifier = Modifier.size(70.dp, 70.dp).clip(CircleShape),
painter = painter,
contentDescription = null
)
@Composable
fun generateImageLoader(
tokenManager: TokenManager = koinInject()
): ImageLoader {
return ImageLoader {
components {
setupDefaultComponents(
httpClient = {
HttpClient{
defaultRequest {
bearerAuth(tokenManager.getAuthorization)
}
}
}
)
}
}
}
Hi
when i set image loader for rememberImagePainter, i got the following error:
io.ktor.client.HttpClient -- REQUEST https://example.com/image failed with exception: java.util.concurrent.CancellationException: The coroutine scope left the composition
how can i fix that?
Exception in thread "AWT-EventQueue-0" java.lang.ArithmeticException: / by zero at com.seiko.imageloader.util.GifPainter.update(GifPainter.kt:62)
Test: gif image without animation
Supporting tvos should be a very simple add-on. Supporting tvos is the same as supporting ios.
All you would need to do is add the following kotlin multiplatform build targets:
tvosArm64()
tvosX64()
tvosSimulatorArm64()
For the desktop version you are using the Batik based twelvemonkeys SVG renderer. Why do you do that? All desktop versions are also Skia versions and thus have the Skia SVG built in. It would save people from a lot of dependency downloads if you would drop that. The Skia SVG renderer works nicely on desktop so I don't see any reason to use the Batik one. It would make the final distribution bundles smaller.
Hi! I found an issue related to the recently introduced maxImageSize
option.
The current default cache key generation logic does not take care about the option, so memory cache maybe returns different size images.
I know we can add own custom Keyer implementation to handle the situation, but I think this one should be handled in the library itself.
Repro:
https://github.com/h6ah4i/ComposeImageLoaderMemCacheConfliction
Expected | Actual (the right image is NOT scaled) |
---|---|
For this part of your example usage code
private fun generateImageLoader(): ImageLoader {
return ImageLoaderBuilder().build()
}
IntelliJ is giving me the error message
Expected class ImageLoaderBuilder does not have default constructor
This must be an IntelliJ issue because the code compiles and runs just well but maybe this error message could be avoided if you would just provide that default constructor in your code.
Otherwise your code seems to work nicely. Great job!
I just updated from 1.2.0 to 1.2.9. It's a little odd to see breaking API changes in a bug version change. Are you following semantic versioning?
How to put a placeholder image?
Or at least for now able to know if loading of image is successful or not.
Hey! thanks for making this library.
I am using version 1.2.9. It's working on ios and android and not on desktops only.
library version: 1.2.9
kotlin version = 1.8.0
compose version = "1.3.0"
Stack trace:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Module with the Main dispatcher had failed to initialize. For tests Dispatchers.setMain from kotlinx-coroutines-test module can be used
at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.missing(MainDispatchers.kt:118)
at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.isDispatchNeeded(MainDispatchers.kt:96)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:319)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source)
at kotlinx.coroutines.flow.FlowKt__CollectKt.launchIn(Collect.kt:49)
at kotlinx.coroutines.flow.FlowKt.launchIn(Unknown Source)
at com.seiko.imageloader.AsyncImagePainter.onRemembered(AsyncImagePainter.kt:140)
at androidx.compose.runtime.CompositionImpl$RememberEventDispatcher.dispatchRememberObservers(Composition.kt:1091)
at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:818)
at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:839)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:585)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:503)
at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42)
at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71)
at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:411)
at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:326)
at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:325)
at androidx.compose.ui.awt.ComposeLayer.catchExceptions(ComposeLayer.desktop.kt:109)
at androidx.compose.ui.awt.ComposeLayer.access$catchExceptions(ComposeLayer.desktop.kt:87)
at androidx.compose.ui.awt.ComposeLayer$1.onRender(ComposeLayer.desktop.kt:325)
at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:525)
at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invokeSuspend(MetalRedrawer.kt:50)
at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelled}@6a8d944, Dispatchers.Main[missing, cause=java.lang.NoClassDefFoundError: android/os/Looper]]
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.ui.awt.ComposeLayer$coroutineExceptionHandler$1@bb7cb9, androidx.compose.runtime.BroadcastFrameClock@2b0a0a66, StandaloneCoroutine{Cancelling}@2f02b1ff, FlushCoroutineDispatcher@5296454b]
Caused by: java.lang.NoClassDefFoundError: android/os/Looper
at kotlinx.coroutines.android.AndroidDispatcherFactory.createDispatcher(HandlerDispatcher.kt:55)
at kotlinx.coroutines.internal.MainDispatchersKt.tryCreateDispatcher(MainDispatchers.kt:57)
at kotlinx.coroutines.internal.MainDispatcherLoader.loadMainDispatcher(MainDispatchers.kt:38)
at kotlinx.coroutines.internal.MainDispatcherLoader.<clinit>(MainDispatchers.kt:22)
at kotlinx.coroutines.Dispatchers.getMain(Dispatchers.kt:57)
at com.seiko.imageloader.ImageLoaderConfigBuilder.<init>(ImageLoaderConfig.kt:20)
at com.seiko.imageloader.ImageLoaderConfigKt.ImageLoaderConfig(ImageLoaderConfig.kt:47)
at com.seiko.imageloader.ImageLoaderKt.ImageLoader(ImageLoader.kt:22)
at com.seiko.imageloader.ImageLoaderKt.ImageLoader$default(ImageLoader.kt:17)
at com.seiko.imageloader.LocalImageLoader_desktopKt$createImageLoaderProvidableCompositionLocal$1.invoke(LocalImageLoader.desktop.kt:25)
at com.seiko.imageloader.LocalImageLoader_desktopKt$createImageLoaderProvidableCompositionLocal$1.invoke(LocalImageLoader.desktop.kt:24)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at androidx.compose.runtime.LazyValueHolder.getCurrent(ValueHolders.kt:29)
at androidx.compose.runtime.LazyValueHolder.getValue(ValueHolders.kt:31)
at androidx.compose.runtime.ComposerImpl.resolveCompositionLocal(Composer.kt:1981)
at androidx.compose.runtime.ComposerImpl.consume(Composer.kt:1949)
at com.seiko.imageloader.AsyncImagePainterKt.rememberAsyncImagePainter-DJqXB-Q(AsyncImagePainter.kt:225)
at com.kashif.common.presentation.components.AsyncImageKt.AsyncImage(AsyncImage.kt:16)
at com.kashif.common.presentation.AppKt$MovieCard$2.invoke(App.kt:152)
at com.kashif.common.presentation.AppKt$MovieCard$2.invoke(App.kt:149)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.material.SurfaceKt$Surface$1.invoke(Surface.kt:134)
at androidx.compose.material.SurfaceKt$Surface$1.invoke(Surface.kt:117)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.material.SurfaceKt.Surface-F-jzlyU(Surface.kt:114)
at androidx.compose.material.CardKt.Card-F-jzlyU(Card.kt:68)
at com.kashif.common.presentation.AppKt.MovieCard(App.kt:145)
at com.kashif.common.presentation.AppKt$MoviesScreen$1$1$invoke$$inlined$items$default$4.invoke(LazyDsl.kt:424)
at com.kashif.common.presentation.AppKt$MoviesScreen$1$1$invoke$$inlined$items$default$4.invoke(LazyDsl.kt:145)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:135)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.foundation.lazy.LazyListItemProviderImpl$1.invoke(LazyListItemProvider.kt:80)
at androidx.compose.foundation.lazy.LazyListItemProviderImpl$1.invoke(LazyListItemProvider.kt:79)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:135)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.foundation.lazy.layout.DefaultLazyLayoutItemsProvider.Item(LazyLayoutItemProvider.kt:118)
at androidx.compose.foundation.lazy.LazyListItemProviderImpl.Item(LazyListItemProvider.kt)
at androidx.compose.foundation.lazy.layout.DefaultDelegatingLazyLayoutItemProvider.Item(LazyLayoutItemProvider.kt:197)
at androidx.compose.foundation.lazy.LazyListItemProviderKt$rememberLazyListItemProvider$1$1.Item(LazyListItemProvider.kt)
at androidx.compose.foundation.lazy.layout.LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1$1.invoke(LazyLayoutItemContentFactory.kt:99)
at androidx.compose.foundation.lazy.layout.LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1$1.invoke(LazyLayoutItemContentFactory.kt:98)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.runtime.saveable.SaveableStateHolderImpl.SaveableStateProvider(SaveableStateHolder.kt:84)
at androidx.compose.foundation.lazy.layout.LazySaveableStateHolder.SaveableStateProvider(LazySaveableStateHolder.kt:84)
at androidx.compose.foundation.lazy.layout.LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1.invoke(LazyLayoutItemContentFactory.kt:98)
at androidx.compose.foundation.lazy.layout.LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1.invoke(LazyLayoutItemContentFactory.kt:90)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:145)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2375)
at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2643)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3260)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3238)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3238)
at androidx.compose.runtime.ComposerImpl.recompose$runtime(Composer.kt:3203)
at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:771)
at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1031)
at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:125)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:534)
... 30 more
Caused by: java.lang.ClassNotFoundException: android.os.Looper
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 96 more
This is the stack trace i am getting as a result of the crash
This code in your Android SVG decoder
if (svg.documentSVGVersion.startsWith("2")) {
throw RuntimeException("Un support SVG version '2.0'")
}
results in an NPE for many of my icons because documentSVGVersion returns null. After replacing this with
if (svg.documentSVGVersion != null && svg.documentSVGVersion.startsWith("2")) {
throw RuntimeException("Un support SVG version '2.0'")
}
everything was good again.
After adding image-loader api dependency to commonMain in shared build.gradle.kts, androidx.compose.ui.window.Popup imports cannot be found in commonMain kotlin files with error (Unresolved reference: Popup)
Hello. I have a problem with your library.
This is result when i'm loading picture via your library:
This is the picture:
Actual fun:
@Composable actual fun rememberAsyncImagePainter(fileResource: FileResource): AsyncImagePainter { return rememberAsyncImagePainter(fileResource.rawResId) }
Expect fun:
@Composable expect fun rememberAsyncImagePainter(fileResource: FileResource): AsyncImagePainter
Note: files storage is provided by Moko-Resources
Libraries versions:
imageloader: 1.2.10 (upgrading to 1.3.1 did no impact)
compose: 1.3.0-rc05
moko-resources: 0.20.1
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These problems occurred while renovating this repository. View logs.
Warning
Renovate failed to look up the following dependencies: Could not determine new digest for update (github-tags package dawidd6/action-download-artifact)
.
Files affected: .github/workflows/CompareScreenshotComment.yml
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
io.ktor:ktor-client-js-js
, io.ktor:ktor-client-cio
, io.ktor:ktor-client-darwin
, io.ktor:ktor-client-okhttp
, io.ktor:ktor-client-content-negotiation
, io.ktor:ktor-client-logging
, io.ktor:ktor-client-core
, io.ktor:ktor-serialization-kotlinx-json
)These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
@docusaurus/core
, @docusaurus/module-type-aliases
, @docusaurus/preset-classic
)io.ktor:ktor-client-js-wasm-js
, io.ktor:ktor-client-js-js
, io.ktor:ktor-client-cio
, io.ktor:ktor-client-darwin
, io.ktor:ktor-client-okhttp
, io.ktor:ktor-client-content-negotiation
, io.ktor:ktor-client-logging
, io.ktor:ktor-client-core
, io.ktor:ktor-serialization-kotlinx-json
).github/workflows/Check.yml
actions/checkout v4
gradle/wrapper-validation-action v3
actions/setup-java v3
actions/checkout v4
gradle/wrapper-validation-action v3
actions/setup-java v3
actions/checkout v4
gradle/wrapper-validation-action v3
actions/setup-java v3
actions/upload-artifact v4
actions/checkout v4
gradle/wrapper-validation-action v3
actions/setup-java v3
actions/checkout v4
gradle/wrapper-validation-action v3
actions/setup-java v3
.github/workflows/CompareScreenshot.yml
actions/checkout v4.1.7@692973e3d937129bcbf40652eb9f2f61becf3332
actions/setup-java v3.13.0@0ab4596768b603586c0de567f2430c30f5b0d2b0
gradle/gradle-build-action v3.4.2@66535aaf56f831b35e3a8481c9c99b665b84dd45
dawidd6/action-download-artifact v6
actions/upload-artifact v4
actions/upload-artifact v4
actions/upload-artifact v4
actions/upload-artifact v4
.github/workflows/CompareScreenshotComment.yml
dawidd6/action-download-artifact v2.28.1@f29d1b6a8930683e80acedfbe6baa2930cd646b4
actions/checkout v4
dawidd6/action-download-artifact v2.28.1@f29d1b6a8930683e80acedfbe6baa2930cd646b4
peter-evans/find-comment v3
peter-evans/create-or-update-comment v4
.github/workflows/DocsDeploy.yml
actions/checkout v4
gradle/wrapper-validation-action v3
actions/setup-java v3
gradle/gradle-build-action v3
actions/setup-node v4
peaceiris/actions-gh-pages v4
.github/workflows/DocsTest.yml
actions/checkout v4
gradle/wrapper-validation-action v3
actions/setup-java v3
gradle/gradle-build-action v3
actions/setup-node v4
.github/workflows/Publish.yml
actions/checkout v4
gradle/wrapper-validation-action v3
actions/setup-java v3
gradle/gradle-build-action v3
actions/checkout v4
softprops/action-gh-release v2
.github/workflows/StoreScreenshot.yml
actions/checkout v4.1.7@692973e3d937129bcbf40652eb9f2f61becf3332
actions/setup-java v3.13.0@0ab4596768b603586c0de567f2430c30f5b0d2b0
gradle/gradle-build-action v3.4.2@66535aaf56f831b35e3a8481c9c99b665b84dd45
actions/upload-artifact v4
actions/upload-artifact v4
actions/upload-artifact v4
gradle.properties
settings.gradle.kts
com.gradle.enterprise 3.17.5
build.gradle.kts
app/android/build.gradle.kts
app/android/benchmark/build.gradle.kts
app/common/gradle.properties
app/common/build.gradle.kts
app/desktop/build.gradle.kts
app/intellij-plugin/build.gradle.kts
org.jetbrains.intellij 1.17.3
app/macos/build.gradle.kts
app/wasmJs/build.gradle.kts
app/web/build.gradle.kts
build-logic/gradle.properties
build-logic/settings.gradle.kts
build-logic/convention/build.gradle.kts
extension/compose-resources/gradle.properties
extension/compose-resources/build.gradle.kts
extension/imageio/gradle.properties
extension/imageio/build.gradle.kts
com.twelvemonkeys.imageio:imageio-batik 3.11.0
org.apache.xmlgraphics:batik-transcoder 1.17
extension/ktor-network/gradle.properties
extension/ktor-network/build.gradle.kts
extension/moko-resources/gradle.properties
extension/moko-resources/build.gradle.kts
dev.icerock.moko:resources 0.24.1
extension/nine-patch/gradle.properties
extension/nine-patch/build.gradle.kts
extension/svg/gradle.properties
extension/svg/build.gradle.kts
gradle/libs.versions.toml
com.android.tools.build:gradle 8.5.0
org.jetbrains.kotlin:kotlin-gradle-plugin 2.0.0
org.jetbrains.compose:compose-gradle-plugin 1.6.11
org.jetbrains.kotlin:compose-compiler-gradle-plugin 2.0.0
org.jetbrains.kotlinx:kotlinx-coroutines-core 1.8.1
org.jetbrains.kotlinx:kotlinx-coroutines-test 1.8.1
org.jetbrains.kotlinx:kotlinx-coroutines-android 1.8.1
org.jetbrains.kotlinx:kotlinx-coroutines-swing 1.8.1
org.jetbrains.kotlinx:kotlinx-serialization-json 1.7.1
androidx.core:core-ktx 1.13.1
androidx.collection:collection 1.4.0
androidx.appcompat:appcompat-resources 1.7.0
androidx.exifinterface:exifinterface 1.3.7
androidx.activity:activity-compose 1.9.0
androidx.lifecycle:lifecycle-runtime-ktx 2.8.2
junit:junit 4.13.2
androidx.test.ext:junit 1.1.5
androidx.test.espresso:espresso-core 3.5.1
androidx.test.uiautomator:uiautomator 2.3.0
androidx.benchmark:benchmark-macro-junit4 1.2.4
androidx.profileinstaller:profileinstaller 1.3.1
org.robolectric:robolectric 4.12.2
io.github.takahirom.roborazzi:roborazzi 1.20.0
io.github.takahirom.roborazzi:roborazzi-junit-rule 1.20.0
io.github.takahirom.roborazzi:roborazzi-compose 1.20.0
io.github.takahirom.roborazzi:roborazzi-compose-desktop 1.20.0
com.squareup.okio:okio 3.9.0
com.squareup.okio:okio-fakefilesystem 3.9.0
io.ktor:ktor-serialization-kotlinx-json 2.3.11
io.ktor:ktor-client-core 2.3.11
io.ktor:ktor-client-logging 2.3.11
io.ktor:ktor-client-content-negotiation 2.3.11
io.ktor:ktor-client-okhttp 2.3.11
io.ktor:ktor-client-darwin 2.3.11
io.ktor:ktor-client-cio 2.3.11
io.ktor:ktor-client-js-js 2.3.11
io.ktor:ktor-client-js-wasm-js 2.3.11
com.eygraber:uri-kmp 0.0.18
co.touchlab:kermit 2.0.4
com.caverock:androidsvg-aar 1.4
com.darkrockstudios:mpfilepicker 3.1.0
com.android.application 8.5.0
com.android.library 8.5.0
com.android.test 8.5.0
org.jetbrains.kotlin.jvm 2.0.0
org.jetbrains.kotlin.android 2.0.0
org.jetbrains.kotlin.multiplatform 2.0.0
org.jetbrains.kotlin.plugin.serialization 2.0.0
org.jetbrains.kotlin.plugin.compose 2.0.0
org.jetbrains.compose 1.6.11
com.diffplug.spotless 6.25.0
com.vanniktech.maven.publish 0.29.0
org.jetbrains.dokka 1.9.20
androidx.baselineprofile 1.2.4
io.github.takahirom.roborazzi 1.20.0
dev.drewhamilton.poko 0.16.0
image-loader/gradle.properties
image-loader/build.gradle.kts
image-loader-singleton/gradle.properties
image-loader-singleton/build.gradle.kts
gradle/wrapper/gradle-wrapper.properties
gradle 8.8
docs/package.json
@docusaurus/core 2.4.3
@docusaurus/preset-classic 2.4.3
@mdx-js/react ^1.6.22
clsx ^1.2.1
prism-react-renderer ^1.3.5
react ^18.0.0
react-dom ^18.0.0
@docusaurus/module-type-aliases 2.4.3
node >=16.14
After I built in the function to calculate the size of the application's cache, I found the following behavior:
every time I open a screen with multiple images (including GIFs), the application cache size increases by 6MB (images are always the same)
This behavior only happens on a real device with Android 9.0
The files have the format name tmp[NUMBER].tmp
The files are created at /data/user/0/[App]/cache/
and may not have a space limit.
Through searching for tmp
I found this line:
The original files are also located along the path /data/user/0/[App]/cache/image_cache
I have a ImageLoader with DiskCache and MemoryCache configured but it seems to only be using the MemoryCache. My images use a custom class that I have Mappers and Keyers setup for but it doesnt seem to allow them to be inserted into the DiskCache even though they are loading the images. This happens on both Desktop and Android.
I have tried with multiple configurations using the builder and even disabling the memory cache, which does not seem to help. It doesnt seem like its hitting the DiskCacheInterceptor at all and Napier says nothing about errors.
In general I cannot figure out whats wrong.
I tried using this with compose 1.4.0-dev-wasm06
and it conflicts with that version, so I cannot use it
Thank you for maintaining this library! We desperately need something like this in the community.
The documentation is a little lacking, primarily on compatibility with what versions of Kotlin and Compose. I'm about to try out your library and I'm not confident whether it will work with my version of Kotlin / Compose.
There are also other things that seem to be lacking in the documentation around the configurability of the memory and disk caches.
I am trying to implement this section Memory/Disk cache support on all platforms.
Aside from README file, I can't find usage in the sample code.
Questions:
//actuals on the platforms:
//Android
actual fun ComponentRegistryBuilder.setupDefaultComponents() = this.setupDefaultComponents(App.context)
actual fun getImageCacheDirectoryPath(): Path = App.context.cacheDir.absolutePath.toPath()
//iOS
actual fun ComponentRegistryBuilder.setupDefaultComponents() = this.setupDefaultComponents()
actual fun getImageCacheDirectoryPath(): Path {
val cacheDir = NSSearchPathForDirectoriesInDomains(
NSCachesDirectory,
NSUserDomainMask,
true
).first() as String
return (cacheDir + "/media").toPath()
}
//Desktop
actual fun ComponentRegistryBuilder.setupDefaultComponents() = this.setupDefaultComponents()
actual fun getImageCacheDirectoryPath(): Path = "media/".toPath()
App
in App.context.
?I am very new to Kotlin Multiplatform, so can't get it at first if this is quite obvious to you.
Hi,
I clone the project and try to build it, but the gradle sync failed.
The error :
'pod install' command failed with code 1.
Full command: pod install
Error message:
Analyzing dependencies
[!] CocoaPods could not find compatible versions for pod "combine":
In Podfile:
combine (from `../ios-combine`)
Specs satisfying the `combine (from `../ios-combine`)` dependency were found, but they required a higher minimum deployment target.
Please, check that podfile contains following lines in header:
source 'https://cdn.cocoapods.org'
Please, check that each target depended on combine contains following dependencies:
Kotlin 1.9.0 came.
Please use Kotlin 1.9.0.
After update to 1.5.1 (from 1.3.1), there is broken size of some downloaded SVG images. I would like the image to fill the entire image view. Here's en example of two similar SVG images and comparison with Coil-Compose:
As you can see, one of the images has broken size and setting contentScale or other imageLoader options has no effect to it.
Here's my code:
Image(
painter = rememberAsyncImagePainter(
url = url,
contentScale = ContentScale.FillWidth,
),
contentDescription = null,
modifier = Modifier
.size(50.dp)
.background(color = Color.Red),
contentScale = ContentScale.FillWidth,
)
I have attached a demo project - ImageDemo.zip
Versions:
ImageLoader - 1.5.1
Kotlin - 1.8.20
Compose - 1.4.0
Gradle - 8.0.2
Thank you for producing and sharing this library; the power of the Compose/Multiplatform ecosystem is beginning to show!
While the cross-platform ability is great; I noticed you have focused API's on loading resources asynchronously.
My use case is for showing SVG (and potentially other format) files from local bytes which are much faster to load and so the overhead of managing a progress 'spinner' etc. is undesirable.
If you are planning any major new features for this library; please consider building API's intended for local resources: that take byte data for images directly, and minimise overhead to display.
Seems that 1.5.2 includes a25bfd7 which now targets JDK 17. Why?
This breaks Android builds (which only really support up to JDK 11).
hey, thanks for the work on this.
we're trying to adopt this library for js, but version 1.2.8 doesn't seem to be working for us (nothing loads). our code is fairly straightforward:
onWasmReady {
Window("") {
CompositionLocalProvider(
LocalImageLoader provides ImageLoader {
logger = DebugLogger(LogPriority.VERBOSE)
components {
setupDefaultComponents(imageScope)
}
interceptor {
memoryCacheConfig {
maxSizePercent(0.25)
}
}
},
) {
Image(
modifier = Modifier.fillMaxSize(),
painter = rememberAsyncImagePainter("https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png"),
contentDescription = "",
contentScale = ContentScale.Crop,
)
}
}
}
this roughly matches the image loader configuration in the js sample here. i've also tried with just ImageLoader { }
and also without providing our own. but unfortunately, all approaches have resulted in nothing loading.
here are the logs we're seeing:
DEBUG MappedInterceptor : [image data] https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
[message] map -> https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
build.umd.js:3103 WARNING AsyncImagePainter : [image data] https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
[message] load image error
the last version I tried was 1.2.5 and that worked without a problem, but we're looking to update to jb-compose:1.3.0.
any thoughts?
Would it be possible to provide a Bitmap or Drawable in addition to Painter when the image is successfully downloaded in Android target similar to Coil-Compose?
Coil:
DisposableEffect(url) {
val request = ImageRequest.Builder(context)
.data(data = url)
.target { drawable ->
val bitmap = drawable.toBitmapOrNull() ?: return@target
// TODO use bitmap
}
.build()
val disposable = ImageLoader.Builder(context)
.components { add(SvgDecoder.Factory()) }
.build()
.enqueue(request)
onDispose {
disposable.dispose()
}
}
Hello,
Thanks for the SDK. I'm using this beautiful imageLoader in my KMM android-ios project. The iOS application crashes when fast scrolling, but this situation does not occur when 'rememberCoroutineScope()' is passed to imageLoader for iOS consumer app.
The error report when I debug it with Xcode ,
MidJourney Images Compose Multiplatform`:
0x1027e1378 <+92>: bl 0x10312e9cc ; EnterFrame
0x1027e137c <+96>: adrp x8, 6570
0x1027e1380 <+100>: add x8, x8, #0xcdc ; kotlin::mm::internal::gSuspensionRequested
0x1027e1384 <+104>: ldarb w8, [x8]
0x1027e1388 <+108>: tbz w8, #0x0, 0x1027e1398 ; <+124> at MetalRedrawer.ios.kt
0x1027e138c <+112>: b 0x1027e1390 ; <+116> at MetalRedrawer.ios.kt:158:5
0x1027e1390 <+116>: bl 0x103112df4 ; kotlin::mm::SuspendIfRequestedSlowPath()
-> 0x1027e1394 <+120>: b 0x1027e1398 ; <+124> at MetalRedrawer.ios.kt
0x1027e1398 <+124>: b 0x1027e139c ; <+128> at MetalRedrawer.ios.kt
0x1027e139c <+128>: ldr x1, [sp, #0x10]
0x1027e13a0 <+132>: ldur x0, [x29, #-0x8]
0x1027e13a4 <+136>: bl 0x1023affa0 ; interpretObjCPointer
0x1027e13a8 <+140>: str x0, [sp]
0x1027e13ac <+144>: b 0x1027e13b0 ; <+148> at MetalRedrawer.ios.kt
0x1027e13b0 <+148>: ldr x0, [sp]
0x1027e13b4 <+152>: bl 0x1027e11d0 ; kfun:org.jetbrains.skiko.redrawer.FrameTickListener.onDisplayLinkTick#internal at MetalRedrawer.ios.kt
0x1027e13b8 <+156>: b 0x1027e13bc ; <+160> at MetalRedrawer.ios.kt:160:6
0x1027e13bc <+160>: b 0x1027e13c0 ; <+164> at MetalRedrawer.ios.kt
0x1027e13c0 <+164>: ldr x0, [sp, #0x8]
0x1027e13c4 <+168>: mov w1, #0x0
0x1027e13c8 <+172>: mov w2, #0x4
0x1027e13cc <+176>: bl 0x10312ea18 ; LeaveFrame
Where could the error be originating from?
Any recommendations? Thanks 🙏
这里是sample
Hi
I want use imageloader in Lazy Column
how to use that?
Image(
modifier = Modifier
.fillMaxWidth()
.height(200.dp),
painter = rememberImagePainter(product.image),
contentDescription = null
)
If I change the version to 1.2.8. & 1.6.0 & 1.6.8
Then the image loads successfully on android
If the image loader cannot successfully download an image on the first try, then, when caching is enabled, it does not make any attempt to download the image again at a later time. When the disk cache is enabled it does not even retry this when the application is terminated and started again. It seems that even in case of a download error something is stored in the cache which then blocks any further attempts. I tested this by removing my images from my server, then start the application, then copy the images back to the server while the application is still running. Switching screens or restarting the application does not force a re-load of the images. This all works when no caching is configured but this is no option for me.
I have configured caching like this:
fun generateImageLoader(): ImageLoader {
return ImageLoaderBuilder().apply {
diskCache {
DiskCacheBuilder()
.directory("... path to some cache directory ...".toPath())
.maxSizeBytes(1024 * 1024 * 50) // 50 MB
.build()
}
memoryCache {
MemoryCacheBuilder()
.build()
}
}.build()
}
crash in ios.
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Invalid conversion: The generator cannot convert to match the request, ignoring dimensions
at org.jetbrains.skia.Codec$Companion._validateResult$skiko(Codec.kt:28)
at org.jetbrains.skia.Codec.readPixels(Codec.kt:191)
at com.seiko.imageloader.util.GifPainter.onDraw(GifPainter.kt:61)
at androidx.compose.ui.graphics.painter.Painter.draw-x_KDEd0(Painter.kt:212)
at com.seiko.imageloader.AsyncImagePainter.onDraw(AsyncImagePainter.kt:113)
at androidx.compose.ui.graphics.painter.Painter.draw-x_KDEd0(Painter.kt:212)
at androidx.compose.ui.draw.PainterModifier.draw(PainterModifier.kt:281)
at androidx.compose.ui.node.DrawEntity.draw(DrawEntity.kt:98)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:329)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:64)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:351)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2103)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.platform.SkiaLayer.performDrawLayer(SkiaLayer.skiko.kt:264)
at androidx.compose.ui.platform.SkiaLayer.drawLayer(SkiaLayer.skiko.kt:225)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:314)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:64)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:351)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2103)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.platform.SkiaLayer.performDrawLayer(SkiaLayer.skiko.kt:264)
at androidx.compose.ui.platform.SkiaLayer.drawLayer(SkiaLayer.skiko.kt:225)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:314)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:48)
at androidx.compose.foundation.NoIndication$NoIndicationInstance.drawIndication(Indication.kt:136)
at androidx.compose.foundation.IndicationModifier.draw(Indication.kt:183)
at androidx.compose.ui.node.DrawEntity.draw(DrawEntity.kt:98)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:329)
at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:64)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:351)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2103)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.platform.SkiaLayer.performDrawLayer(SkiaLayer.skiko.kt:264)
at androidx.compose.ui.platform.SkiaLayer.drawLayer(SkiaLayer.skiko.kt:225)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:314)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:48)
at androidx.compose.material.ripple.CommonRippleIndicationInstance.drawIndication(CommonRipple.kt:70)
at androidx.compose.foundation.IndicationModifier.draw(Indication.kt:183)
at androidx.compose.ui.node.DrawEntity.draw(DrawEntity.kt:98)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:329)
at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:64)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:351)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2103)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.platform.SkiaLayer.performDrawLayer(SkiaLayer.skiko.kt:264)
at androidx.compose.ui.platform.SkiaLayer.drawLayer(SkiaLayer.skiko.kt:225)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:314)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:48)
at androidx.compose.foundation.Background.draw(Background.kt:107)
at androidx.compose.ui.node.DrawEntity.draw(DrawEntity.kt:98)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:329)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:64)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:351)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2103)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.platform.SkiaLayer.performDrawLayer(SkiaLayer.skiko.kt:264)
at androidx.compose.ui.platform.SkiaLayer.drawLayer(SkiaLayer.skiko.kt:225)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:314)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:64)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:351)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2103)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.platform.SkiaLayer.performDrawLayer(SkiaLayer.skiko.kt:264)
at androidx.compose.ui.platform.SkiaLayer.drawLayer(SkiaLayer.skiko.kt:225)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:314)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:64)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:351)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2103)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.platform.SkiaLayer.performDrawLayer(SkiaLayer.skiko.kt:264)
at androidx.compose.ui.platform.SkiaLayer.drawLayer(SkiaLayer.skiko.kt:225)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:314)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:48)
at androidx.compose.foundation.Background.draw(Background.kt:107)
at androidx.compose.ui.node.DrawEntity.draw(DrawEntity.kt:98)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:329)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:245)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:64)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:351)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2103)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:350)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:186)
at androidx.compose.ui.platform.SkiaLayer.performDrawLayer(SkiaLayer.skiko.kt:264)
at androidx.compose.ui.platform.SkiaLayer.drawLayer(SkiaLayer.skiko.kt:225)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:314)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:143)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:327)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:319)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:933)
at androidx.compose.ui.platform.SkiaBasedOwner.draw(SkiaBasedOwner.skiko.kt:352)
at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:386)
at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:297)
at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:296)
at androidx.compose.ui.awt.ComposeLayer.catchExceptions(ComposeLayer.desktop.kt:96)
at androidx.compose.ui.awt.ComposeLayer.access$catchExceptions(ComposeLayer.desktop.kt:76)
at androidx.compose.ui.awt.ComposeLayer$1.onRender(ComposeLayer.desktop.kt:296)
at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:507)
at org.jetbrains.skiko.redrawer.MetalRedrawer.update(MetalRedrawer.kt:66)
at org.jetbrains.skiko.redrawer.MetalRedrawer.access$update(MetalRedrawer.kt:13)
at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invokeSuspend(MetalRedrawer.kt:38)
at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@511bac43, SwingDispatcher@1882c825
Image cache is not working when buildFeatures.compose is set to true. When Image is recomposed, library try to download image from url again and not hit the cache. When buildFeatures.compose is turned off, the cache is working.
diskCacheConfig {
directory(context.applicationContext.cacheDir.toOkioPath())
maxSizeBytes(512L * 1024 * 1024) // 512MB
}
Versions:
Kotlin = 1.8.10
Gradle = 8.0.2
AGP = 7.4.2
Compose = 1.3.1 (multiplatform)
ImageLoader = 1.3.1 (for 1.4.0 the same result)
I'm not sure if this can help, but by running this test on jsNodeTest you can get a file in a real file system
kotlinx-io js test
Please provide a changelog, or some other means, so we know what version of Compose each version matches with and which version of ktor it uses as well.
version 1.6.2
kotlin 1.8.2
platform ios
compose 1.4.3
i have a code
@Composabe
fun myAsyncImage(url: String) {
val imageAction by rememberImageAction(url)
val painter = rememberImageActionPainter(imageAction)
}
and then i changed a url happend nothing.
workaround
@Composable
private fun fixedRememberImageAction(
url: String,
imageLoader: ImageLoader = LocalImageLoader.current,
): State<ImageAction> {
val request = >>>>remember(url)<<<< { ImageRequest(url) }
return rememberImageAction(request, imageLoader)
}
Please, can you fix the rememberImageAction
?
The new version have removed ImageRequestState.
So how do we now conditionally render loading, error and success states.
Earlier you could do this.
when (painter.requestState) {
is ImageRequestState.Loading -> {}
is ImageRequestState.Failure -> {}
is ImageRequestState.Success -> {}
}
I suppose this partially fixes the problem, but
rememberImageActionPainter(action, placeholderPainter, errorPainter)
But I need to run code when the Image is successfully loaded. How do you do it in these newer versions?
Hello, one of the needs that may arise when using the image library is to be able to display 9-patch images - which can stretch while maintaining angles. My quick glance at Compose suggests that there is no low-level option to draw Nine-patch, unlike Flutter, where there is a special command.
I had such a need and I made a simple draft version of NinePatchPainter
for my tasks. Here you can see an example.
I will leave the source code here in case there is a desire to modify it and integrate it into the library.
Maybe it can become a starting point for the implementation of Nine-patch images.
class NinePatchPainter(
private val image: ImageBitmap,
private val centerSlice: CenterRect,
private val scale: Float = 1f,
private val filterQuality: FilterQuality = FilterQuality.Medium,
) : Painter() {
private val centerWidth = max(1, centerSlice.width)
private val centerHeight = max(1, centerSlice.height)
private val widthLeft = centerSlice.left
private val widthRight = image.width - centerSlice.right
private val heightTop = centerSlice.top
private val heightBottom = image.height - centerSlice.bottom
// Source Offset
private val offsetTopLeft = IntOffset.Zero
private val offsetTop = IntOffset(widthLeft, 0)
private val offsetTopRight = IntOffset(centerSlice.right, 0)
private val offsetLeft = IntOffset(0, heightTop)
private val offsetCenter = IntOffset(centerSlice.left, heightTop)
private val offsetRight = IntOffset(centerSlice.right, heightTop)
private val offsetBottomLeft = IntOffset(0, centerSlice.bottom)
private val offsetBottom = IntOffset(centerSlice.left, centerSlice.bottom)
private val offsetBottomRight = IntOffset(centerSlice.right, centerSlice.bottom)
// Source Size
private val sizeTopLeft = IntSize(widthLeft, heightTop)
private val sizeTop = IntSize(centerWidth, heightTop)
private val sizeTopRight = IntSize(widthRight, heightTop)
private val sizeLeft = IntSize(widthLeft, centerHeight)
private val sizeCenter = IntSize(centerWidth, centerHeight)
private val sizeRight = IntSize(widthRight, centerHeight)
private val sizeBottomLeft = IntSize(widthLeft, heightBottom)
private val sizeBottom = IntSize(centerWidth, heightBottom)
private val sizeBottomRight = IntSize(widthRight, heightBottom)
private val size: IntSize = IntSize(image.width, image.height) // validateSize(IntOffset.Zero, surfaceSize)
private var alpha: Float = 1.0f
private var colorFilter: ColorFilter? = null
override fun DrawScope.onDraw() {
if (image.width < centerSlice.right || image.height < centerSlice.bottom) return println("incorrect bitmap")
val drawWidth = [email protected]()
val drawHeight = [email protected]()
val factor = min(drawWidth / image.width.toFloat(), drawHeight / image.height.toFloat())
val drawScale = min(1f, factor * scale)
val scaleLeft = max(1, (widthLeft * drawScale).toInt())
val scaleRight = max(1, (widthRight * drawScale).toInt())
val scaleTop = max(1, (heightTop * drawScale).toInt())
val scaleBottom = max(1, (heightBottom * drawScale).toInt())
val scaleWidth = max(1, drawWidth - scaleLeft - scaleRight)
val scaleHeight = max(1, drawHeight - scaleTop - scaleBottom)
// Center
drawImage(
image, offsetCenter, sizeCenter,
dstOffset = IntOffset(scaleLeft, scaleTop),
dstSize = IntSize(scaleWidth, scaleHeight),
alpha = alpha, colorFilter = colorFilter, filterQuality = filterQuality
)
// Top
drawImage(
image, offsetTop, sizeTop,
dstOffset = IntOffset(scaleLeft, 0),
dstSize = IntSize(scaleWidth, scaleTop),
alpha = alpha, colorFilter = colorFilter, filterQuality = filterQuality
)
// Left
drawImage(
image, offsetLeft, sizeLeft,
dstOffset = IntOffset(0, scaleTop),
dstSize = IntSize(scaleLeft, scaleHeight),
alpha = alpha, colorFilter = colorFilter, filterQuality = filterQuality
)
// Right
drawImage(
image, offsetRight, sizeRight,
dstOffset = IntOffset(drawWidth - scaleRight, scaleTop),
dstSize = IntSize(scaleRight, scaleHeight),
alpha = alpha, colorFilter = colorFilter, filterQuality = filterQuality
)
// Bottom
drawImage(
image, offsetBottom, sizeBottom,
dstOffset = IntOffset(scaleLeft, drawHeight - scaleBottom),
dstSize = IntSize(scaleWidth, scaleBottom),
alpha = alpha, colorFilter = colorFilter, filterQuality = filterQuality
)
// TopLeft
drawImage(
image, offsetTopLeft, sizeTopLeft,
dstOffset = IntOffset.Zero,
dstSize = IntSize(scaleLeft, scaleTop),
alpha = alpha, colorFilter = colorFilter, filterQuality = filterQuality
)
// TopRight
drawImage(
image, offsetTopRight, sizeTopRight,
dstOffset = IntOffset(drawWidth - scaleRight, 0),
dstSize = IntSize(scaleRight, scaleTop),
alpha = alpha, colorFilter = colorFilter, filterQuality = filterQuality
)
// BottomLeft
drawImage(
image, offsetBottomLeft, sizeBottomLeft,
dstOffset = IntOffset(0, drawHeight - scaleBottom),
dstSize = IntSize(scaleLeft, scaleBottom),
alpha = alpha, colorFilter = colorFilter, filterQuality = filterQuality
)
// BottomRight
drawImage(
image, offsetBottomRight, sizeBottomRight,
dstOffset = IntOffset(drawWidth - scaleRight, drawHeight - scaleBottom),
dstSize = IntSize(scaleRight, scaleBottom),
alpha = alpha, colorFilter = colorFilter, filterQuality = filterQuality
)
}
override val intrinsicSize: Size get() = size.toSize()
override fun applyAlpha(alpha: Float): Boolean {
this.alpha = alpha
return true
}
override fun applyColorFilter(colorFilter: ColorFilter?): Boolean {
this.colorFilter = colorFilter
return true
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is NinePatchPainter) return false
if (image != other.image) return false
if (centerSlice != other.centerSlice) return false
if (scale != other.scale) return false
if (filterQuality != other.filterQuality) return false
return true
}
override fun hashCode(): Int {
var result = image.hashCode()
result = 31 * result + centerSlice.hashCode()
result = 31 * result + size.hashCode()
result = 31 * result + scale.hashCode()
result = 31 * result + filterQuality.hashCode()
return result
}
override fun toString(): String {
return "NinePathPainter(image=$image, centerSlice=$centerSlice, scale=$scale)"
}
}
@Immutable
class CenterRect(left: Int, top: Int, right: Int, bottom: Int) {
@Stable
val left: Int = max(0, left)
@Stable
val top: Int = max(0, top)
@Stable
val right: Int = max(0, right)
@Stable
val bottom: Int = max(0, bottom)
@Stable
val width: Int get() = max(1, right - left)
@Stable
val height: Int get() = max(1, bottom - top)
override fun toString(): String {
return "CenterRect{$left, $top, $right, $bottom}"
}
}
@Composable
fun rememberNinePatchPainter(
action: ImageAction,
center: CenterRect,
scale: Float = 1f,
editor: Boolean,
filterQuality: FilterQuality = DrawScope.DefaultFilterQuality,
placeholderPainter: (@Composable () -> Painter)? = null,
errorPainter: (@Composable () -> Painter)? = null,
): Painter {
return when (action) {
is ImageEvent -> placeholderPainter?.invoke() ?: EmptyPainter
is ImageResult -> {
return when (action) {
is ImageResult.Painter -> remember(action) { action.painter }
is ImageResult.Bitmap ->
if (editor) remember(action, center, scale, filterQuality) {
NinePatchPainter(
action.bitmap.asImageBitmap(),
centerSlice = center,
scale = scale,
filterQuality = filterQuality
)
} else remember(action, filterQuality) {
NinePatchPainter(
action.bitmap.asImageBitmap(),
centerSlice = center,
scale = scale,
filterQuality = filterQuality
)
}
is ImageResult.Image -> remember(action) { action.image.toPainter() }
is ImageResult.Error, is ImageResult.Source -> errorPainter?.invoke() ?: EmptyPainter
}.also { painter ->
when (painter) {
is AnimationPainter -> LaunchedEffect(painter) {
while (painter.isPlay()) {
withFrameMillis { frameTimeMillis -> painter.update(frameTimeMillis) }
}
}
}
}
}
}
}
if change the default small image to raw image , as following "val imageUrl: String get() = urls?.raw ?: url " in Image.kt in the sample , the memory will be drained soon on iOS device.
It works fine normally but when I enabled Image caching as mentioned in the documentation, ui starts to lag a lot while scroll through the lazylists.
I'm trying to write a Paparazzi ui test, but no image is displayed :
my test :
class TempTest {
private fun generateImageLoader() = ImageLoader {
interceptor {
useDefaultInterceptors = false
addInterceptor { ImageResult.OfPainter(ColorPainter(Color.Green)) }
}
}
@get:Rule
val paparazzi = Paparazzi(
deviceConfig = DeviceConfig.PIXEL_6,
theme = "android:Theme.Material.NoActionBar",
)
@Test
fun launchComposable() {
paparazzi.snapshot {
CompositionLocalProvider(LocalImageLoader provides remember { generateImageLoader() }) {
AutoSizeImage("", null, modifier = Modifier.size(200.dp))
}
}
}
}
PS : I managed to write this kind of test with Coil
version: api("io.github.qdsfdhvh:image-loader:1.2.10")
kotlin version : 1.8.0
Compose : 1.3.0
Ktor 请求日志:
log----start-------
I/System.out: REQUEST: https://www.wanandroid.com/blogimgs/42da12d8-de56-4439-b40c-eab66c227a4b.png
I/System.out: METHOD: HttpMethod(value=GET)
I/System.out: COMMON HEADERS
I/System.out: -> Accept: application/json
I/System.out: -> Accept-Charset: UTF-8
I/System.out: CONTENT HEADERS
I/System.out: -> Content-Length: 0
I/System.out: RESPONSE: 200 OK
I/System.out: METHOD: HttpMethod(value=GET)
I/System.out: FROM: https://www.wanandroid.com/blogimgs/42da12d8-de56-4439-b40c-eab66c227a4b.png
I/System.out: COMMON HEADERS
I/System.out: -> accept-ranges: bytes
I/System.out: -> cache-control: private
I/System.out: -> content-length: 80542
I/System.out: -> content-type: image/png
I/System.out: -> date: Sun, 26 Mar 2023 06:41:36 GMT
I/System.out: -> etag: W/"80542-1647681580000"
I/System.out: -> expires: Thu, 01 Jan 1970 08:00:00 CST
I/System.out: -> last-modified: Sat, 19 Mar 2022 09:19:40 GMT
I/System.out: -> server: Apache-Coyote/1.1
I/System.out: status:Failure(error=java.lang.RuntimeException: Unable to create a decoder that supports: Source(request=com.seiko.imageloader.model.ImageRequest@b719312, source=buffer(source(io.ktor.utils.io.jvm.javaio.InputAdapter@c174ae3)), dataSource=Engine, extra={KEY_MIME_TYPE=image/png}))
log-----end-------
Failure(error=java.lang.RuntimeException: Unable to create a decoder that supports: Source(request=com.seiko.imageloader.model.ImageRequest@b719312, source=buffer(source(io.ktor.utils.io.jvm.javaio.InputAdapter@c174ae3)), dataSource=Engine, extra={KEY_MIME_TYPE=image/png}))
我把painter 的请求状态 打印出来了,打印报错 就是上面提示的错误。
要解决这个错误 需要从哪里入手啊,麻烦大佬给提供个思路
Please support the latest version of Ktor. 2.1.2
I was using the ImageConfig.HARDWARE configuation for thumbnails since it seemed to help perfomance, but I got this exception when I was testing on a older emulator(API 24).
I did some research and it seems like Bitmap.Config.HARDWARE
wasn't added until API 26. I changed what I use for ImageConfig to a variable that changes based on the API level, but I think this should be handled at the library level or at least give a warning.
2022-11-08 00:12:12.982 11097-11097/ca.gosyer.jui.android.debug W/ImageLoaderImageKt: Caused by: java.lang.NoSuchFieldError: No field HARDWARE of type Landroid/graphics/Bitmap$Config; in class Landroid/graphics/Bitmap$Config; or its superclasses (declaration of 'android.graphics.Bitmap$Config' appears in /system/framework/framework.jar)
at com.seiko.imageloader.util.BitmapKt.toBitmapConfig(Bitmap.kt:19)
at com.seiko.imageloader.component.decoder.BitmapFactoryDecoder.configureConfig(BitmapFactoryDecoder.kt:86)
at com.seiko.imageloader.component.decoder.BitmapFactoryDecoder.decode(BitmapFactoryDecoder.kt:59)
at com.seiko.imageloader.component.decoder.BitmapFactoryDecoder.access$decode(BitmapFactoryDecoder.kt:26)
at com.seiko.imageloader.component.decoder.BitmapFactoryDecoder$decode$2$1.invoke(BitmapFactoryDecoder.kt:34)
at com.seiko.imageloader.component.decoder.BitmapFactoryDecoder$decode$2$1.invoke(BitmapFactoryDecoder.kt:34)
at kotlinx.coroutines.InterruptibleKt.runInterruptibleInExpectedContext(Interruptible.kt:51)
at kotlinx.coroutines.InterruptibleKt.access$runInterruptibleInExpectedContext(Interruptible.kt:1)
at kotlinx.coroutines.InterruptibleKt$runInterruptible$2.invokeSuspend(Interruptible.kt:43)
at kotlinx.coroutines.InterruptibleKt$runInterruptible$2.invoke(Interruptible.kt)
at kotlinx.coroutines.InterruptibleKt$runInterruptible$2.invoke(Interruptible.kt)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:161)
at kotlinx.coroutines.BuildersKt.withContext(Unknown Source)
at kotlinx.coroutines.InterruptibleKt.runInterruptible(Interruptible.kt:42)
at kotlinx.coroutines.InterruptibleKt.runInterruptible$default(Interruptible.kt:39)
at com.seiko.imageloader.component.decoder.BitmapFactoryDecoder.decode(BitmapFactoryDecoder.kt:34)
at com.seiko.imageloader.intercept.DecodeInterceptor.decode(DecodeInterceptor.kt:45)
at com.seiko.imageloader.intercept.DecodeInterceptor.intercept(DecodeInterceptor.kt:19)
at com.seiko.imageloader.intercept.RealInterceptorChain.proceed(RealInterceptorChain.kt:37)
at com.seiko.imageloader.intercept.MemoryCacheInterceptor.intercept(MemoryCacheInterceptor.kt:31)
at com.seiko.imageloader.intercept.RealInterceptorChain.proceed(RealInterceptorChain.kt:37)
at com.seiko.imageloader.intercept.MappedInterceptor.intercept(MappedInterceptor.kt:12)
at com.seiko.imageloader.intercept.RealInterceptorChain.proceed(RealInterceptorChain.kt:37)
at com.seiko.imageloader.RealImageLoader.executeMain(ImageLoader.kt:64)
at com.seiko.imageloader.RealImageLoader.access$executeMain(ImageLoader.kt:29)
at com.seiko.imageloader.RealImageLoader$execute$2.invokeSuspend(ImageLoader.kt:50)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Class 'com.seiko.imageloader.ImageLoader' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler
I'm using:
Kotlin 1.7.0
Compose JB 1.2.0-alpha01-dev753
How to Add basic auth to load image ?
Hello, I've noticed that the minimum SDK version has changed in the latest release, but there was no mention of this in the release notes. Is this change intentional?
Affected Version: 1.6.5
Expected Behavior: Min SDK Version should be consistent with previous versions or mentioned in release notes if changed.
Actual Behavior: Min SDK Version changed without any notice.
Thank you for your time and effort on this project.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.