peekaboo

repository·main·Indexed 18 days ago

https://github.com/onseok/peekaboo

A Kotlin Multiplatform library for Compose Multiplatform providing image picking and camera functionality for iOS and Android. It includes peekaboo-ui for custom camera views and gallery picker states, and peekaboo-image-picker for single or multiple image selection with support for resizing, compression, and visual filters (Grayscale, Sepia, Invert).

Tokens
2.8K
Snippets
12
Records
12
Agent score
14%

What's inside peekaboo

  1. Configure iOS Camera permissions

    main

    To access the camera on iOS devices, you must add the Privacy - Camera Usage Description key to your Info.plist file. This provides the user with a description of why the app requires camera access.

    <key>Privacy - Camera Usage Description</key>
    <string>This app uses camera for capturing photos.</string>
  2. Install peekaboo for Compose Multiplatform

    main

    Add the desired dependency to your commonMain configuration. The minimum supported Android SDK is 24 (Android 7.0).

    Choose between:

    • peekaboo-ui: Provides UI elements like a custom camera view for iOS and Android.
    • peekaboo-image-picker: Provides functionality to select single or multiple images on iOS and Android.
    commonMain {
        dependencies {
            // For UI components (Camera)
            implementation("io.github.onseok:peekaboo-ui:$latest_version")
    
            // For image selection
            implementation("io.github.onseok:peekaboo-image-picker:$latest_version")
        }
    }
  3. Use Multiple Image Selection with Resizing

    main

    To pick multiple images with a limit and apply resizing, use SelectionMode.Multiple(maxSelection = n). The onResult callback returns a list of ByteArrays representing all selected and resized images.

    val multipleImagePicker = rememberImagePickerLauncher(
        selectionMode = SelectionMode.Multiple(maxSelection = 5),
        scope = rememberCoroutineScope(),
        resizeOptions = resizeOptions,
        onResult = {
            byteArrays ->
            byteArrays.forEach {
                // Process the resized images' ByteArrays
                println(it)
            }
        }
    )
  4. Use Single Image Selection with Resizing

    main

    To pick a single image and apply resizing, pass SelectionMode.Single and your ResizeOptions to rememberImagePickerLauncher. The onResult callback provides a list of ByteArrays; for single selection, you typically use .firstOrNull().

    val singleImagePicker = rememberImagePickerLauncher(
        selectionMode = SelectionMode.Single,
        scope = rememberCoroutineScope(),
        resizeOptions = resizeOptions,
        onResult = {
            byteArrays ->
            byteArrays.firstOrNull()?.let {
                // Process the resized image's ByteArray
                println(it)
            }
        }
    )
  5. Configure image resizing with ResizeOptions

    main

    You can optimize image selection by providing resizeOptions to rememberImagePickerLauncher. This allows you to specify target dimensions, a file size threshold for when resizing should trigger, and compression quality.

    Key behaviors:

    • Aspect Ratio: The original aspect ratio is preserved; final dimensions may vary slightly to maintain proportions.
    • Default Dimensions: 800 x 800 pixels.
    • Default Threshold: 1MB (images larger than this will be resized).
    • Compression Quality: A value from 0.0 to 1.0.
    val resizeOptions = ResizeOptions(
        width = 1200, // Custom width
        height = 1200, // Custom height
        resizeThresholdBytes = 2 * 1024 * 1024L, // Custom threshold for 2MB
        compressionQuality = 0.5 // Adjust compression quality (0.0 to 1.0)
    )
  6. Select single or multiple images with rememberImagePickerLauncher

    main

    Use rememberImagePickerLauncher to implement image selection. This requires a CoroutineScope and a SelectionMode.

    Selection Modes:

    • SelectionMode.Single: For picking one image.
    • SelectionMode.Multiple(maxSelection: Int): For picking multiple images. If maxSelection is not provided, it defaults to the system's maximum capacity.

    onResult Callback: Returns a list of ByteArray representing the selected images.

    val scope = rememberCoroutineScope()
    
    // Single Image Selection
    val singleImagePicker = rememberImagePickerLauncher(
        selectionMode = SelectionMode.Single,
        scope = scope,
        onResult = { byteArrays ->
            byteArrays.firstOrNull()?.let { /* Process image */ }
        }
    )
    
    // Multiple Image Selection
    val multipleImagePicker = rememberImagePickerLauncher(
        selectionMode = SelectionMode.Multiple(maxSelection = 5),
        scope = scope,
        onResult = { byteArrays ->
            byteArrays.forEach { /* Process image */ }
        }
    )
    
    // To trigger the picker:
    // singleImagePicker.launch()
  7. Manage camera state with rememberPeekabooCameraState

    main

    Use rememberPeekabooCameraState to initialize and control the camera.

    Parameters:

    • initialCameraMode: The starting camera (front or back). Default is CameraMode.Back. Note: To switch modes during runtime, use PeekabooCameraState.toggleCamera instead of changing this parameter.
    • onCapture: A lambda called when a photo is captured, providing the photo as a ByteArray? (null if capture fails).

    State Properties:

    • isCameraReady: Boolean indicating if the camera is available to be shown.
    • isCapturing: Boolean indicating if a capture is currently in progress.
    • cameraMode: The current CameraMode (front or back).
    val state = rememberPeekabooCameraState(
        initialCameraMode = CameraMode.Back,
        onCapture = { byteArray -> 
            // Handle the captured image
        }
    )
  8. Apply image filters with FilterOptions

    main

    You can apply visual filters to selected images on both Android and iOS by setting the filterOptions parameter in rememberImagePickerLauncher.

    Available filters:

    • FilterOptions.Default: No filter applied (default).
    • FilterOptions.GrayScale: Converts image to grayscale.
    • FilterOptions.Sepia: Applies a sepia tone.
    • FilterOptions.Invert: Inverts the colors.
    val imagePicker = rememberImagePickerLauncher(
        selectionMode = SelectionMode.Single,
        scope = rememberCoroutineScope(),
        filterOptions = FilterOptions.GrayScale,
        onResult = {
            byteArrays ->
            // Process the filtered images' ByteArrays
        }
    )
  9. Use PeekabooCamera for custom camera UI

    main

    The PeekabooCamera composable provides a customizable camera interface. You can use it as a simple view or wrap it in a Box to draw custom overlays on top of the camera preview.

    Key parameters:

    • state: A PeekabooCameraState instance to control the camera.
    • permissionDeniedContent: An optional composable lambda that displays content (like informative text or a button to settings) when camera permissions are denied.
    @Composable
    fun CustomCameraView() {
        val state = rememberPeekabooCameraState(onCapture = { /* Handle captured images */ })
        Box(modifier = Modifier.fillMaxSize()) {
            PeekabooCamera(
                state = state,
                modifier = Modifier.fillMaxSize(),
                permissionDeniedContent = {
                    // Custom UI for permission denied scenario
                },
            )
            // Draw your custom UI overlay here using the state
            YourCameraOverlay(
                state = state,
                modifier = Modifier.fillMaxSize(),
            )
        }
    }
  10. Initialize GalleryPickerState with rememberGalleryPickerState

    main

    Use rememberGalleryPickerState to create and remember the state for a gallery picker UI. This state holds configuration values for the grid layout, such as padding, spacing, corner radius, and column count. The state is wrapped in rememberSaveable, meaning it will survive configuration changes (like screen rotations) using the internal GalleryPickerState.Saver.

    val galleryState = rememberGalleryPickerState(
        contentPadding = 8,
        itemSpacing = 4,
        cornerSize = 12,
        columns = 4
    )
  11. Configure GalleryPickerState layout options

    main

    When calling rememberGalleryPickerState, you can customize the following layout properties:

    ParameterTypeDefaultDescription
    contentPaddingInt4Horizontal padding applied to the entire gallery grid content.
    itemSpacingInt4Spacing between individual items in the grid (both horizontal and vertical).
    cornerSizeInt0The corner radius for the card items in the gallery.
    columnsInt3The number of columns in the gallery grid.
    // Example of a highly customized grid
    val galleryState = rememberGalleryPickerState(
        contentPadding = 16,
        itemSpacing = 8,
        cornerSize = 16,
        columns = 5
    )
  12. Convert ByteArray to ImageBitmap using toImageBitmap()

    main

    Use the toImageBitmap() extension function to convert a raw ByteArray (received from the image picker) into a Compose ImageBitmap for easy display in your UI.

    val imageBitmap = byteArray.toImageBitmap()