@@ -27,7 +27,6 @@ import io.element.android.libraries.androidutils.file.createTmpFile
27
27
import io.element.android.libraries.di.ApplicationContext
28
28
import kotlinx.coroutines.Dispatchers
29
29
import kotlinx.coroutines.withContext
30
- import java.io.BufferedInputStream
31
30
import java.io.File
32
31
import java.io.InputStream
33
32
import javax.inject.Inject
@@ -42,14 +41,14 @@ class ImageCompressor @Inject constructor(
42
41
* @return a [Result] containing the resulting [ImageCompressionResult] with the temporary [File] and some metadata.
43
42
*/
44
43
suspend fun compressToTmpFile (
45
- inputStream : InputStream ,
44
+ inputStreamProvider : () -> InputStream ,
46
45
resizeMode : ResizeMode ,
47
46
format : Bitmap .CompressFormat = Bitmap .CompressFormat .JPEG ,
48
47
orientation : Int = ExifInterface .ORIENTATION_UNDEFINED ,
49
48
desiredQuality : Int = 80,
50
49
): Result <ImageCompressionResult > = withContext(Dispatchers .IO ) {
51
50
runCatching {
52
- val compressedBitmap = compressToBitmap(inputStream , resizeMode, orientation).getOrThrow()
51
+ val compressedBitmap = compressToBitmap(inputStreamProvider , resizeMode, orientation).getOrThrow()
53
52
// Encode bitmap to the destination temporary file
54
53
val tmpFile = context.createTmpFile(extension = " jpeg" )
55
54
tmpFile.outputStream().use {
@@ -65,17 +64,24 @@ class ImageCompressor @Inject constructor(
65
64
}
66
65
67
66
/* *
68
- * Decodes the [inputStream] into a [Bitmap] and applies the needed transformations (rotation, scale) based on [resizeMode] and [orientation].
67
+ * Decodes the inputStream from [inputStreamProvider] into a [Bitmap] and applies the needed transformations (rotation, scale)
68
+ * based on [resizeMode] and [orientation].
69
69
* @return a [Result] containing the resulting [Bitmap].
70
70
*/
71
71
fun compressToBitmap (
72
- inputStream : InputStream ,
72
+ inputStreamProvider : () -> InputStream ,
73
73
resizeMode : ResizeMode ,
74
74
orientation : Int ,
75
75
): Result <Bitmap > = runCatching {
76
- BufferedInputStream (inputStream).use { input ->
77
- val options = BitmapFactory .Options ()
76
+ val options = BitmapFactory .Options ()
77
+ // Decode bounds
78
+ inputStreamProvider().use { input ->
78
79
calculateDecodingScale(input, resizeMode, options)
80
+ }
81
+ // Decode the actual bitmap
82
+ inputStreamProvider().use { input ->
83
+ // Now read the actual image and rotate it to match its metadata
84
+ options.inJustDecodeBounds = false
79
85
val decodedBitmap = BitmapFactory .decodeStream(input, null , options)
80
86
? : error(" Decoding Bitmap from InputStream failed" )
81
87
val rotatedBitmap = decodedBitmap.rotateToMetadataOrientation(orientation)
@@ -88,7 +94,7 @@ class ImageCompressor @Inject constructor(
88
94
}
89
95
90
96
private fun calculateDecodingScale (
91
- inputStream : BufferedInputStream ,
97
+ inputStream : InputStream ,
92
98
resizeMode : ResizeMode ,
93
99
options : BitmapFactory .Options
94
100
) {
@@ -98,14 +104,10 @@ class ImageCompressor @Inject constructor(
98
104
is ResizeMode .None -> return
99
105
}
100
106
// Read bounds only
101
- inputStream.mark(inputStream.available())
102
107
options.inJustDecodeBounds = true
103
108
BitmapFactory .decodeStream(inputStream, null , options)
104
109
// Set sample size based on the outWidth and outHeight
105
110
options.inSampleSize = options.calculateInSampleSize(width, height)
106
- // Now read the actual image and rotate it to match its metadata
107
- inputStream.reset()
108
- options.inJustDecodeBounds = false
109
111
}
110
112
}
111
113
0 commit comments