A powerful, efficient, and modern Android image loading library built with Jetpack Compose. Features multi-level caching, animated image support (GIF, WebP), image transformations, and more.
- Async Image Loading - Load images from URLs with automatic caching
- Multi-Level Caching - Memory cache (LRU) + Disk cache for optimal performance
- Animated Images - Full support for GIF and WebP animations
- Image Transformations - Rounded corners, circles with borders, blur effects
- Compose-First - Built specifically for Jetpack Compose
- Smooth Animations - Fade, Scale, and Slide-up animations
- Prefetching - Preload images for better UX
- Memory Efficient - Bitmap pooling and smart memory management
- Error Handling - Built-in loading, success, and error states
![]() |
![]() |
![]() |
Add the JitPack repository to your project's settings.gradle.kts:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") } // Add this line
}
}Add the dependency to your app's build.gradle.kts:
dependencies {
implementation("com.github.jasi381:Custom-Image-Loader:1.0.0")
}import com.jasmeet.imageloader.ui.theme.AsyncImage
@Composable
fun MyScreen() {
AsyncImage(
url = "https://example.com/image.jpg",
contentDescription = "My image",
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
)
}AsyncImage(
url = "https://example.com/image.jpg",
contentDescription = "Rounded image",
modifier = Modifier
.fillMaxWidth()
.height(200.dp),
transformation = ImageTransformation.RoundedCorners(cornerRadius = 32f)
)AsyncImage(
url = "https://example.com/avatar.jpg",
contentDescription = "Profile picture",
modifier = Modifier.size(120.dp),
transformation = ImageTransformation.Circle(
borderWidth = 4f,
borderColor = 0xFF6200EE.toInt()
)
)AsyncImage(
url = "https://example.com/background.jpg",
contentDescription = "Blurred background",
modifier = Modifier.fillMaxSize(),
transformation = ImageTransformation.Blur(radius = 25f)
)// Fade animation
AsyncImage(
url = "https://example.com/image.jpg",
contentDescription = "Fading image",
modifier = Modifier.size(200.dp),
animation = ImageAnimation.FADE
)
// Scale animation
AsyncImage(
url = "https://example.com/image.jpg",
contentDescription = "Scaling image",
modifier = Modifier.size(200.dp),
animation = ImageAnimation.SCALE
)
// Slide up animation
AsyncImage(
url = "https://example.com/image.jpg",
contentDescription = "Sliding image",
modifier = Modifier.size(200.dp),
animation = ImageAnimation.SLIDE_UP
)AsyncImage(
url = "https://media.giphy.com/media/3o7abKhOpu0NwenH3O/giphy.gif",
contentDescription = "Animated GIF",
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
)AsyncImage(
url = "https://example.com/image.jpg",
contentDescription = "Image with placeholders",
modifier = Modifier.size(200.dp),
placeholderResId = R.drawable.placeholder,
errorResId = R.drawable.error_image
)@Composable
fun MyScreen() {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val imageLoader = remember { ImageLoader(context) }
// Prefetch images
LaunchedEffect(Unit) {
imageLoader.prefetch("https://example.com/image1.jpg", scope)
imageLoader.prefetch("https://example.com/image2.jpg", scope)
}
// Use AsyncImage as normal
AsyncImage(
url = "https://example.com/image1.jpg",
contentDescription = "Prefetched image",
modifier = Modifier.fillMaxWidth()
)
}import com.jasmeet.imageloader.utils.ImageState
@Composable
fun MyScreen() {
var imageState by remember { mutableStateOf<ImageState>(ImageState.Loading) }
when (imageState) {
is ImageState.Loading -> {
CircularProgressIndicator()
}
is ImageState.Success -> {
val bitmap = (imageState as ImageState.Success).bitmap
Image(
bitmap = bitmap.asImageBitmap(),
contentDescription = "Loaded image"
)
}
is ImageState.Error -> {
Text("Error loading image: ${(imageState as ImageState.Error).message}")
}
}
}The library uses a two-tier caching system:
- Memory Cache - LRU-based in-memory cache (1/8 of max heap)
- Disk Cache - Persistent storage for downloaded images
The caching is automatic and requires no configuration. Images are first checked in memory, then disk, and finally downloaded if not found.
Transformations are applied after the image is loaded but before it's displayed. Available transformations:
ImageTransformation.RoundedCorners(cornerRadius: Float)- Applies rounded cornersImageTransformation.Circle(borderWidth: Float, borderColor: Int)- Makes the image circular with optional borderImageTransformation.Blur(radius: Float)- Applies Gaussian blur (requires RenderScript)
- Static Images: JPEG, PNG, WebP
- Animated Images: GIF, WebP (animated, API 28+)
The library automatically detects the image format and uses the appropriate decoder.
- Lazy Loading - Images are loaded only when needed
- Bitmap Pooling - Reuses bitmap memory to reduce GC pressure
- Background Threading - All network and disk I/O happens off the main thread
- Efficient Caching - Minimizes redundant downloads and memory usage
- Minimum SDK: 24 (Android 7.0)
- Target SDK: 36
- Jetpack Compose: BOM 2024.09.00+
- Kotlin: 2.0.21+
Copyright 2025 Jasmeet Singh
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Contributions are welcome! Please feel free to submit a Pull Request.
Jasmeet Singh - @jasi381
- Async image loading with Jetpack Compose
- Multi-level caching (Memory + Disk)
- GIF and WebP animation support
- Image transformations (Rounded corners, Circle, Blur)
- Loading animations (Fade, Scale, Slide-up)
- Prefetching capability
- Error handling and state management
If you find this library useful, please give it a star ⭐ on GitHub!
For issues and feature requests, please use the GitHub Issues page.


