use Picasso as a decoder for fullscreen SubsamplingScaleImageView images
This commit is contained in:
parent
4ea5e34b0f
commit
23dd5baaa4
7 changed files with 80 additions and 58 deletions
|
@ -58,6 +58,7 @@ dependencies {
|
|||
implementation 'com.google.vr:sdk-panowidget:1.150.0'
|
||||
implementation 'org.apache.sanselan:sanselan:0.97-incubator'
|
||||
implementation 'info.androidhive:imagefilters:1.0.7'
|
||||
implementation 'com.squareup.picasso:picasso:2.71828'
|
||||
|
||||
kapt "android.arch.persistence.room:compiler:1.1.1"
|
||||
implementation "android.arch.persistence.room:runtime:1.1.1"
|
||||
|
|
6
app/proguard-rules.pro
vendored
6
app/proguard-rules.pro
vendored
|
@ -1,3 +1,9 @@
|
|||
-keep class com.simplemobiletools.** { *; }
|
||||
-dontwarn com.simplemobiletools.**
|
||||
-dontwarn org.apache.**
|
||||
|
||||
# Picasso
|
||||
-dontwarn javax.annotation.**
|
||||
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
||||
-dontwarn okhttp3.internal.platform.ConscryptPlatform
|
||||
|
|
|
@ -77,7 +77,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
companion object {
|
||||
var screenWidth = 0
|
||||
var screenHeight = 0
|
||||
var wasDecodedByGlide = false
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
|
@ -61,7 +61,7 @@ fun Activity.launchCamera() {
|
|||
|
||||
fun SimpleActivity.launchAbout() {
|
||||
val licenses = LICENSE_GLIDE or LICENSE_CROPPER or LICENSE_MULTISELECT or LICENSE_RTL or LICENSE_SUBSAMPLING or LICENSE_PATTERN or
|
||||
LICENSE_REPRINT or LICENSE_GIF_DRAWABLE or LICENSE_PHOTOVIEW or LICENSE_EXOPLAYER or LICENSE_PANORAMA_VIEW or LICENSE_SANSELAN or LICENSE_FILTERS
|
||||
LICENSE_REPRINT or LICENSE_GIF_DRAWABLE or LICENSE_PHOTOVIEW or LICENSE_PICASSO or LICENSE_EXOPLAYER or LICENSE_PANORAMA_VIEW or LICENSE_SANSELAN or LICENSE_FILTERS
|
||||
|
||||
val faqItems = arrayListOf(
|
||||
FAQItem(R.string.faq_5_title_commons, R.string.faq_5_text_commons),
|
||||
|
|
|
@ -9,20 +9,14 @@ import android.graphics.Matrix
|
|||
import android.graphics.drawable.ColorDrawable
|
||||
import android.media.ExifInterface.*
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.DecodeFormat
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.load.engine.GlideException
|
||||
import com.bumptech.glide.request.RequestListener
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.davemorrissey.labs.subscaleview.ImageSource
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
|
@ -33,11 +27,10 @@ import com.simplemobiletools.gallery.activities.PanoramaActivity
|
|||
import com.simplemobiletools.gallery.activities.PhotoActivity
|
||||
import com.simplemobiletools.gallery.activities.ViewPagerActivity
|
||||
import com.simplemobiletools.gallery.extensions.*
|
||||
import com.simplemobiletools.gallery.helpers.GlideRotateTransformation
|
||||
import com.simplemobiletools.gallery.helpers.MEDIUM
|
||||
import com.simplemobiletools.gallery.helpers.PATH
|
||||
import com.simplemobiletools.gallery.helpers.ROTATE_BY_ASPECT_RATIO
|
||||
import com.simplemobiletools.gallery.helpers.*
|
||||
import com.simplemobiletools.gallery.models.Medium
|
||||
import com.squareup.picasso.Callback
|
||||
import com.squareup.picasso.Picasso
|
||||
import it.sephiroth.android.library.exif2.ExifInterface
|
||||
import kotlinx.android.synthetic.main.pager_photo_item.view.*
|
||||
import org.apache.sanselan.common.byteSources.ByteSourceInputStream
|
||||
|
@ -48,12 +41,11 @@ import java.io.FileOutputStream
|
|||
|
||||
class PhotoFragment : ViewPagerFragment() {
|
||||
private val DEFAULT_DOUBLE_TAP_ZOOM = 2f
|
||||
private val ZOOMABLE_VIEW_LOAD_DELAY = 1000L
|
||||
private val ZOOMABLE_VIEW_LOAD_DELAY = 500L
|
||||
|
||||
private var isFragmentVisible = false
|
||||
private var isFullscreen = false
|
||||
private var wasInit = false
|
||||
private var useHalfResolution = false
|
||||
private var isPanorama = false
|
||||
private var imageOrientation = -1
|
||||
private var gifDrawable: GifDrawable? = null
|
||||
|
@ -245,48 +237,19 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
|
||||
private fun loadBitmap(degrees: Int = 0) {
|
||||
if (degrees == 0) {
|
||||
var targetWidth = if (ViewPagerActivity.screenWidth == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenWidth
|
||||
var targetHeight = if (ViewPagerActivity.screenHeight == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenHeight
|
||||
if (useHalfResolution) {
|
||||
targetWidth /= 2
|
||||
targetHeight /= 2
|
||||
}
|
||||
|
||||
if (imageOrientation == ORIENTATION_ROTATE_90) {
|
||||
targetWidth = targetHeight
|
||||
targetHeight = Target.SIZE_ORIGINAL
|
||||
}
|
||||
|
||||
val options = RequestOptions()
|
||||
.signature(medium.path.getFileSignature())
|
||||
.format(DecodeFormat.PREFER_ARGB_8888)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.override(targetWidth, targetHeight)
|
||||
|
||||
Glide.with(this)
|
||||
.asBitmap()
|
||||
.load(getPathToLoad(medium))
|
||||
.apply(options)
|
||||
.listener(object : RequestListener<Bitmap> {
|
||||
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean): Boolean {
|
||||
if (!useHalfResolution && e?.rootCauses?.firstOrNull() is OutOfMemoryError) {
|
||||
useHalfResolution = true
|
||||
Handler().post {
|
||||
if (activity?.isActivityDestroyed() == false) {
|
||||
loadBitmap(degrees)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
|
||||
Picasso.get()
|
||||
.load(File(medium.path))
|
||||
.centerInside()
|
||||
.fit()
|
||||
.into(view.photo_view, object : Callback {
|
||||
override fun onSuccess() {
|
||||
if (isFragmentVisible) {
|
||||
scheduleZoomableView()
|
||||
}
|
||||
return false
|
||||
}
|
||||
}).into(view.photo_view)
|
||||
|
||||
override fun onError(e: Exception) {}
|
||||
})
|
||||
} else {
|
||||
val options = RequestOptions()
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
|
@ -311,23 +274,24 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
private fun scheduleZoomableView() {
|
||||
loadZoomableViewHandler.removeCallbacksAndMessages(null)
|
||||
loadZoomableViewHandler.postDelayed({
|
||||
if (isFragmentVisible && !context!!.config.replaceZoomableImages && medium.isImage() && view.subsampling_view.isGone()) {
|
||||
if (isFragmentVisible && medium.isImage() && view.subsampling_view.isGone()) {
|
||||
addZoomableView()
|
||||
}
|
||||
}, ZOOMABLE_VIEW_LOAD_DELAY)
|
||||
}
|
||||
|
||||
private fun addZoomableView() {
|
||||
ViewPagerActivity.wasDecodedByGlide = false
|
||||
val rotation = degreesForRotation(imageOrientation)
|
||||
view.subsampling_view.apply {
|
||||
setBitmapDecoderFactory { PicassoDecoder(medium.path, Picasso.get(), rotation) }
|
||||
setRegionDecoderFactory { PicassoRegionDecoder() }
|
||||
maxScale = 10f
|
||||
beVisible()
|
||||
isQuickScaleEnabled = context.config.oneFingerZoom
|
||||
setResetScaleOnSizeChange(context.config.screenRotation != ROTATE_BY_ASPECT_RATIO)
|
||||
setImage(ImageSource.uri(getPathToLoad(medium)))
|
||||
orientation = if (imageOrientation == -1) SubsamplingScaleImageView.ORIENTATION_USE_EXIF else degreesForRotation(imageOrientation)
|
||||
orientation = rotation
|
||||
setEagerLoadingEnabled(false)
|
||||
setExecutor(AsyncTask.SERIAL_EXECUTOR)
|
||||
setOnImageEventListener(object : SubsamplingScaleImageView.OnImageEventListener {
|
||||
override fun onImageLoaded() {
|
||||
}
|
||||
|
@ -400,8 +364,6 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
|
||||
return if (context == null || bitmapAspectRatio == screenAspectRatio) {
|
||||
DEFAULT_DOUBLE_TAP_ZOOM
|
||||
} else if (ViewPagerActivity.wasDecodedByGlide) {
|
||||
1f
|
||||
} else if (context!!.portrait && bitmapAspectRatio <= screenAspectRatio) {
|
||||
ViewPagerActivity.screenHeight / height.toFloat()
|
||||
} else if (context!!.portrait && bitmapAspectRatio > screenAspectRatio) {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.simplemobiletools.gallery.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import com.davemorrissey.labs.subscaleview.decoder.ImageDecoder
|
||||
import com.squareup.picasso.MemoryPolicy
|
||||
import com.squareup.picasso.Picasso
|
||||
|
||||
class PicassoDecoder(val tag: String, val picasso: Picasso, val degrees: Int) : ImageDecoder {
|
||||
|
||||
override fun decode(context: Context, uri: Uri): Bitmap {
|
||||
return picasso
|
||||
.load(uri)
|
||||
.tag(tag)
|
||||
.config(Bitmap.Config.ARGB_8888)
|
||||
.memoryPolicy(MemoryPolicy.NO_CACHE)
|
||||
.rotate(-degrees.toFloat())
|
||||
.get()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.simplemobiletools.gallery.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.net.Uri
|
||||
import com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder
|
||||
|
||||
class PicassoRegionDecoder : ImageRegionDecoder {
|
||||
private var decoder: BitmapRegionDecoder? = null
|
||||
private val decoderLock = Any()
|
||||
|
||||
override fun init(context: Context, uri: Uri): Point {
|
||||
val inputStream = context.contentResolver.openInputStream(uri)
|
||||
this.decoder = BitmapRegionDecoder.newInstance(inputStream, false)
|
||||
return Point(this.decoder!!.width, this.decoder!!.height)
|
||||
}
|
||||
|
||||
override fun decodeRegion(rect: Rect, sampleSize: Int): Bitmap {
|
||||
synchronized(this.decoderLock) {
|
||||
val options = BitmapFactory.Options()
|
||||
options.inSampleSize = sampleSize
|
||||
options.inPreferredConfig = Bitmap.Config.ARGB_8888
|
||||
val bitmap = this.decoder!!.decodeRegion(rect, options)
|
||||
return bitmap ?: throw RuntimeException("Region decoder returned null bitmap - image format may not be supported")
|
||||
}
|
||||
}
|
||||
|
||||
override fun isReady() = this.decoder != null && !this.decoder!!.isRecycled
|
||||
|
||||
override fun recycle() {
|
||||
this.decoder!!.recycle()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue