Glideフレームガウスぼかし画像処理

8464 ワード

変換元:https://ligboy.org/?p=380
くだらないことを見る必要がない人には直接ショーをしてください.
ファジイ処理の場合、一般的な解決策は4つあります.
Java実現のアルゴリズム処理;
NDK実現のアルゴリズム処理;
RenderScript処理;
OpenGL処理;
この4つのシナリオの性能を考えると、一般的には1<3<2<4(2、3の性能は非常に近い)が、RenderScript方式が最も簡便である(明らかにプラットフォームは無関係である).
RenderScriptはAndroidがSDK 17から提供したプラットフォームに関係なく計算が密集しているスクリプトで、C 99構文スクリプトを使用して高性能な計算を実現することができますが、それは多くのインライン関数を含んでいます.その中には、今日使用されているScriptIntrinsicBlurが含まれています.これはガウスファジイ処理インライン関数で、一般的なシステムはシャドウの計算処理に使用されます.
前述のRenderScriptはSDK 17から導入されたものですが、AndroidチームはRenderScript support libraryを提供してくれました.Gradle-baseのプロジェクトでの導入も極めて簡単で、module buildだけが必要です.gradleは、次の11、12の2行を設定します.
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"
 
    defaultConfig {
        applicationId "org.ligboy.backsound"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        renderscriptTargetApi 20
        renderscriptSupportModeEnabled true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

次に、ScriptIntrinsicBlurについて簡単に説明します.これは便利ですが、欠点もあります.ファジイradiusは25.0 fを超えることはできませんが、原図サンプリングを縮小することで相を変えて半径を拡大することができます.
Glideは優れた画像ロードキャッシュ処理など一連の機能のフレームワークであり、優雅でグラデーションを使用し、拡張も容易であり、GlideはカスタムTransformation方式で画像を拡張する処理を提供している.
ここまで来るとTransformationをカスタマイズする方法で、詳細はここでは後述しませんが、Glide公式ドキュメント:Transformationを参照してください.特に、各Transformationには、処理後のピクチャをキャッシュする際のファイル名に使用されるString getId()のコールバックがあり、これにより、次回同じピクチャが同じTransformationを使用する場合、実際の処理を必要とせず、キャッシュファイルを直接読み出すことができるため、実装時のIDはすべての調整パラメータを同時に関連付ける必要がある.パラメータ変更のIDもそれに応じて変更する必要があります.次は私がカスタマイズしたBlurTransformationです
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.support.annotation.FloatRange;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.Element;
import android.support.v8.renderscript.RenderScript;
import android.support.v8.renderscript.ScriptIntrinsicBlur;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import com.bumptech.glide.request.target.Target;

/**
 * Georgia Blur Transformation
 * 

* @author Ligboy.Liu [email protected]. */ public class BlurTransformation extends BitmapTransformation { private static final String ID = "org.ligboy.glide.BlurTransformation"; public static final float DEFAULT_RADIUS = 25.0f; public static final float MAX_RADIUS = 25.0f; private static final float DEFAULT_SAMPLING = 1.0f; private Context mContext; private float mSampling = DEFAULT_SAMPLING; private float mRadius; private int mColor; public static class Builder { private Context mContext; private float mRadius = DEFAULT_RADIUS; private int mColor = Color.TRANSPARENT; public Builder(Context mContext) { this.mContext = mContext; } public float getRadius() { return mRadius; } public Builder setRadius(float radius) { mRadius = radius; return this; } public int getColor() { return mColor; } public Builder setColor(int color) { mColor = color; return this; } public BlurTransformation build() { return new BlurTransformation(mContext, mRadius, mColor); } } /** * * @param context Context * @param radius The blur's radius. * @param color The color filter for blurring. */ public BlurTransformation(Context context, @FloatRange(from = 0.0f) float radius, int color) { super(context); mContext = context; if (radius > MAX_RADIUS) { mSampling = radius / 25.0f; mRadius = MAX_RADIUS; } else { mRadius = radius; } mColor = color; } /** * * @param context Context * @param radius The blur's radius. */ public BlurTransformation(Context context, @FloatRange(from = 0.0f) float radius) { this(context, radius, Color.TRANSPARENT); } public BlurTransformation(Context context) { this(context, DEFAULT_RADIUS); } /** * Transforms the given {@link Bitmap} based on the given dimensions and returns the transformed * result. *

*

* The provided Bitmap, toTransform, should not be recycled or returned to the pool. Glide will automatically * recycle and/or reuse toTransform if the transformation returns a different Bitmap. Similarly implementations * should never recycle or return Bitmaps that are returned as the result of this method. Recycling or returning * the provided and/or the returned Bitmap to the pool will lead to a variety of runtime exceptions and drawing * errors. See #408 for an example. If the implementation obtains and discards intermediate Bitmaps, they may * safely be returned to the BitmapPool and/or recycled. *

* *

* outWidth and outHeight will never be {@link Target#SIZE_ORIGINAL}, this * class converts them to be the size of the Bitmap we're going to transform before calling this method. *

* * @param pool A {@link BitmapPool} that can be used to obtain and * return intermediate {@link Bitmap}s used in this transformation. For every * {@link Bitmap} obtained from the pool during this transformation, a * {@link Bitmap} must also be returned. * @param toTransform The {@link Bitmap} to transform. * @param outWidth The ideal width of the transformed bitmap (the transformed width does not need to match exactly). * @param outHeight The ideal height of the transformed bitmap (the transformed heightdoes not need to match */ @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { boolean needScaled = mSampling == DEFAULT_SAMPLING; int originWidth = toTransform.getWidth(); int originHeight = toTransform.getHeight(); int width, height; if (needScaled) { width = originWidth; height = originHeight; } else { width = (int) (originWidth / mSampling); height = (int) (originHeight / mSampling); } //find a re-use bitmap Bitmap bitmap = pool.get(width, height, Bitmap.Config.ARGB_8888); if (bitmap == null) { bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); } Canvas canvas = new Canvas(bitmap); if (mSampling != DEFAULT_SAMPLING) { canvas.scale(1 / mSampling, 1 / mSampling); } Paint paint = new Paint(); paint.setFlags(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG); PorterDuffColorFilter filter = new PorterDuffColorFilter(mColor, PorterDuff.Mode.SRC_ATOP); paint.setColorFilter(filter); canvas.drawBitmap(toTransform, 0, 0, paint); // TIPS: Glide will take care of returning our original Bitmap to the BitmapPool for us, // we needn't to recycle it. // toTransform.recycle(); *

* If this transformation does not affect the data that will be stored in cache, returning an empty string here * is acceptable. *

* * @return A string that uniquely identifies this transformation. */ @Override public String getId() { StringBuilder sb = new StringBuilder(ID); sb .append('-').append(mRadius) .append('-').append(mColor); return sb.toString(); } }

使用するのも簡単です.
Glide.with(MainActivity.this).load(imageFile.getUrl())
         .transform(new BlurTransformation(MainActivity.this, 100))
         .crossFade()
         .into(mBackgroundImageView);

Gist:  https://gist.github.com/ligboy/eee784aa57f40a615179