A modular Android media SDK built with Kotlin. Pick images from the gallery or camera, then crop them — all with a single fluent API.
| Artifact | Description |
|---|---|
io.github.akshayashokcode:imagepicker |
Gallery & camera image picking with lifecycle-safe activity result handling |
io.github.akshayashokcode:imagecropper |
Custom crop view with aspect ratio lock, shape mask, rotate/flip, and configurable output |
Add to your app's build.gradle.kts:
dependencies {
// Image picking (gallery + camera)
implementation("io.github.akshayashokcode:imagepicker:0.2.0")
// Optional — only needed if you want the built-in crop UI
implementation("io.github.akshayashokcode:imagecropper:0.2.0")
}
imagecropperdepends onimagepickertransitively — adding justimagecropperis enough if you want both.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Must be constructed before setContent — registerForActivityResult
// must be called before the activity reaches STARTED.
val picker = ImagePicker.with(this, this)
.source(MediaSource.Gallery)
.onResult { result ->
when (result) {
is ImagePickerResult.Success -> { /* use result.uri */ }
is ImagePickerResult.Cancelled -> { /* user cancelled */ }
is ImagePickerResult.Error -> { /* show result.message */ }
else -> Unit
}
}
.onError { error ->
// ImagePickerException subtypes: PermissionDenied, AppNotFound, etc.
}
setContent {
MyTheme {
MyScreen(onPickImage = { picker.launch() })
}
}
}
}val picker = ImagePicker.with(this, this)
.source(MediaSource.Gallery)
.crop(MediaKitCropProvider()) // requires imagecropper artifact
.onResult { result ->
// result.uri is the cropped image URI
}All CropperOptions parameters are optional — only set what you need:
val picker = ImagePicker.with(this, this)
.source(MediaSource.Gallery)
.crop(
MediaKitCropProvider(
CropperOptions(
aspectRatios = listOf(AspectRatio.Free, AspectRatio.Square, AspectRatio.SixteenNine),
showRotateButtons = true,
showFlipButtons = true,
cropShape = CropShape.Rectangle, // or CropShape.Circle
outputFormat = OutputFormat.JPEG(quality = 90),
maxOutputWidth = 2048,
maxOutputHeight = 2048
)
)
)
.onResult { result -> }val picker = ImagePicker.with(this, this)
.source(MediaSource.Camera) // CAMERA permission requested automatically
.onResult { result ->
when (result) {
is ImagePickerResult.SuccessWithBitmap -> {
// result.uri — content URI
// result.bitmap — orientation-corrected bitmap
}
else -> Unit
}
}Use the crop UI directly in your own layout without the picker flow:
<com.akshayashokcode.imagecropper.CropperView
android:id="@+id/cropperView"
android:layout_width="match_parent"
android:layout_height="match_parent" />cropperView.setImageBitmap(bitmap)
val cropped: Bitmap? = cropperView.getCroppedImage()Implement ImageCropProvider to plug in uCrop, Android Image Cropper, or any other crop library:
class MyCropProvider : ImageCropProvider {
override fun createLauncher(
context: Context,
caller: ActivityResultCaller,
callback: (ImagePickerResult) -> Unit
): CropLauncher {
// register your activity result launcher here
// return CropLauncher { uri -> /* launch your crop UI */ }
}
}
val picker = ImagePicker.with(this, this)
.source(MediaSource.Gallery)
.crop(MyCropProvider())
.onResult { result -> }MediaSource.Gallery // system photo picker / file picker
MediaSource.Camera // camera capture (CAMERA permission requested automatically)
MediaSource.Both // falls back to gallery (chooser UI planned)CropperOptions(
aspectRatios: List<AspectRatio> = listOf(AspectRatio.Free),
lockAspectRatio: Boolean = false,
cropShape: CropShape = CropShape.Rectangle,
showRotateButtons: Boolean = false, // 90° CW / CCW buttons
showFlipButtons: Boolean = false, // horizontal / vertical flip buttons
outputFormat: OutputFormat = OutputFormat.JPEG(),
maxOutputWidth: Int = 0, // 0 = no limit
maxOutputHeight: Int = 0,
minOutputWidth: Int = 100,
minOutputHeight: Int = 100
)AspectRatio.Free // unconstrained (default)
AspectRatio.Square // 1:1
AspectRatio.Ratio(width, height) // e.g. Ratio(16, 9)
// Convenience presets
AspectRatio.FourThree // 4:3
AspectRatio.SixteenNine // 16:9
AspectRatio.ThreeTwo // 3:2
AspectRatio.FiveFour // 5:4CropShape.Rectangle // standard rectangular crop (default)
CropShape.Circle // circular mask — output bitmap has transparent cornersOutputFormat.JPEG(quality: Int = 90) // default
OutputFormat.PNG // lossless, transparent background for circle crop
OutputFormat.WebP(quality: Int = 90)sealed class ImagePickerResult {
data class Success(val uri: Uri) // gallery pick or crop output
data class SuccessWithBitmap(val uri: Uri, val bitmap: Bitmap) // camera capture (orientation-corrected)
data object Cancelled // user dismissed
data class Error(val message: String) // non-fatal error
}sealed class ImagePickerException {
object PermissionDenied // CAMERA permission not granted
object AppNotFound // no camera or gallery app available
object FileCreationFailed // temp file for camera capture could not be created
object InvalidUri // returned URI was null or unreadable
object DecodingFailed // bitmap decode / EXIF rotation failed
object FileDeletionFailed // cleanup of temp file failed
object IntentFailed // intent could not be launched
class Unknown(message: String?, cause: Throwable?)
}- minSdk 24 (Android 7.0+)
- Kotlin
MediaKit-android/
├── imagepicker/ (library — ImagePicker, ImageCropProvider interface)
├── imagecropper/ (library — CropperView, CropperActivity, MediaKitCropProvider)
├── sample-app/ (demo Compose app)
└── docs/
- Modular —
imagepickerworks withoutimagecropperon the classpath - Lightweight — no third-party image loading dependencies
- Lifecycle-safe — all
registerForActivityResultcalls happen beforeonStart - Kotlin-first — sealed results, fluent builder, no Java boilerplate
- Extensible — implement
ImageCropProviderto plug in any crop library
See CONTRIBUTING.md.
MIT — see LICENSE.