For only with Files now
This commit is contained in:
parent
b31178683c
commit
544bff9f4f
|
@ -21,56 +21,46 @@ import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.graphics.Matrix
|
import android.graphics.Matrix
|
||||||
import android.net.Uri
|
|
||||||
import androidx.core.content.FileProvider
|
|
||||||
import androidx.exifinterface.media.ExifInterface
|
import androidx.exifinterface.media.ExifInterface
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.matrix.android.sdk.internal.di.SessionDownloadsDirectory
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.SimpleDateFormat
|
import java.util.UUID
|
||||||
import java.util.Date
|
|
||||||
import java.util.Locale
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class ImageCompressor @Inject constructor(
|
internal class ImageCompressor @Inject constructor() {
|
||||||
@SessionDownloadsDirectory
|
|
||||||
private val sessionCacheDirectory: File
|
|
||||||
) {
|
|
||||||
private val cacheFolder = File(sessionCacheDirectory, "MF")
|
|
||||||
|
|
||||||
suspend fun compress(
|
suspend fun compress(
|
||||||
context: Context,
|
context: Context,
|
||||||
imageUri: Uri,
|
imageFile: File,
|
||||||
desiredWidth: Int,
|
desiredWidth: Int,
|
||||||
desiredHeight: Int,
|
desiredHeight: Int,
|
||||||
desiredQuality: Int = 80): Uri {
|
desiredQuality: Int = 80): File {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val compressedBitmap = BitmapFactory.Options().run {
|
val compressedBitmap = BitmapFactory.Options().run {
|
||||||
inJustDecodeBounds = true
|
inJustDecodeBounds = true
|
||||||
decodeBitmap(context, imageUri, this)
|
decodeBitmap(imageFile, this)
|
||||||
inSampleSize = calculateInSampleSize(outWidth, outHeight, desiredWidth, desiredHeight)
|
inSampleSize = calculateInSampleSize(outWidth, outHeight, desiredWidth, desiredHeight)
|
||||||
inJustDecodeBounds = false
|
inJustDecodeBounds = false
|
||||||
decodeBitmap(context, imageUri, this)?.let {
|
decodeBitmap(imageFile, this)?.let {
|
||||||
rotateBitmap(context, imageUri, it)
|
rotateBitmap(imageFile, it)
|
||||||
}
|
}
|
||||||
} ?: return@withContext imageUri
|
} ?: return@withContext imageFile
|
||||||
|
|
||||||
val destinationUri = createDestinationUri(context)
|
val destinationFile = createDestinationFile(context)
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
context.contentResolver.openOutputStream(destinationUri).use {
|
destinationFile.outputStream().use {
|
||||||
compressedBitmap.compress(Bitmap.CompressFormat.JPEG, desiredQuality, it)
|
compressedBitmap.compress(Bitmap.CompressFormat.JPEG, desiredQuality, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return@withContext destinationUri
|
return@withContext destinationFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun rotateBitmap(context: Context, uri: Uri, bitmap: Bitmap): Bitmap {
|
private fun rotateBitmap(file: File, bitmap: Bitmap): Bitmap {
|
||||||
context.contentResolver.openInputStream(uri)?.use { inputStream ->
|
file.inputStream().use { inputStream ->
|
||||||
try {
|
try {
|
||||||
ExifInterface(inputStream).let { exifInfo ->
|
ExifInterface(inputStream).let { exifInfo ->
|
||||||
val orientation = exifInfo.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
|
val orientation = exifInfo.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
|
||||||
|
@ -94,7 +84,7 @@ internal class ImageCompressor @Inject constructor(
|
||||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "Cannot read orientation: %s", uri.toString())
|
Timber.e(e, "Cannot read orientation")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bitmap
|
return bitmap
|
||||||
|
@ -118,9 +108,9 @@ internal class ImageCompressor @Inject constructor(
|
||||||
return inSampleSize
|
return inSampleSize
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun decodeBitmap(context: Context, uri: Uri, options: BitmapFactory.Options = BitmapFactory.Options()): Bitmap? {
|
private fun decodeBitmap(file: File, options: BitmapFactory.Options = BitmapFactory.Options()): Bitmap? {
|
||||||
return try {
|
return try {
|
||||||
context.contentResolver.openInputStream(uri)?.use { inputStream ->
|
file.inputStream().use { inputStream ->
|
||||||
BitmapFactory.decodeStream(inputStream, null, options)
|
BitmapFactory.decodeStream(inputStream, null, options)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -129,19 +119,7 @@ internal class ImageCompressor @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDestinationUri(context: Context): Uri {
|
private fun createDestinationFile(context: Context): File {
|
||||||
val file = createTempFile()
|
return File.createTempFile(UUID.randomUUID().toString(), null, context.cacheDir)
|
||||||
val authority = "${context.packageName}.mx-sdk.fileprovider"
|
|
||||||
return FileProvider.getUriForFile(context, authority, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createTempFile(): File {
|
|
||||||
if (!cacheFolder.exists()) cacheFolder.mkdirs()
|
|
||||||
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
|
||||||
return File.createTempFile(
|
|
||||||
"${timeStamp}_", /* prefix */
|
|
||||||
".jpg", /* suffix */
|
|
||||||
cacheFolder /* directory */
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,6 @@ package org.matrix.android.sdk.internal.session.content
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import androidx.core.net.toFile
|
|
||||||
import androidx.core.net.toUri
|
|
||||||
import androidx.work.CoroutineWorker
|
import androidx.work.CoroutineWorker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
@ -129,7 +127,6 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
||||||
inputStream.copyTo(it)
|
inputStream.copyTo(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inputStream.use {
|
|
||||||
var uploadedThumbnailUrl: String? = null
|
var uploadedThumbnailUrl: String? = null
|
||||||
var uploadedThumbnailEncryptedFileInfo: EncryptedFileInfo? = null
|
var uploadedThumbnailEncryptedFileInfo: EncryptedFileInfo? = null
|
||||||
|
|
||||||
|
@ -181,9 +178,10 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
||||||
val fileToUpload: File
|
val fileToUpload: File
|
||||||
|
|
||||||
if (attachment.type == ContentAttachmentData.Type.IMAGE && params.compressBeforeSending) {
|
if (attachment.type == ContentAttachmentData.Type.IMAGE && params.compressBeforeSending) {
|
||||||
fileToUpload = imageCompressor.compress(context, workingFile.toUri(), MAX_IMAGE_SIZE, MAX_IMAGE_SIZE)
|
fileToUpload = imageCompressor.compress(context, workingFile, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE)
|
||||||
.also { compressedUri ->
|
.also { compressedFile ->
|
||||||
context.contentResolver.openInputStream(compressedUri)?.use {
|
// Get new Bitmap size
|
||||||
|
compressedFile.inputStream().use {
|
||||||
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||||
val bitmap = BitmapFactory.decodeStream(it, null, options)
|
val bitmap = BitmapFactory.decodeStream(it, null, options)
|
||||||
val fileSize = bitmap?.byteCount ?: 0
|
val fileSize = bitmap?.byteCount ?: 0
|
||||||
|
@ -194,7 +192,9 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toFile()
|
|
||||||
|
// we can delete workingFile
|
||||||
|
tryThis { workingFile.delete() }
|
||||||
} else {
|
} else {
|
||||||
fileToUpload = workingFile
|
fileToUpload = workingFile
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
||||||
}
|
}
|
||||||
Timber.v("## FileService: cache storage updated")
|
Timber.v("## FileService: cache storage updated")
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
Timber.e(failure, "## FileService: Failed to update fileservice cache")
|
Timber.e(failure, "## FileService: Failed to update file cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSuccess(params,
|
handleSuccess(params,
|
||||||
|
|
Loading…
Reference in New Issue