diff --git a/doric-android/doric/build.gradle b/doric-android/doric/build.gradle index ab7a034c..8e5dbc86 100644 --- a/doric-android/doric/build.gradle +++ b/doric-android/doric/build.gradle @@ -11,9 +11,6 @@ android { versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - - renderscriptTargetApi 18 - renderscriptSupportModeEnabled true } buildTypes { @@ -28,11 +25,6 @@ android { assets.srcDirs = ["../../doric-js/bundle"] } } - packagingOptions { - exclude 'lib/*/libRSSupport.so' - exclude 'lib/*/librsjni.so' - exclude 'lib/*/librsjni_androidx.so' - } } dependencies { @@ -42,11 +34,10 @@ dependencies { api 'com.github.penfeizhou:jsc4a:0.2.5' //api "pub.doric:jse:${rootProject.ext.Version}" implementation 'com.squareup.okhttp3:okhttp:3.12.1' - implementation('com.github.penfeizhou.android.animation:glide-plugin:2.13.0') { + implementation('com.github.penfeizhou.android.animation:glide-plugin:2.17.0') { exclude group: 'com.github.bumptech.glide' } implementation 'com.github.bumptech.glide:glide:4.11.0' - implementation 'jp.wasabeef:glide-transformations:4.1.0' implementation "com.google.android.material:material:1.2.1" def nav_version = "2.3.0" diff --git a/doric-android/doric/src/main/java/pub/doric/shader/AeroEffectView.java b/doric-android/doric/src/main/java/pub/doric/shader/AeroEffectView.java index d7eb3213..bb41d23f 100644 --- a/doric-android/doric/src/main/java/pub/doric/shader/AeroEffectView.java +++ b/doric-android/doric/src/main/java/pub/doric/shader/AeroEffectView.java @@ -19,14 +19,13 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.Rect; -import android.os.Build; import androidx.annotation.NonNull; -import jp.wasabeef.glide.transformations.internal.FastBlur; -import jp.wasabeef.glide.transformations.internal.RSBlur; -import jp.wasabeef.glide.transformations.internal.SupportRSBlur; +import pub.doric.utils.DoricUtils; /** * @Description: This could blur what's contained. @@ -42,6 +41,9 @@ public class AeroEffectView extends DoricLayer { private Canvas mRectCanvas = null; private Rect mDstRect = null; + private Bitmap mScaledBitmap = null; + private Canvas mScaledCanvas = null; + public AeroEffectView(@NonNull Context context) { super(context); } @@ -78,29 +80,34 @@ public class AeroEffectView extends DoricLayer { } Bitmap blurredBitmap; int radius = 15; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - try { - blurredBitmap = SupportRSBlur.blur(getContext(), blurringBitmap, radius); - } catch (NoClassDefFoundError e) { - try { - blurredBitmap = RSBlur.blur(getContext(), blurringBitmap, radius); - } catch (Exception ee) { - blurredBitmap = FastBlur.blur(blurringBitmap, radius, true); - } - } catch (Exception e) { - blurredBitmap = FastBlur.blur(blurringBitmap, radius, true); - } + float scale = Math.max(blurringBitmap.getWidth() / 50f, blurringBitmap.getHeight() / 50f); + int scaledWidth = (int) (blurringBitmap.getWidth() / scale); + int scaledHeight = (int) (blurringBitmap.getHeight() / scale); + if (mScaledBitmap == null + || mScaledBitmap.getWidth() != scaledWidth + || mScaledBitmap.getHeight() != scaledHeight) { + mScaledBitmap = Bitmap.createScaledBitmap(blurringBitmap, scaledWidth, scaledHeight, true); + mScaledCanvas = new Canvas(mScaledBitmap); } else { - blurredBitmap = FastBlur.blur(blurringBitmap, radius, true); + mScaledCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + Matrix matrix = new Matrix(); + matrix.setScale(1 / scale, 1 / scale); + mScaledCanvas.drawBitmap(blurringBitmap, matrix, null); } - Bitmap retBitmap; + blurredBitmap = DoricUtils.blur(getContext(), mScaledBitmap, radius); if (mEffectiveRect != null) { - mFullCanvas.drawBitmap(blurredBitmap, mDstRect, mEffectiveRect, null); - retBitmap = mFullBitmap; + mFullCanvas.drawBitmap(blurredBitmap, + new Rect(0, 0, blurredBitmap.getWidth(), blurredBitmap.getHeight()), + mEffectiveRect, + null); } else { - retBitmap = blurredBitmap; + Paint paint = new Paint(); + paint.setAntiAlias(true); + mFullCanvas.drawBitmap(blurredBitmap, + new Rect(0, 0, blurredBitmap.getWidth(), blurredBitmap.getHeight()), + new Rect(0, 0, mFullBitmap.getWidth(), mFullBitmap.getHeight()), + paint); } - - canvas.drawBitmap(retBitmap, 0, 0, null); + canvas.drawBitmap(mFullBitmap, 0, 0, null); } } diff --git a/doric-android/doric/src/main/java/pub/doric/shader/BlurEffectView.java b/doric-android/doric/src/main/java/pub/doric/shader/BlurEffectView.java index f84741a2..98f8fb3b 100644 --- a/doric-android/doric/src/main/java/pub/doric/shader/BlurEffectView.java +++ b/doric-android/doric/src/main/java/pub/doric/shader/BlurEffectView.java @@ -21,12 +21,9 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.Rect; -import android.os.Build; import androidx.annotation.NonNull; -import jp.wasabeef.glide.transformations.internal.FastBlur; -import jp.wasabeef.glide.transformations.internal.RSBlur; -import jp.wasabeef.glide.transformations.internal.SupportRSBlur; +import pub.doric.utils.DoricUtils; /** * @Description: This could blur what's contained. @@ -86,23 +83,7 @@ public class BlurEffectView extends DoricLayer { } else { blurringBitmap = mFullBitmap; } - Bitmap blurredBitmap; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 - && mRadius <= 25) { - try { - blurredBitmap = SupportRSBlur.blur(getContext(), blurringBitmap, mRadius); - } catch (NoClassDefFoundError e) { - try { - blurredBitmap = RSBlur.blur(getContext(), blurringBitmap, mRadius); - } catch (Exception ee) { - blurredBitmap = FastBlur.blur(blurringBitmap, mRadius, true); - } - } catch (Exception e) { - blurredBitmap = FastBlur.blur(blurringBitmap, mRadius, true); - } - } else { - blurredBitmap = FastBlur.blur(blurringBitmap, mRadius, true); - } + Bitmap blurredBitmap = DoricUtils.blur(getContext(), blurringBitmap, mRadius); Bitmap retBitmap; if (mEffectiveRect != null) { mFullCanvas.drawBitmap(blurredBitmap, mDstRect, mEffectiveRect, null); diff --git a/doric-android/doric/src/main/java/pub/doric/shader/ImageNode.java b/doric-android/doric/src/main/java/pub/doric/shader/ImageNode.java index 6fb54456..d4c9a84e 100644 --- a/doric-android/doric/src/main/java/pub/doric/shader/ImageNode.java +++ b/doric-android/doric/src/main/java/pub/doric/shader/ImageNode.java @@ -20,8 +20,10 @@ import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Animatable; import android.graphics.drawable.BitmapDrawable; @@ -42,6 +44,8 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.DrawableImageViewTarget; @@ -54,8 +58,8 @@ import com.github.pengfeizhou.jscore.JSValue; import java.io.File; import java.io.InputStream; +import java.security.MessageDigest; -import jp.wasabeef.glide.transformations.BlurTransformation; import pub.doric.DoricContext; import pub.doric.async.AsyncResult; import pub.doric.extension.bridge.DoricMethod; @@ -254,7 +258,29 @@ public class ImageNode extends ViewNode { if (isBlur) { requestBuilder = requestBuilder .apply(RequestOptions - .bitmapTransform(new BlurTransformation(25, 3))); + .bitmapTransform(new BitmapTransformation() { + @Override + protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { + int width = toTransform.getWidth(); + int height = toTransform.getHeight(); + int sampling = 3; + int scaledWidth = width / sampling; + int scaledHeight = height / sampling; + Bitmap bitmap = pool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888); + bitmap.setDensity(toTransform.getDensity()); + Canvas canvas = new Canvas(bitmap); + canvas.scale(1 / (float) sampling, 1 / (float) sampling); + Paint paint = new Paint(); + paint.setFlags(Paint.FILTER_BITMAP_FLAG); + canvas.drawBitmap(toTransform, 0, 0, paint); + return DoricUtils.blur(getContext(), bitmap, 25); + } + + @Override + public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { + messageDigest.update(("DoricBlurTransform").getBytes(CHARSET)); + } + })); } Drawable placeHolderDrawable = getPlaceHolderDrawable(); diff --git a/doric-android/doric/src/main/java/pub/doric/utils/DoricUtils.java b/doric-android/doric/src/main/java/pub/doric/utils/DoricUtils.java index 2091229f..6354693a 100644 --- a/doric-android/doric/src/main/java/pub/doric/utils/DoricUtils.java +++ b/doric-android/doric/src/main/java/pub/doric/utils/DoricUtils.java @@ -21,9 +21,15 @@ import android.content.ContextWrapper; import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; import android.os.Build; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RSRuntimeException; +import android.renderscript.RenderScript; +import android.renderscript.ScriptIntrinsicBlur; import android.util.DisplayMetrics; import android.util.Pair; import android.view.Display; @@ -356,4 +362,293 @@ public class DoricUtils { } return show; } + + + @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) + public static Bitmap rsBlur(Context context, Bitmap bitmap, int radius) throws RSRuntimeException { + RenderScript rs = null; + Allocation input = null; + Allocation output = null; + ScriptIntrinsicBlur blur = null; + try { + rs = RenderScript.create(context); + rs.setMessageHandler(new RenderScript.RSMessageHandler()); + input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE, + Allocation.USAGE_SCRIPT); + output = Allocation.createTyped(rs, input.getType()); + blur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); + + blur.setInput(input); + blur.setRadius(radius); + blur.forEach(output); + output.copyTo(bitmap); + } finally { + if (rs != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + RenderScript.releaseAllContexts(); + } else { + rs.destroy(); + } + } + if (input != null) { + input.destroy(); + } + if (output != null) { + output.destroy(); + } + if (blur != null) { + blur.destroy(); + } + } + + return bitmap; + } + + public static Bitmap fastBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) { + + // Stack Blur v1.0 from + // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html + // + // Java Author: Mario Klingemann + // http://incubator.quasimondo.com + // created Feburary 29, 2004 + // Android port : Yahel Bouaziz + // http://www.kayenko.com + // ported april 5th, 2012 + + // 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 + + Bitmap bitmap; + if (canReuseInBitmap) { + bitmap = sentBitmap; + } else { + bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); + } + + if (radius < 1) { + return (null); + } + + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + int[] pix = new int[w * h]; + bitmap.getPixels(pix, 0, w, 0, 0, w, h); + + int wm = w - 1; + int hm = h - 1; + int wh = w * h; + int div = radius + radius + 1; + + int[] r = new int[wh]; + int[] g = new int[wh]; + int[] b = new int[wh]; + int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; + int[] vmin = new int[Math.max(w, h)]; + + int divsum = (div + 1) >> 1; + divsum *= divsum; + int[] dv = new int[256 * divsum]; + for (i = 0; i < 256 * divsum; i++) { + dv[i] = (i / divsum); + } + + yw = yi = 0; + + int[][] stack = new int[div][3]; + int stackpointer; + int stackstart; + int[] sir; + int rbs; + int r1 = radius + 1; + int routsum, goutsum, boutsum; + int rinsum, ginsum, binsum; + + for (y = 0; y < h; y++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + for (i = -radius; i <= radius; i++) { + p = pix[yi + Math.min(wm, Math.max(i, 0))]; + sir = stack[i + radius]; + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 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]; + } + } + stackpointer = radius; + + for (x = 0; x < w; x++) { + + 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 & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 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++; + } + yw += w; + } + for (x = 0; x < w; x++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + yp = -radius * w; + for (i = -radius; i <= radius; i++) { + 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; + } + } + yi = x; + stackpointer = radius; + for (y = 0; y < h; y++) { + // Preserve alpha channel: ( 0xff000000 & pix[yi] ) + pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | 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; + } + } + bitmap.setPixels(pix, 0, w, 0, 0, w, h); + return (bitmap); + } + + public static Bitmap blur(Context context, Bitmap inBitmap, int radius) { + Bitmap bitmap; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 + && radius <= 25) { + try { + bitmap = rsBlur(context, inBitmap, radius); + } catch (Exception e) { + bitmap = fastBlur(inBitmap, radius, true); + } + } else { + bitmap = fastBlur(inBitmap, radius, true); + } + return bitmap; + } }