Files
assistant-android/app/src/main/java/com/gh/common/util/ImageUtils.kt

381 lines
15 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.gh.common.util
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.drawable.Animatable
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.controller.ControllerListener
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.image.ImageInfo
import com.facebook.imagepipeline.request.ImageRequest
import com.gh.common.constant.Config
import com.gh.gamecenter.R
import com.halo.assistant.HaloApp
import com.squareup.picasso.Picasso
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.io.ByteArrayOutputStream
object ImageUtils {
private const val PIC_MAX_FILE_SIZE: Long = 10 * 1024 * 1024
private val TINY_GIF_SIZE = 30F.dip2px()
private val LARGE_GIF_SIZE = 80F.dip2px()
private val STANDARD_GIF_SIZE = 60F.dip2px()
@JvmStatic
fun getUploadFileMaxSize(): Long {
val uploadLimitSize = Config.getSettings()?.image?.uploadLimitSize
if (uploadLimitSize != null) {
return uploadLimitSize
}
return PIC_MAX_FILE_SIZE
}
@JvmStatic
fun getDefaultGifRule(): String? {
val gifConfig = Config.getSettings()?.image?.oss?.gif
if (gifConfig != null) {
return gifConfig
}
return ""
}
@JvmStatic
fun getWatermarkWidthGifRule(width: Int?): String? {
val gifConfig = Config.getSettings()?.image?.oss?.gitThumb
val gifWaterMark = Config.getSettings()?.image?.oss?.gifWaterMark
if (gifConfig != null && gifWaterMark != null) {
return "$gifConfig,w_$width$gifWaterMark"
}
return ""
}
@JvmStatic
fun getLimitWidthRule(width: Int?): String? {
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
if (jpegConfig != null) {
return "$jpegConfig,w_$width"
}
return ""
}
@JvmStatic
fun addLimitWidth(imageUrl: String?, width: Int?): String? {
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
if (jpegConfig != null) {
return "$imageUrl$jpegConfig,w_$width"
}
return imageUrl
}
@JvmStatic
fun addLimitHeight(imageUrl: String, height: Int): String {
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
if (jpegConfig != null) {
return "$imageUrl$jpegConfig,h_$height"
}
return imageUrl
}
@JvmStatic
fun addLimitWidthAndHeight(imageUrl: String, width: Int, height: Int): String {
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
if (jpegConfig != null) {
return "$imageUrl$jpegConfig,w_$width,h_$height"
}
return imageUrl
}
@JvmStatic
fun getGitStaticImage(imageUrl: String): String {
val gifThumb = Config.getSettings()?.image?.oss?.gitThumb
if (gifThumb != null) {
return "$imageUrl$gifThumb"
}
return imageUrl
}
@JvmStatic
fun addLimitWidthAndLoad(draweeView: SimpleDraweeView?, imageUrl: String, width: Int) {
val newUrl = addLimitWidth(imageUrl, width)
draweeView?.setImageURI(newUrl)
}
@JvmStatic
fun addLimitWidthAndLoad(draweeView: SimpleDraweeView?, imageUrl: String?, width: Int?, onLoadListener: OnImageloadListener?) {
val newUrl = getTransformLimitUrl(imageUrl, width, draweeView?.context)
val listener = object : BaseControllerListener<ImageInfo>() {
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
onLoadListener?.onLoadFinal(imageInfo)
}
}
draweeView?.controller = Fresco.newDraweeControllerBuilder()
.setUri(newUrl)
.setControllerListener(listener)
.build()
}
fun display(simpleDraweeView: SimpleDraweeView?, url: String?, width: Int?, listener: BaseControllerListener<ImageInfo>) {
simpleDraweeView?.controller = Fresco.newDraweeControllerBuilder()
.setUri(getTransformLimitUrl(url, width, simpleDraweeView?.context))
.setControllerListener(listener)
.build()
}
// 自适应图片宽高
@JvmStatic
fun display(simpleDraweeView: SimpleDraweeView?, url: String?, width: Int) {
val listener = object : BaseControllerListener<ImageInfo>() {
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
if (imageInfo == null) {
return
}
val layoutParams = simpleDraweeView?.layoutParams
val scale = imageInfo.height.toFloat() / imageInfo.width.toFloat()
layoutParams?.height = (width * scale).toInt()
simpleDraweeView?.layoutParams = layoutParams
}
}
simpleDraweeView?.controller = Fresco.newDraweeControllerBuilder()
.setControllerListener(listener)
.setUri(getTransformLimitUrl(url, width, simpleDraweeView?.context))
.build()
}
// 自适应图片宽高
@JvmStatic
fun displayScale(simpleDraweeView: SimpleDraweeView?, url: String?, height: Int) {
val listener = object : BaseControllerListener<ImageInfo>() {
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
if (imageInfo == null) {
return
}
val layoutParams = simpleDraweeView?.layoutParams
val scale = imageInfo.width.toFloat() / imageInfo.height.toFloat()
layoutParams?.width = (height * scale).toInt()
simpleDraweeView?.layoutParams = layoutParams
}
}
simpleDraweeView?.controller = Fresco.newDraweeControllerBuilder()
.setUri(url)
.setControllerListener(listener)
.build()
}
// 设置缩放类型,设置按压状态下的叠加图
@JvmStatic
fun display(resources: Resources?, simpleDraweeView: SimpleDraweeView?, width: Int,
scaleType: ScalingUtils.ScaleType?, url: String?) {
if (simpleDraweeView == null) return
val context = simpleDraweeView.context ?: return
simpleDraweeView.hierarchy = GenericDraweeHierarchyBuilder(resources)
.setFadeDuration(500)
.setPressedStateOverlay(ColorDrawable(ContextCompat.getColor(context, R.color.pressed_bg)))
.setPlaceholderImage(R.drawable.occupy2, ScalingUtils.ScaleType.CENTER)
.setBackground(ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
.setActualImageScaleType(scaleType)
.build()
simpleDraweeView.setImageURI(getTransformLimitUrl(url, width, context))
}
// 设置占位符
@JvmStatic
fun display(resources: Resources?, simpleDraweeView: SimpleDraweeView?, url: String?, placeholderImage: Int) {
if (simpleDraweeView == null) return
val context = simpleDraweeView.context ?: return
simpleDraweeView.hierarchy = GenericDraweeHierarchyBuilder(resources)
.setFadeDuration(500)
.setPressedStateOverlay(ColorDrawable(ContextCompat.getColor(context, R.color.pressed_bg)))
.setBackground(ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
.setPlaceholderImage(placeholderImage)
.build()
display(simpleDraweeView, url)
}
// 图片下载监听和设置低高分辨率图片
fun display(simpleDraweeView: SimpleDraweeView?, url: String?, lowUrl: String?,
listener: ControllerListener<in ImageInfo>) {
simpleDraweeView?.controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(ImageRequest.fromUri(url))
.setControllerListener(listener)
.setLowResImageRequest(ImageRequest.fromUri(lowUrl)) // 低分辨率图片
.build()
}
// 获取bitmap (使用 fresco 获取 gif bitmap 会为空https://github.com/facebook/fresco/issues/241)
// 所以这里换用 picasso
@SuppressLint("CheckResult")
@JvmStatic
fun getBitmap(url: String, callback: BiCallback<Bitmap, Boolean>) {
Single.just(url)
.map { Picasso.with(HaloApp.getInstance().application).load(url).priority(Picasso.Priority.HIGH).get() }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
callback.onFirst(it)
}, {
callback.onSecond(true)
it.printStackTrace()
})
}
/**
* 规则 width>0 Wifi/4G:x2 traffic:x1
* 第一种方案:通过LayoutParams获取 可以快速(无延迟)获取宽高,但是无法获取wrap_content和match_parent的View
* 第二种方案(备用方案):有延迟,View的宽高需要在Measure过程后才能确定,能够在这里获取到正确的宽高
*/
@JvmStatic
fun display(view: SimpleDraweeView?, url: String?) {
url?.let {
// 图片是以 gif 结尾的就
if (it.endsWith(".gif") && view?.getTag(R.id.tag_show_gif) != false) {
if (view?.tag == url) return@let
val width = view?.layoutParams?.width
val height = view?.layoutParams?.height
if (width != null && width > 0) {
val controller = Fresco.newDraweeControllerBuilder()
.setUri(resizeGif(url, width, height ?: 0))
.setAutoPlayAnimations(true)
.build()
view.controller = controller
} else {
view?.post {
val controller = Fresco.newDraweeControllerBuilder()
.setUri(resizeGif(url, view.width, view.height))
.setAutoPlayAnimations(true)
.build()
view.controller = controller
}
}
} else {
val width = view?.layoutParams?.width
if (width != null && width > 0) {
view.setImageURI(getTransformLimitUrl(url, width, view.context))
} else {
view?.post {
view.setImageURI(getTransformLimitUrl(url, view.width, view.context))
}
}
}
view?.tag = url
}
}
// Wifi/4G:x2 traffic:x1
@JvmStatic
fun getTransformLimitUrl(url: String?, width: Int?, context: Context?): String? {
var transformUrl: String? = url
if (width != null && width > 0) {
val transformUrlX2 = addLimitWidth(url, width * 2)
val transformUrlX1 = addLimitWidth(url, width)
// 当网络为 WIFI 或 4G 且系统版本大于 5.0 && 手机内存大于 1G 才用高清图片
if (NetworkUtils.isWifiOr4GConnected(context)
&& Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP
&& DeviceUtils.getTotalRamSizeOfDevice(context) > 1000) {
transformUrl = transformUrlX2
} else {
// 检查X2大图是否被缓存
if (Fresco.getImagePipeline().isInBitmapMemoryCache(Uri.parse(transformUrlX2)) ||
Fresco.getImagePipeline().isInDiskCacheSync(Uri.parse(transformUrlX2))) {
transformUrl = transformUrlX2
} else {
transformUrl = transformUrlX1
}
}
}
// Utils.log("displayPost::viewWidth->$width----transformUrl->$transformUrl")
return transformUrl
}
// 规则 width>0 Wifi/4G:x2 traffic:x2
@JvmStatic
fun displayIcon(view: SimpleDraweeView?, url: String?) {
val width = view?.layoutParams?.width
if (width != null && width > 0) {
view.setImageURI(addLimitWidth(url, width * 2))
// Utils.log("displayIcon::viewWidth->" + view.width + "---transformUrl->" + transformUrl)
} else {
view?.post {
view.setImageURI(addLimitWidth(url, view.width * 2))
// Utils.log("displayIcon::viewWidth->" + view.width + "---transformUrl->" + transformUrl)
}
}
}
@JvmStatic
fun bmpToByteArray(bmp: Bitmap, needRecycle: Boolean): ByteArray {
val output = ByteArrayOutputStream()
bmp.compress(Bitmap.CompressFormat.PNG, 100, output)
if (needRecycle) {
bmp.recycle()
}
val result = output.toByteArray()
try {
output.close()
} catch (e: Exception) {
e.printStackTrace()
}
return result
}
@JvmStatic
fun display(draweeView: SimpleDraweeView, @DrawableRes res: Int?) {
draweeView.setImageURI("res:///" + res)
}
//预加载图片
@JvmStatic
fun prefetchToDiskCache(url: String) {
val imagePipeline = Fresco.getImagePipeline()
val imageRequest = ImageRequest.fromUri(url)
imagePipeline.prefetchToDiskCache(imageRequest, HaloApp.getInstance().application)
}
private fun resizeGif(url: String, width: Int, height: Int): String {
val idealSize = getIdealGifSize(width, height)
return "$url?x-oss-process=image/resize,h_$idealSize,w_$idealSize"
}
private fun getIdealGifSize(width: Int, height: Int): String {
return if (width > LARGE_GIF_SIZE || height > LARGE_GIF_SIZE) {
"256"
} else if (width >= STANDARD_GIF_SIZE || height >= STANDARD_GIF_SIZE) {
"192"
} else if (width > TINY_GIF_SIZE || height > TINY_GIF_SIZE) {
"128"
} else {
"64"
}
}
public interface OnImageloadListener {
fun onLoadFinal(imageInfo: ImageInfo?)
}
fun getVideoSnapshot(videoUrl: String, progress: Long): String {
return "$videoUrl?x-oss-process=video/snapshot,t_$progress,f_jpg,w_0,h_0"
}
}