Skip to content

Commit

Permalink
Merge pull request #42 from shtolik/compression
Browse files Browse the repository at this point in the history
Adding compression quality as parameter of ResizeOption. Fixes #41.
  • Loading branch information
onseok authored Mar 10, 2024
2 parents 5d0b2f4 + 6932b30 commit ad6a20d
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 7 deletions.
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ compose-foundation = "1.5.4"
compose-material3 = "1.1.2"
androidx-activityCompose = "1.8.2"
androidx-lifecycleViewmodelCompose = "2.7.0"
androidx-version = "1.7.1"
nexus-publish = "2.0.0-rc-1"
spotless = "6.25.0"
ktlint = "1.0.1"
Expand Down Expand Up @@ -49,6 +50,7 @@ androidx-exifinterface = { group = "androidx.exifinterface", name = "exifinterfa
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycleViewmodelCompose" }
paging-common = { module = "app.cash.paging:paging-common", version.ref = "multiplatform-paging" }
paging-compose-common = { module = "app.cash.paging:paging-compose-common", version.ref = "multiplatform-paging" }
annotation = { module = "androidx.annotation:annotation", version.ref = "androidx-version" }

[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
Expand Down
1 change: 1 addition & 0 deletions peekaboo-image-picker/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ kotlin {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(libs.annotation)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ private fun pickSingleImage(
width = resizeOptions.width,
height = resizeOptions.height,
resizeThresholdBytes = resizeOptions.resizeThresholdBytes,
compressionQuality = resizeOptions.compressionQuality,
filterOptions = filterOptions,
) { resizedImage ->
if (resizedImage != null) {
Expand Down Expand Up @@ -129,6 +130,7 @@ private fun pickMultipleImages(
width = resizeOptions.width,
height = resizeOptions.height,
resizeThresholdBytes = resizeOptions.resizeThresholdBytes,
compressionQuality = resizeOptions.compressionQuality,
filterOptions = filterOptions,
) { resizedImage ->
resizedImage?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import android.graphics.Matrix
import android.graphics.Paint
import android.net.Uri
import android.provider.OpenableColumns
import androidx.annotation.FloatRange
import androidx.exifinterface.media.ExifInterface
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -40,12 +41,14 @@ internal object PeekabooImageResizer {
width: Int,
height: Int,
resizeThresholdBytes: Long,
@FloatRange(from = 0.0, to = 1.0)
compressionQuality: Double,
filterOptions: FilterOptions,
onResult: (ByteArray?) -> Unit,
) {
coroutineScope.launch(Dispatchers.Default) {
if (getImageSize(context, uri) > resizeThresholdBytes) {
val byteArray = resizeImage(context, uri, width, height, filterOptions)
val byteArray = resizeImage(context, uri, width, height, compressionQuality, filterOptions)
withContext(Dispatchers.Main) {
onResult(byteArray)
}
Expand Down Expand Up @@ -86,6 +89,8 @@ internal object PeekabooImageResizer {
uri: Uri,
width: Int,
height: Int,
@FloatRange(from = 0.0, to = 1.0)
compression: Double,
filterOptions: FilterOptions,
): ByteArray? {
val resizeCacheKey = "${uri}_w${width}_h$height"
Expand Down Expand Up @@ -127,7 +132,8 @@ internal object PeekabooImageResizer {
val filteredBitmap = applyFilter(rotatedBitmap, filterOptions)

ByteArrayOutputStream().use { byteArrayOutputStream ->
filteredBitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream)
val validatedCompression = compression.coerceIn(0.0, 1.0)
filteredBitmap.compress(Bitmap.CompressFormat.JPEG, (100 * validatedCompression).toInt(), byteArrayOutputStream)
val byteArray = byteArrayOutputStream.toByteArray()
PeekabooBitmapCache.instance.put(filterCacheKey, filteredBitmap)
return byteArray
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.preat.peekaboo.image.picker

import androidx.annotation.FloatRange
import androidx.compose.runtime.Composable
import kotlinx.coroutines.CoroutineScope

Expand Down Expand Up @@ -45,6 +46,8 @@ data class ResizeOptions(
val width: Int = DEFAULT_RESIZE_IMAGE_WIDTH,
val height: Int = DEFAULT_RESIZE_IMAGE_HEIGHT,
val resizeThresholdBytes: Long = DEFAULT_RESIZE_THRESHOLD_BYTES,
@FloatRange(from = 0.0, to = 1.0)
val compressionQuality: Double = 1.0,
)

sealed interface FilterOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.preat.peekaboo.image.picker

import androidx.annotation.FloatRange
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import kotlinx.cinterop.CValue
Expand Down Expand Up @@ -86,9 +87,10 @@ actual fun rememberImagePickerLauncher(
resizeOptions.width,
resizeOptions.height,
resizeOptions.resizeThresholdBytes,
resizeOptions.compressionQuality,
filterOptions,
)
val bytes = resizedImage?.toByteArray()
val bytes = resizedImage?.toByteArray(resizeOptions.compressionQuality)
if (bytes != null) {
imageData.add(bytes)
}
Expand Down Expand Up @@ -122,8 +124,9 @@ actual fun rememberImagePickerLauncher(
}

@OptIn(ExperimentalForeignApi::class)
private fun UIImage.toByteArray(): ByteArray {
val jpegData = UIImageJPEGRepresentation(this, 1.0)!!
private fun UIImage.toByteArray(compressionQuality: Double): ByteArray {
val validCompressionQuality = compressionQuality.coerceIn(0.0, 1.0)
val jpegData = UIImageJPEGRepresentation(this, validCompressionQuality)!!
return ByteArray(jpegData.length.toInt()).apply {
memcpy(this.refTo(0), jpegData.bytes, jpegData.length)
}
Expand All @@ -134,9 +137,11 @@ private fun UIImage.fitInto(
maxWidth: Int,
maxHeight: Int,
resizeThresholdBytes: Long,
@FloatRange(from = 0.0, to = 1.0)
compressionQuality: Double,
filterOptions: FilterOptions,
): UIImage {
val imageData = this.toByteArray()
val imageData = this.toByteArray(compressionQuality)
if (imageData.size > resizeThresholdBytes) {
val originalWidth = this.size.useContents { width }
val originalHeight = this.size.useContents { height }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ fun App() {
selectionMode = SelectionMode.Multiple(maxSelection = 5),
scope = scope,
// Resize options are customizable. Default is set to 800 x 800 pixels.
resizeOptions = ResizeOptions(width = 1200, height = 1200),
resizeOptions = ResizeOptions(width = 1200, height = 1200, compressionQuality = 1.0),
// Default is 'Default', which applies no filter.
// Other available options: GrayScale, Sepia, Invert.
filterOptions = FilterOptions.GrayScale,
Expand Down

0 comments on commit ad6a20d

Please sign in to comment.