|
| 1 | +# Image on Steroids |
| 2 | + |
| 3 | +Collection of Image Composables and utility functions for Jetpack compose to expand |
| 4 | +and enrich displaying, manipulating, scaling, morphing, zooming, exif and more with |
| 5 | + |
| 6 | +## ImageWithConstraints |
| 7 | +A composable that lays out and draws a given `ImageBitmap`. This will attempt to |
| 8 | +size the composable according to the `ImageBitmap`'s given width and height. |
| 9 | + |
| 10 | +`ImageScope` contains `Constraints` since `ImageWithConstraints` uses `BoxWithConstraints` |
| 11 | +also it contains information about canvas width, height and top left position relative |
| 12 | +to parent `BoxWithConstraints`. |
| 13 | + |
| 14 | +This composable enables building other `Image` based Composables that require you to know |
| 15 | +which section of Composable image is drawn to or which section of Bitmap is drawn to `Canvas` |
| 16 | + |
| 17 | +```kotlin |
| 18 | +@Composable |
| 19 | +fun ImageWithConstraints( |
| 20 | + modifier: Modifier = Modifier, |
| 21 | + imageBitmap: ImageBitmap, |
| 22 | + alignment: Alignment = Alignment.Center, |
| 23 | + contentScale: ContentScale = ContentScale.Fit, |
| 24 | + contentDescription: String? = null, |
| 25 | + alpha: Float = DefaultAlpha, |
| 26 | + colorFilter: ColorFilter? = null, |
| 27 | + filterQuality: FilterQuality = DrawScope.DefaultFilterQuality, |
| 28 | + drawImage: Boolean = true, |
| 29 | + content: @Composable ImageScope.() -> Unit = {} |
| 30 | +) { |
| 31 | + |
| 32 | +} |
| 33 | +``` |
| 34 | +returns `ImageScope` which is |
| 35 | + |
| 36 | +``` |
| 37 | +@Stable |
| 38 | +interface ImageScope { |
| 39 | + /** |
| 40 | + * The constraints given by the parent layout in pixels. |
| 41 | + * |
| 42 | + * Use [minWidth], [maxWidth], [minHeight] or [maxHeight] if you need value in [Dp]. |
| 43 | + */ |
| 44 | + val constraints: Constraints |
| 45 | +
|
| 46 | + /** |
| 47 | + * The minimum width in [Dp]. |
| 48 | + * |
| 49 | + * @see constraints for the values in pixels. |
| 50 | + */ |
| 51 | + val minWidth: Dp |
| 52 | +
|
| 53 | + /** |
| 54 | + * The maximum width in [Dp]. |
| 55 | + * |
| 56 | + * @see constraints for the values in pixels. |
| 57 | + */ |
| 58 | + val maxWidth: Dp |
| 59 | +
|
| 60 | + /** |
| 61 | + * The minimum height in [Dp]. |
| 62 | + * |
| 63 | + * @see constraints for the values in pixels. |
| 64 | + */ |
| 65 | + val minHeight: Dp |
| 66 | +
|
| 67 | + /** |
| 68 | + * The maximum height in [Dp]. |
| 69 | + * |
| 70 | + * @see constraints for the values in pixels. |
| 71 | + */ |
| 72 | + val maxHeight: Dp |
| 73 | +
|
| 74 | + /** |
| 75 | + * Width of area inside BoxWithConstraints that is scaled based on [ContentScale] |
| 76 | + * This is width of the [Canvas] draw draws [ImageBitmap] |
| 77 | + */ |
| 78 | + val imageWidth: Dp |
| 79 | +
|
| 80 | + /** |
| 81 | + * Height of area inside BoxWithConstraints that is scaled based on [ContentScale] |
| 82 | + * This is height of the [Canvas] draw draws [ImageBitmap] |
| 83 | + */ |
| 84 | + val imageHeight: Dp |
| 85 | +
|
| 86 | + /** |
| 87 | + * [IntRect] that covers boundaries of [ImageBitmap] |
| 88 | + */ |
| 89 | + val rect: IntRect |
| 90 | +} |
| 91 | +``` |
| 92 | + |
| 93 | +* drawImage param is to set whether this Composable should draw on Canvas or `content` param |
| 94 | +should get scope parameter and draw it |
| 95 | + |
| 96 | +## ImageWithThumbnail |
| 97 | +`ImageWithThumbnail` displays thumbnail of bitmap it draws in corner specified |
| 98 | +by `ThumbnailState.position`. When touch position is close to thumbnail position |
| 99 | +if `ThumbnailState.dynamicPosition` is set to true moves thumbnail |
| 100 | +to corner specified by `ThumbnailState.moveTo` |
| 101 | + |
| 102 | +```kotlin |
| 103 | +@Composable |
| 104 | +fun ImageWithThumbnail( |
| 105 | + modifier: Modifier = Modifier, |
| 106 | + imageBitmap: ImageBitmap, |
| 107 | + contentScale: ContentScale = ContentScale.Fit, |
| 108 | + alignment: Alignment = Alignment.Center, |
| 109 | + contentDescription: String?, |
| 110 | + thumbnailState: ThumbnailState = rememberThumbnailState(), |
| 111 | + alpha: Float = DefaultAlpha, |
| 112 | + colorFilter: ColorFilter? = null, |
| 113 | + filterQuality: FilterQuality = DrawScope.DefaultFilterQuality, |
| 114 | + drawOriginalImage: Boolean = true, |
| 115 | + onDown: ((Offset) -> Unit)? = null, |
| 116 | + onMove: ((Offset) -> Unit)? = null, |
| 117 | + onUp: (() -> Unit)? = null, |
| 118 | + onThumbnailCenterChange: ((Offset) -> Unit)? = null, |
| 119 | + content: @Composable ImageScope.() -> Unit = {} |
| 120 | +) { |
| 121 | + |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +## TransformLayout |
| 126 | +Composable that changes scale of its content from handles, translates its position |
| 127 | +when dragged inside bounds |
| 128 | + |
| 129 | +```kotlin |
| 130 | +@Composable |
| 131 | +fun TransformLayout( |
| 132 | + modifier: Modifier = Modifier, |
| 133 | + enabled: Boolean = true, |
| 134 | + handleRadius: Dp = 15.dp, |
| 135 | + handlePlacement: HandlePlacement = HandlePlacement.Corner, |
| 136 | + onDown: (Transform) -> Unit = {}, |
| 137 | + onMove: (Transform) -> Unit = {}, |
| 138 | + onUp: (Transform) -> Unit = {}, |
| 139 | + content: @Composable () -> Unit |
| 140 | +) { |
| 141 | + |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +## MorphLayout |
| 146 | +Composable that changes dimensions of its content from handles, translates its position |
| 147 | +when dragged inside bounds. When using be mindful about the parent composable that contains this |
| 148 | +Composable since maximum width and height this Composable depends on how a Composable, |
| 149 | +Column for instance, lays out its children. It can be expanded upto remaining space if other |
| 150 | +sibling occupy rest of the parent's available space |
| 151 | + |
| 152 | +```kotlin |
| 153 | +@Composable |
| 154 | +fun MorphLayout( |
| 155 | + modifier: Modifier = Modifier, |
| 156 | + containerModifier: Modifier = Modifier, |
| 157 | + enabled: Boolean = true, |
| 158 | + handleRadius: Dp = 15.dp, |
| 159 | + handlePlacement: HandlePlacement = HandlePlacement.Corner, |
| 160 | + updatePhysicalSize: Boolean = false, |
| 161 | + onDown: () -> Unit = {}, |
| 162 | + onMove: (DpSize) -> Unit = {}, |
| 163 | + onUp: () -> Unit = {}, |
| 164 | + content: @Composable () -> Unit |
| 165 | +) { |
| 166 | +} |
| 167 | +``` |
| 168 | + |
| 169 | +## ZoomableImage |
| 170 | +Zoomable image that zooms in and out in [ [minZoom], [maxZoom] ] interval and translates |
| 171 | +zoomed image based on pointer position. |
| 172 | +Double tap gestures reset image translation and zoom to default values with animation. |
| 173 | + |
| 174 | +```kotlin |
| 175 | +@Composable |
| 176 | +fun ZoomableImage( |
| 177 | + modifier: Modifier = Modifier, |
| 178 | + imageBitmap: ImageBitmap, |
| 179 | + alignment: Alignment = Alignment.Center, |
| 180 | + contentScale: ContentScale = ContentScale.Fit, |
| 181 | + contentDescription: String? = null, |
| 182 | + alpha: Float = DefaultAlpha, |
| 183 | + initialZoom: Float = 1f, |
| 184 | + minZoom: Float = 1f, |
| 185 | + maxZoom: Float = 5f, |
| 186 | + clipTransformToContentScale: Boolean = false, |
| 187 | + colorFilter: ColorFilter? = null, |
| 188 | + filterQuality: FilterQuality = DrawScope.DefaultFilterQuality, |
| 189 | +) { |
| 190 | +} |
| 191 | +``` |
0 commit comments