mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-20 03:59:35 +01:00
fix displaying of large images
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
ec976fcbdd
commit
e03f048126
@ -186,6 +186,7 @@ dependencies {
|
|||||||
implementation "androidx.work:work-runtime:${workVersion}"
|
implementation "androidx.work:work-runtime:${workVersion}"
|
||||||
implementation "androidx.work:work-rxjava2:${workVersion}"
|
implementation "androidx.work:work-rxjava2:${workVersion}"
|
||||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||||
|
implementation 'androidx.exifinterface:exifinterface:1.3.2'
|
||||||
androidTestImplementation "androidx.work:work-testing:${workVersion}"
|
androidTestImplementation "androidx.work:work-testing:${workVersion}"
|
||||||
implementation 'com.google.android:flexbox:2.0.1'
|
implementation 'com.google.android:flexbox:2.0.1'
|
||||||
implementation ('com.gitlab.bitfireAT:dav4jvm:2.1.2', {
|
implementation ('com.gitlab.bitfireAT:dav4jvm:2.1.2', {
|
||||||
|
@ -25,29 +25,26 @@
|
|||||||
package com.nextcloud.talk.activities
|
package com.nextcloud.talk.activities
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import com.nextcloud.talk.BuildConfig
|
import com.nextcloud.talk.BuildConfig
|
||||||
import com.nextcloud.talk.R
|
import com.nextcloud.talk.R
|
||||||
import com.nextcloud.talk.databinding.ActivityFullScreenImageBinding
|
import com.nextcloud.talk.databinding.ActivityFullScreenImageBinding
|
||||||
|
import com.nextcloud.talk.utils.BitmapShrinker
|
||||||
import pl.droidsonroids.gif.GifDrawable
|
import pl.droidsonroids.gif.GifDrawable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class FullScreenImageActivity : AppCompatActivity() {
|
class FullScreenImageActivity : AppCompatActivity() {
|
||||||
lateinit var binding: ActivityFullScreenImageBinding
|
lateinit var binding: ActivityFullScreenImageBinding
|
||||||
|
|
||||||
private lateinit var path: String
|
private lateinit var path: String
|
||||||
|
|
||||||
private var showFullscreen = false
|
private var showFullscreen = false
|
||||||
|
|
||||||
private val maxScale = 6.0f
|
|
||||||
private val mediumScale = 2.45f
|
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
menuInflater.inflate(R.menu.menu_preview, menu)
|
menuInflater.inflate(R.menu.menu_preview, menu)
|
||||||
return true
|
return true
|
||||||
@ -98,8 +95,8 @@ class FullScreenImageActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
// Enable enlarging the image more than default 3x maximumScale.
|
// Enable enlarging the image more than default 3x maximumScale.
|
||||||
// Medium scale adapted to make double-tap behaviour more consistent.
|
// Medium scale adapted to make double-tap behaviour more consistent.
|
||||||
binding.photoView.maximumScale = maxScale
|
binding.photoView.maximumScale = MAX_SCALE
|
||||||
binding.photoView.mediumScale = mediumScale
|
binding.photoView.mediumScale = MEDIUM_SCALE
|
||||||
|
|
||||||
val fileName = intent.getStringExtra("FILE_NAME")
|
val fileName = intent.getStringExtra("FILE_NAME")
|
||||||
val isGif = intent.getBooleanExtra("IS_GIF", false)
|
val isGif = intent.getBooleanExtra("IS_GIF", false)
|
||||||
@ -116,7 +113,25 @@ class FullScreenImageActivity : AppCompatActivity() {
|
|||||||
} else {
|
} else {
|
||||||
binding.gifView.visibility = View.INVISIBLE
|
binding.gifView.visibility = View.INVISIBLE
|
||||||
binding.photoView.visibility = View.VISIBLE
|
binding.photoView.visibility = View.VISIBLE
|
||||||
binding.photoView.setImageURI(Uri.parse(path))
|
displayImage(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun displayImage(path: String) {
|
||||||
|
val displayMetrics = applicationContext.resources.displayMetrics
|
||||||
|
val doubleScreenWidth = displayMetrics.widthPixels * 2
|
||||||
|
val doubleScreenHeight = displayMetrics.heightPixels * 2
|
||||||
|
|
||||||
|
val bitmap = BitmapShrinker.shrinkBitmap(path, doubleScreenWidth, doubleScreenHeight)
|
||||||
|
|
||||||
|
val bitmapSize: Int = bitmap.byteCount
|
||||||
|
|
||||||
|
// info that 100MB is the limit comes from https://stackoverflow.com/a/53334563
|
||||||
|
if (bitmapSize > HUNDRED_MB) {
|
||||||
|
Log.e(TAG, "bitmap will be too large to display. It won't be displayed to avoid RuntimeException")
|
||||||
|
Toast.makeText(this, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
|
||||||
|
} else {
|
||||||
|
binding.photoView.setImageBitmap(bitmap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,4 +164,11 @@ class FullScreenImageActivity : AppCompatActivity() {
|
|||||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = "FullScreenImageActivity"
|
||||||
|
private const val HUNDRED_MB = 100 * 1024 * 1024
|
||||||
|
private const val MAX_SCALE = 6.0f
|
||||||
|
private const val MEDIUM_SCALE = 2.45f
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
112
app/src/main/java/com/nextcloud/talk/utils/BitmapShrinker.kt
Normal file
112
app/src/main/java/com/nextcloud/talk/utils/BitmapShrinker.kt
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Marcel Hibbe
|
||||||
|
* Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.utils
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.Matrix
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.exifinterface.media.ExifInterface
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
object BitmapShrinker {
|
||||||
|
|
||||||
|
private val TAG = "BitmapShrinker"
|
||||||
|
private const val DEGREES_90 = 90f
|
||||||
|
private const val DEGREES_180 = 180f
|
||||||
|
private const val DEGREES_270 = 270f
|
||||||
|
|
||||||
|
fun shrinkBitmap(
|
||||||
|
path: String,
|
||||||
|
reqWidth: Int,
|
||||||
|
reqHeight: Int
|
||||||
|
): Bitmap {
|
||||||
|
val bitmap = decodeBitmap(path, reqWidth, reqHeight)
|
||||||
|
return rotateBitmap(path, bitmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// solution inspired by https://developer.android.com/topic/performance/graphics/load-bitmap
|
||||||
|
private fun decodeBitmap(
|
||||||
|
path: String,
|
||||||
|
requestedWidth: Int,
|
||||||
|
requestedHeight: Int
|
||||||
|
): Bitmap {
|
||||||
|
return BitmapFactory.Options().run {
|
||||||
|
inJustDecodeBounds = true
|
||||||
|
BitmapFactory.decodeFile(path, this)
|
||||||
|
inSampleSize = getInSampleSize(this, requestedWidth, requestedHeight)
|
||||||
|
inJustDecodeBounds = false
|
||||||
|
BitmapFactory.decodeFile(path, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// solution inspired by https://developer.android.com/topic/performance/graphics/load-bitmap
|
||||||
|
private fun getInSampleSize(
|
||||||
|
options: BitmapFactory.Options,
|
||||||
|
requestedWidth: Int,
|
||||||
|
requestedHeight: Int
|
||||||
|
): Int {
|
||||||
|
val (height: Int, width: Int) = options.run { outHeight to outWidth }
|
||||||
|
var inSampleSize = 1
|
||||||
|
if (height > requestedHeight || width > requestedWidth) {
|
||||||
|
val halfHeight: Int = height / 2
|
||||||
|
val halfWidth: Int = width / 2
|
||||||
|
// "||" was used instead of "&&". Otherwise it would still crash for wide panorama photos.
|
||||||
|
while (halfHeight / inSampleSize >= requestedHeight || halfWidth / inSampleSize >= requestedWidth) {
|
||||||
|
inSampleSize *= 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inSampleSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// solution inspired by https://stackoverflow.com/a/15341203
|
||||||
|
private fun rotateBitmap(path: String, bitmap: Bitmap): Bitmap {
|
||||||
|
try {
|
||||||
|
val exif = ExifInterface(path)
|
||||||
|
val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1)
|
||||||
|
val matrix = Matrix()
|
||||||
|
when (orientation) {
|
||||||
|
ExifInterface.ORIENTATION_ROTATE_90 -> {
|
||||||
|
matrix.postRotate(DEGREES_90)
|
||||||
|
}
|
||||||
|
ExifInterface.ORIENTATION_ROTATE_180 -> {
|
||||||
|
matrix.postRotate(DEGREES_180)
|
||||||
|
}
|
||||||
|
ExifInterface.ORIENTATION_ROTATE_270 -> {
|
||||||
|
matrix.postRotate(DEGREES_270)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val rotatedBitmap = Bitmap.createBitmap(
|
||||||
|
bitmap,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
bitmap.getWidth(),
|
||||||
|
bitmap.getHeight(),
|
||||||
|
matrix,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
return rotatedBitmap
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e(TAG, "error while rotating image", e)
|
||||||
|
}
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user