Skip to content

AkshayAshokCode/MediaKit-android

MediaKit Android

A modular Android media SDK built with Kotlin. Pick images from the gallery or camera, then crop them — all with a single fluent API.

Maven Central Maven Central License: MIT API


Modules

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

Installation

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")
}

imagecropper depends on imagepicker transitively — adding just imagecropper is enough if you want both.


Quick Start

Pick from gallery

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() })
            }
        }
    }
}

Pick and crop

val picker = ImagePicker.with(this, this)
    .source(MediaSource.Gallery)
    .crop(MediaKitCropProvider())   // requires imagecropper artifact
    .onResult { result ->
        // result.uri is the cropped image URI
    }

Pick and crop with options

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 -> }

Camera capture

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
        }
    }

Embed CropperView standalone

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()

Bring your own crop library

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 -> }

API Reference

Media Sources

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

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

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:4

CropShape

CropShape.Rectangle   // standard rectangular crop (default)
CropShape.Circle      // circular mask — output bitmap has transparent corners

OutputFormat

OutputFormat.JPEG(quality: Int = 90)   // default
OutputFormat.PNG                        // lossless, transparent background for circle crop
OutputFormat.WebP(quality: Int = 90)

Result Types

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
}

Exception Types

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?)
}

Requirements

  • minSdk 24 (Android 7.0+)
  • Kotlin

Project Structure

MediaKit-android/
├── imagepicker/       (library — ImagePicker, ImageCropProvider interface)
├── imagecropper/      (library — CropperView, CropperActivity, MediaKitCropProvider)
├── sample-app/        (demo Compose app)
└── docs/

Design Goals

  • Modularimagepicker works without imagecropper on the classpath
  • Lightweight — no third-party image loading dependencies
  • Lifecycle-safe — all registerForActivityResult calls happen before onStart
  • Kotlin-first — sealed results, fluent builder, no Java boilerplate
  • Extensible — implement ImageCropProvider to plug in any crop library

Contributing

See CONTRIBUTING.md.

License

MIT — see LICENSE.

About

A modular Android media SDK built with Kotlin. Pick images from the gallery or camera, then crop them — all with a single fluent API.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages