package com.ydl.media.audio.utils import android.graphics.* import com.bumptech.glide.Glide import com.bumptech.glide.load.DecodeFormat import com.bumptech.glide.load.resource.bitmap.CircleCrop import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.target.SimpleTarget import com.bumptech.glide.request.transition.Transition import com.ydl.ydlcommon.base.BaseApp /** * Created by haorui on 2019-10-27 . * Des: */ object CoverImageUtils { private val BLUR_RADIUS = 50 fun blur(source: Bitmap?): Bitmap? { if (source == null) { return null } try { return blur(source, BLUR_RADIUS) } catch (e: Exception) { e.printStackTrace() return source } } /** * Stack Blur v1.0 from * http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html * * * Java Author: Mario Klingemann <mario at quasimondo.com> * http://incubator.quasimondo.com * created Feburary 29, 2004 * Android port : Yahel Bouaziz <yahel at kayenko.com> * http://www.kayenko.com * ported april 5th, 2012 </yahel></mario> * * * This is a compromise between Gaussian Blur and Box blur * It creates much better looking blurs than Box Blur, but is * 7x faster than my Gaussian Blur implementation. * * * I called it Stack Blur because this describes best how this * filter works internally: it creates a kind of moving stack * of colors whilst scanning through the image. Thereby it * just has to add one new block of color to the right side * of the stack and remove the leftmost color. The remaining * colors on the topmost layer of the stack are either added on * or reduced by one, depending on if they are on the right or * on the left side of the stack. * * * If you are using this algorithm in your code please add * the following line: * * * Stack Blur Algorithm by Mario Klingemann <mario></mario>@quasimondo.com> */ private fun blur(source: Bitmap, radius: Int): Bitmap? { val bitmap = source.copy(source.config, true) if (radius < 1) { return null } val w = bitmap.width val h = bitmap.height val pix = IntArray(w * h) bitmap.getPixels(pix, 0, w, 0, 0, w, h) val wm = w - 1 val hm = h - 1 val wh = w * h val div = radius + radius + 1 val r = IntArray(wh) val g = IntArray(wh) val b = IntArray(wh) var rSum: Int var gSum: Int var bSum: Int var x: Int var y: Int var i: Int var p: Int var yp: Int var yi: Int var yw: Int val vMin = IntArray(Math.max(w, h)) var divSum = div + 1 shr 1 divSum *= divSum val dv = IntArray(256 * divSum) i = 0 while (i < 256 * divSum) { dv[i] = i / divSum i++ } yi = 0 yw = yi val stack = Array(div) { IntArray(3) } var stackPointer: Int var stackStart: Int var sir: IntArray var rbs: Int val r1 = radius + 1 var rOutSum: Int var gOutSum: Int var bOutSum: Int var rInSum: Int var gInSum: Int var bInSum: Int y = 0 while (y < h) { bSum = 0 gSum = bSum rSum = gSum bOutSum = rSum gOutSum = bOutSum rOutSum = gOutSum bInSum = rOutSum gInSum = bInSum rInSum = gInSum i = -radius while (i <= radius) { p = pix[yi + Math.min(wm, Math.max(i, 0))] sir = stack[i + radius] sir[0] = p and 0xff0000 shr 16 sir[1] = p and 0x00ff00 shr 8 sir[2] = p and 0x0000ff rbs = r1 - Math.abs(i) rSum += sir[0] * rbs gSum += sir[1] * rbs bSum += sir[2] * rbs if (i > 0) { rInSum += sir[0] gInSum += sir[1] bInSum += sir[2] } else { rOutSum += sir[0] gOutSum += sir[1] bOutSum += sir[2] } i++ } stackPointer = radius x = 0 while (x < w) { r[yi] = dv[rSum] g[yi] = dv[gSum] b[yi] = dv[bSum] rSum -= rOutSum gSum -= gOutSum bSum -= bOutSum stackStart = stackPointer - radius + div sir = stack[stackStart % div] rOutSum -= sir[0] gOutSum -= sir[1] bOutSum -= sir[2] if (y == 0) { vMin[x] = Math.min(x + radius + 1, wm) } p = pix[yw + vMin[x]] sir[0] = p and 0xff0000 shr 16 sir[1] = p and 0x00ff00 shr 8 sir[2] = p and 0x0000ff rInSum += sir[0] gInSum += sir[1] bInSum += sir[2] rSum += rInSum gSum += gInSum bSum += bInSum stackPointer = (stackPointer + 1) % div sir = stack[stackPointer % div] rOutSum += sir[0] gOutSum += sir[1] bOutSum += sir[2] rInSum -= sir[0] gInSum -= sir[1] bInSum -= sir[2] yi++ x++ } yw += w y++ } x = 0 while (x < w) { bSum = 0 gSum = bSum rSum = gSum bOutSum = rSum gOutSum = bOutSum rOutSum = gOutSum bInSum = rOutSum gInSum = bInSum rInSum = gInSum yp = -radius * w i = -radius while (i <= radius) { yi = Math.max(0, yp) + x sir = stack[i + radius] sir[0] = r[yi] sir[1] = g[yi] sir[2] = b[yi] rbs = r1 - Math.abs(i) rSum += r[yi] * rbs gSum += g[yi] * rbs bSum += b[yi] * rbs if (i > 0) { rInSum += sir[0] gInSum += sir[1] bInSum += sir[2] } else { rOutSum += sir[0] gOutSum += sir[1] bOutSum += sir[2] } if (i < hm) { yp += w } i++ } yi = x stackPointer = radius y = 0 while (y < h) { // Preserve alpha channel: ( 0xff000000 & pix[yi] ) pix[yi] = -0x1000000 and pix[yi] or (dv[rSum] shl 16) or (dv[gSum] shl 8) or dv[bSum] rSum -= rOutSum gSum -= gOutSum bSum -= bOutSum stackStart = stackPointer - radius + div sir = stack[stackStart % div] rOutSum -= sir[0] gOutSum -= sir[1] bOutSum -= sir[2] if (x == 0) { vMin[y] = Math.min(y + r1, hm) * w } p = x + vMin[y] sir[0] = r[p] sir[1] = g[p] sir[2] = b[p] rInSum += sir[0] gInSum += sir[1] bInSum += sir[2] rSum += rInSum gSum += gInSum bSum += bInSum stackPointer = (stackPointer + 1) % div sir = stack[stackPointer] rOutSum += sir[0] gOutSum += sir[1] bOutSum += sir[2] rInSum -= sir[0] gInSum -= sir[1] bInSum -= sir[2] yi += w y++ } x++ } bitmap.setPixels(pix, 0, w, 0, 0, w, h) return bitmap } /** * 将图片放大或缩小到指定尺寸 */ fun resizeImage(source: Bitmap?, dstWidth: Int, dstHeight: Int): Bitmap? { if (source == null) { return null } return if (source.width == dstWidth && source.height == dstHeight) { source } else Bitmap.createScaledBitmap(source, dstWidth, dstHeight, true) } /** * 将图片剪裁为圆形 */ fun createCircleImage(source: Bitmap?): Bitmap? { if (source == null) { return null } val length = Math.min(source.width, source.height) val paint = Paint() paint.isAntiAlias = true val target = Bitmap.createBitmap(length, length, Bitmap.Config.ARGB_8888) val canvas = Canvas(target) canvas.drawCircle( (source.width / 2).toFloat(), (source.height / 2).toFloat(), (length / 2).toFloat(), paint ) paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) canvas.drawBitmap(source, 0f, 0f, paint) return target } fun loadThumb(url: String,onCoverLoadListener: OnCoverLoadListener) { Glide.with(BaseApp.getApp()).asBitmap() .load(url).into(object : SimpleTarget<Bitmap>() { override fun onResourceReady(resource: Bitmap?, transition: Transition<in Bitmap>?) { onCoverLoadListener.onComplete(resource!!) } }) } fun loadRound(url: String,onCoverLoadListener: OnCoverLoadListener){ Glide.with(BaseApp.getApp()).asBitmap() .apply( RequestOptions.bitmapTransform( CircleCrop() )).load(url).into(object : SimpleTarget<Bitmap>() { override fun onResourceReady(resource: Bitmap?, transition: Transition<in Bitmap>?) { onCoverLoadListener.onComplete(resource!!) } }) } fun loadBlur(url: String,onCoverLoadListener: OnCoverLoadListener){ val disallowHardwareConfig = RequestOptions().format(DecodeFormat.PREFER_RGB_565).disallowHardwareConfig() Glide.with(BaseApp.getApp()).asBitmap().apply(disallowHardwareConfig).load(url).into(object : SimpleTarget<Bitmap>() { override fun onResourceReady(resource: Bitmap?, transition: Transition<in Bitmap>?) { onCoverLoadListener.onComplete(CoverImageUtils.blur(resource)!!) } }) } interface OnCoverLoadListener { fun onComplete(bitmap: Bitmap) } }