A modern and easy-to-use Android library for picking images and videos from the gallery or capturing
them with the camera. It offers a unified API for traditional Views (Activities/Fragments with XML)
and Jetpack Compose.
Note: The example project does not include examples for all methods.
This library is designed to simplify media selection in your Android app with a robust set of features:
- πΌοΈ Single Image Picker: Select a single image from the gallery.
- π¨ Multiple Image Picker: Choose multiple images (up to 9).
- πΈ Camera Capture: Capture a new photo, with streamlined permission handling that can direct users to app settings or can use the onPermanentCameraPermissionDenied() callback to implement your own custom logic).
- πΉ Video Picker: Select a single video from the gallery.
- π Base64 Conversion: Automatically convert selected images to a Base64 string.
- βοΈ Image Scaling: Easily resize images to your desired dimensions.
- π Jetpack Compose Support: First-class support for Jetpack Compose, with dedicated composables.
- Unified API: Supports both traditional Views (Activities/Fragments) and modern Jetpack Compose UIs.
- Time-Saving: Provides a simple, out-of-the-box solution to a common Android task, saving you significant development time.
- Boilerplate Reduction: Handles
ActivityResultLauncher, permissions, and file processing, letting you focus on your app's logic. - Advanced Functionality: Includes powerful features like Base64 encoding and image scaling without needing extra dependencies.
| Views (XML) | Jetpack Compose |
|---|---|
![]() |
![]() |
- JDK Version:
17 - Target SDK:
37 - Minimum SDK:
24 - Kotlin Version:
2.4.10 - Gradle Version:
9.3.1 - Build Tool Version:
37.0.0
THE BETA RELEASES MAY CONTAIN MAJOR OR MINOR CHANGES.
Important
Check my article with the implementation
π ImagePickerAndroid - My Android Image Picker Library π§βπ» - Medium π
implementation 'com.github.NicosNicolaou16:ImagePickerAndroid:2.6.0'allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}implementation("com.github.NicosNicolaou16:ImagePickerAndroid:2.6.0")dependencyResolutionManagement {
//...
repositories {
//...
maven { url = uri("https://jitpack.io") }
}
}[versions]
# other versions here...
imagePickerAndroid = "2.6.0"
[libraries]
# other libraries here...
image-picker-android = { group = "com.github.NicosNicolaou16", name = "ImagePickerAndroid", version.ref = "imagePickerAndroid" }implementation(libs.image.picker.android)dependencyResolutionManagement {
//...
repositories {
//...
maven { url = uri("https://jitpack.io") }
}
}class MainActivity : AppCompatActivity(), ImagePickerInterface {
//...
private var imagePicker: ImagePicker? = null
//...
fun initImagePicker() {
//Builder
//Note: fragmentActivity or fragment are mandatory one of them
imagePicker = ImagePicker(
fragmentActivity = this, //activity instance - private
fragment = this, // fragment instance - private
coroutineScope = lifecycleScope, // mandatory - coroutine scope from activity or fragment - private
scaleBitmapModelForSingleImage = ScaleBitmapModel(
height = 100,
width = 100
), // optional, change the scale for image, by default is null
scaleBitmapModelForMultipleImages = ScaleBitmapModel(
height = 100,
width = 100
), // optional, change the scale for image, by default is null
scaleBitmapModelForCameraImage = ScaleBitmapModel(
height = 100,
width = 100
), // optional, change the scale for image, by default is null
enabledBase64ValueForSingleImage = true, // optional, by default is false - private
enabledBase64ValueForMultipleImages = true, // optional, by default is false - private
enabledBase64ValueForCameraImage = true, // optional, by default is false - private
imagePickerInterface = this, // call back interface
shouldRedirectedToSettingsIfPermissionDenied = false // optional, by default is true - private, if it set false, need to call the callback onPermanentCameraPermissionDenied()
)
//...other image picker initialization method(s)
}
//...
}imagePicker?.initPickSingleImageFromGalleryResultLauncher()
imagePicker?.initPickMultipleImagesFromGalleryResultLauncher()
imagePicker?.initTakePhotoWithCameraResultLauncher()
imagePicker?.initPickSingleVideoFromGalleryResultLauncher()imagePicker?.pickSingleImageFromGallery()
imagePicker?.pickMultipleImagesFromGallery()
imagePicker?.takeSinglePhotoWithCamera()
imagePicker?.pickSingleVideoFromGallery()class MainActivity : AppCompatActivity(), ImagePickerInterface {
//...
override fun onGallerySingleImage(bitmap: Bitmap?, uri: Uri?) {
super.onGalleryImage(bitmap, uri)
//...your code here
}
override fun onCameraImage(bitmap: Bitmap?) {
super.onCameraImage(bitmap)
//...your code here
}
override fun onMultipleGalleryImages(
bitmapList: MutableList<Bitmap>?,
uriList: MutableList<Uri>?
) {
super.onMultipleGalleryImages(bitmapList, uriList)
//...your code here
}
override fun onGallerySingleImageWithBase64Value(
bitmap: Bitmap?,
uri: Uri?,
base64AsString: String?
) {
super.onGalleryImage(bitmap, uri, base64AsString)
//...your code here
}
override fun onCameraImageWithBase64Value(bitmap: Bitmap?, base64AsString: String?) {
super.onCameraImage(bitmap, base64AsString)
//...your code here
}
override fun onMultipleGalleryImagesWithBase64Value(
bitmapList: MutableList<Bitmap>?,
uriList: MutableList<Uri>?,
base64AsStringList: MutableList<String>?
) {
super.onMultipleGalleryImages(bitmapList, uriList, base64AsStringList)
//...your code here
}
override fun onGallerySingleVideo(uri: Uri?) {
super.onGallerySingleVideo(uri)
//...your code here
}
// Need to call and set the shouldRedirectedToSettingsIfPermissionDenied = false from builder to use this callback
override fun onPermanentCameraPermissionDenied() {
super.onPermanentCameraPermissionDenied()
//...your code here
}
override fun onImagePickerNotAvailable() {
super.onImagePickerNotAvailable()
//...your code here
}
}PickSingleImage(
scaleBitmapModel = ScaleBitmapModel(
height = 100,
width = 100
), listener = { bitmap, uri ->
//...your code here
})
PickSingleImageWithBase64Value(
scaleBitmapModel = null,
listener = { bitmap, uri, base64 ->
//...your code here
})
PickMultipleImages(
scaleBitmapModel = null,
listener = { bitmapList, uriList ->
//...your code here
})
PickMultipleImagesWithBase64Values(
scaleBitmapModel = null,
listener = { bitmapList, uriList, base64List ->
//...your code here
})
// The two options (enum) are `TakeImageType.TAKE_IMAGE` or `TakeImageType.TAKE_IMAGE_PREVIEW`,
// by default is `TakeImageType.TAKE_IMAGE`
TakeSingleCameraImage(
scaleBitmapModel = null,
takeImageType = TakeImageType.TAKE_IMAGE,
listener = { bitmap, uri ->
//...your code here
})
// The two options (enum) are `TakeImageType.TAKE_IMAGE` or `TakeImageType.TAKE_IMAGE_PREVIEW`,
// by default is `TakeImageType.TAKE_IMAGE`
TakeSingleCameraImageWithBase64Value(
scaleBitmapModel = null,
takeImageType = TakeImageType.TAKE_IMAGE,
listener = { bitmap, uri, base64 ->
//...your code here
})
PickSingleVideo(listener = { uri ->
//...your code here
})pickSingleImage(onImagePickerNotAvailable = {
// show custom dialog - showDialog.value = true
})
pickSingleImageWithBase64Value(onImagePickerNotAvailable = {
// show custom dialog - showDialog.value = true
})
pickMultipleImages(onImagePickerNotAvailable = {
// show custom dialog - showDialog.value = true
})
pickMultipleImagesWithBase64Values(onImagePickerNotAvailable = {
// show custom dialog - showDialog.value = true
})
/**
* onPermanentCameraPermissionDeniedCallBack is optional
* */
takeSingleCameraImage(context = context, onPermanentCameraPermissionDeniedCallBack {
// show custom dialog - showDialog.value = true
})
takeSingleCameraImageWithBase64Value(context = context, onPermanentCameraPermissionDeniedCallBack {
// show custom dialog - showDialog.value = true
})
pickSingleVideo()@Composable
fun ImagePickerDemo() {
val context = LocalContext.current
// Use Nullable states instead of allocating empty Bitmaps/Uris
var singleImageBitmap by remember { mutableStateOf<Bitmap?>(null) }
var multiImageBitmaps by remember { mutableStateOf<List<Bitmap>>(emptyList()) }
var videoUri by remember { mutableStateOf<Uri?>(null) }
// ==========================================
// 1. Initialize Library Pickers
// ==========================================
PickSingleImage(
scaleBitmapModel = null,
listener = { bitmap, _ -> singleImageBitmap = bitmap }
)
PickMultipleImagesWithBase64Values(
scaleBitmapModel = ScaleBitmapModel(height = 100, width = 100),
maxNumberOfImages = 3,
listener = { bitmapList, _, base64List ->
if (bitmapList != null) {
multiImageBitmaps = bitmapList
base64List?.forEach { base64 ->
Log.d("ImagePicker", "Base64 value retrieved: ${base64.take(20)}...")
}
}
}
)
TakeSingleCameraImage(
scaleBitmapModel = null,
takeImageType = TakeImageType.TAKE_IMAGE_PREVIEW,
listener = { bitmap, _ ->
singleImageBitmap = bitmap
} // Reusing the single image state for preview
)
PickSingleVideo(
listener = { uri -> videoUri = uri }
)
//other code
}If you enjoy this project, please give it a star! Check out all the stargazers here: Stargazers on GitHub
This library is actively maintained. Feedback, bug reports, and feature requests are welcome! Please feel free to open an issue or submit a pull request.

