381 lines
15 KiB
Kotlin
381 lines
15 KiB
Kotlin
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"
|
||
}
|
||
}
|