Sök…


Introduktion

RenderScript är ett skriptspråk som låter dig skriva högpresterande grafisk rendering och rå datakod. Det tillhandahåller ett sätt att skriva prestanda kritisk kod som systemet senare sammanställer till inbyggd kod för processorn som det kan köras på. Detta kan vara CPU, en flerkärnig CPU eller till och med GPU. Vilket den slutligen kör på beror på många faktorer som inte är lättillgängliga för utvecklaren, men beror också på vilken arkitektur den interna plattformskompilatorn stöder.

Komma igång

RenderScript är ett ramverk som tillåter högpresterande parallellberäkning på Android. Skript som du skriver kommer att köras över alla tillgängliga processorer (t.ex. CPU, GPU etc) parallellt så att du kan fokusera på den uppgift du vill utföra istället för hur den schemaläggs och körs.

Skript skrivs på ett C99-baserat språk (C99 är en gammal version av C-programmeringsspråkstandarden). För varje skript skapas en Java-klass som gör att du enkelt kan interagera med RenderScript i din Java-kod.

Ställa in ditt projekt

Det finns två olika sätt att komma åt RenderScript i din app, med Android Framework-biblioteken eller Support Library. Även om du inte vill rikta in sig på enheter före API-nivå 11 bör du alltid använda Support Library-implementeringen eftersom det garanterar enhetskompatibilitet på många olika enheter. För att kunna använda supportbibliotekets implementering måste du åtminstone använda verktyg för att bygga version 18.1.0 !

Låter nu konfigurera build.gradle-filen för din applikation:

android {
    compileSdkVersion 24
    buildToolsVersion '24.0.1'

    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 24

        renderscriptTargetApi 18
        renderscriptSupportModeEnabled true
    }
}
  • renderscriptTargetApi : Detta bör ställas in på den version av den tidigaste API-nivån som ger all RenderScript-funktionalitet du behöver.
  • renderscriptSupportModeEnabled : Detta möjliggör användning av Support Library RenderScript-implementering.

Hur RenderScript fungerar

Ett typiskt RenderScript består av två saker: kärnor och funktioner. En funktion är precis som den låter som - den accepterar en ingång, gör något med den ingången och returnerar en utgång. En Kernel är där den verkliga kraften i RenderScript kommer från.

En kärna är en funktion som körs mot varje element i en Allocation . En Allocation kan användas för att skicka data som en Bitmap eller en byte matris till ett RenderScript och de används också för att få ett resultat från en kärna. Kärnor kan antingen ta en Allocation som inmatning och en annan som utgång eller så kan de ändra data inuti en Allocation .

Du kan skriva dina ena kärnor, men det finns också många fördefinierade kärnor som du kan använda för att utföra vanliga operationer som en gaussisk bildsuddighet.

Som redan nämnts för varje RenderScript-fil genereras en klass för att interagera med den. Dessa klasser börjar alltid med prefixet ScriptC_ följt av namnet på RenderScript-filen. Om din RenderScript-fil till example kallas example kommer den genererade Java-klassen att kallas ScriptC_example . Alla fördefinierade skript börjar bara med prefixet Script - till exempel kallas ScriptIntrinsicBlur Gaussian Image Blur för ScriptIntrinsicBlur .

Skriva ditt första RenderScript

Följande exempel är baserat på ett exempel på GitHub. Den utför grundläggande bildmanipulation genom att modifiera en bilds mättnad. Du kan hitta källkoden här och kolla in den om du vill leka med den själv. Här är en snabb gif av hur resultatet ska se ut:

demobild

RenderScript-pannplatta

RenderScript-filer finns i mappen src/main/rs i ditt projekt. Varje fil har filändelsen .rs och måste innehålla två #pragma uttalanden högst upp:

#pragma version(1)
#pragma rs java_package_name(your.package.name)
  • #pragma version(1) : Detta kan användas för att ställa in den version av RenderScript du använder. För närvarande finns det bara version 1.

  • #pragma rs java_package_name(your.package.name) : Detta kan användas för att ställa in paketnamnet på Java-klassen som genererats för att interagera med just detta RenderScript.

Det finns ett annat #pragma du vanligtvis ska ställa in i var och en av dina RenderScript-filer och det används för att ställa in flytpunktens precision. Du kan ställa in flytpunktens precision på tre olika nivåer:

  • #pragma rs_fp_full : Detta är den striktaste inställningen med högsta precision och det är också standardvärdet om du inte anger något. Du bör använda detta om du behöver hög flytpunktsprecision.
  • #pragma rs_fp_relaxed : Detta säkerställer inte riktigt lika hög flytpunktsnoggrannhet, men på vissa arkitekturer möjliggör det ett gäng optimeringar som kan göra att dina skript körs snabbare.
  • #pragma rs_fp_imprecise : Detta säkerställer ännu mindre precision och bör användas om flytpunktsprecision inte riktigt betyder något för ditt skript.

De flesta skript kan bara använda #pragma rs_fp_relaxed såvida du inte verkligen behöver hög flytpunktsprecision.

Globala variabler

Nu precis som i C-kod kan du definiera globala variabler eller konstanter:

const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};

float saturationLevel = 0.0f;

Variabeln gMonoMult är av typen float3 . Detta betyder att det är en vektor som består av 3 flottörnummer. Den andra float heter saturationValue är inte konstant, därför kan du ställa in den vid körning till ett värde du gillar. Du kan använda variabler som detta i dina kärnor eller funktioner och därför är de ett annat sätt att ge inmatning till eller ta emot utdata från dina RenderScripts. För varje inte konstant variabel kommer en getter- och setter-metod att genereras i den tillhörande Java-klassen.

kärnor

Men låt oss nu börja implementera kärnan. I det här exemplet kommer jag inte att förklara den matematik som används i kärnan för att ändra bildens mättnad, utan istället kommer att fokusera på hur man implementerar en kärnan och hur man använder den. I slutet av detta kapitel kommer jag snabbt att förklara vad koden i den här kärnan faktiskt gör.

Kärnor i allmänhet

Låt oss ta en titt på källkoden först:

uchar4 __attribute__((kernel)) saturation(uchar4 in) {
    float4 f4 = rsUnpackColor8888(in);
    float3 dotVector = dot(f4.rgb, gMonoMult);
    float3 newColor = mix(dotVector, f4.rgb, saturationLevel);
    return rsPackColorTo8888(newColor);
}

Som du ser ser det ut som en normal C-funktion med ett undantag: __attribute__((kernel)) mellan __attribute__((kernel)) . Det här är det som säger RenderScript att den här metoden är en kärna. En annan sak som du kanske märker är att den här metoden accepterar en uchar4 parameter och returnerar ett annat uchar4 värde. uchar4 är - som float3 variabeln vi diskuterade i kapitlet tidigare - en vektor. Det innehåller 4 uchar värden som bara är bytevärden i området från 0 till 255.

Du kan komma åt dessa enskilda värden på många olika sätt, till exempel in.r skulle returnera byten som motsvarar den röda kanalen för en pixel. Vi använder en uchar4 eftersom varje pixel består av fyra värden - r för röd, g för grön, b för blå och a för alfa - och du kan få åtkomst till dem med den här korta listan. Med RenderScript kan du också ta valfritt antal värden från en vektor och skapa en annan vektor med dem. Till exempel skulle in.rgb returnera ett uchar3 värde som bara innehåller de röda, gröna och blå delarna av pixeln utan alfavärdet.

Vid körning kommer RenderScript att kalla den här kärnmetoden för varje pixel i en bild, varför returvärdet och parametern bara är ett uchar4 värde. RenderScript kör många av dessa samtal parallellt på alla tillgängliga processorer, varför RenderScript är så kraftfullt. Detta innebär också att du inte behöver oroa dig för tråd eller säkerhet, du kan bara implementera vad du vill göra för varje pixel och RenderScript tar hand om resten.

När du ringer en Kernel i Java tillhandahåller du två Allocation , en som innehåller inmatningsdata och en annan som kommer att ta emot utdata. Din Kernel metoden kommer att kallas för varje värde i inmatnings Allocation och kommer att skriva resultatet till utgången Allocation .

RenderScript Runtime API-metoder

I kärnan ovan används några metoder som tillhandahålls ur lådan. RenderScript tillhandahåller många sådana metoder och de är viktiga för nästan allt du tänker göra med RenderScript. Bland dem finns metoder för att utföra matematiska operationer som sin() och hjälpmetoder som mix() som blandar två värden enligt andra värden. Men det finns också metoder för mer komplexa operationer när man hanterar vektorer, kvartärer och matriser.

Den officiella RenderScript Runtime API-referensen är den bästa resursen där ute om du vill veta mer om en viss metod eller letar efter en specifik metod som utför en vanlig åtgärd som att beräkna dot-produkten i en matris. Du kan hitta den här dokumentationen här .

Implementering av kärnan

Låt oss nu titta på detaljerna för vad den här kärnan gör. Här är den första raden i kärnan:

float4 f4 = rsUnpackColor8888(in);

Den första raden kallar den inbyggda metoden rsUnpackColor8888() som omvandlar uchar4 värdet till ett float4 värde. Varje färgkanal transformeras också till intervallet 0.0f - 1.0f där 0.0f motsvarar ett bytevärde på 0 och 1.0f till 255 . Huvudsyftet med detta är att göra all matematik i den här kärnan mycket enklare.

float3 dotVector = dot(f4.rgb, gMonoMult);

Den här nästa rad använder den inbyggda metoden dot() att beräkna punktprodukten för två vektorer. gMonoMult är ett konstant värde som vi definierade några kapitel ovan. Eftersom båda vektorerna måste vara av samma längd för att beräkna prickprodukten och också eftersom vi bara vill påverka färgkanalerna och inte en alfakanal för en pixel använder vi den korta .rgb att få en ny float3 vektor som bara innehåller röda, gröna och blå färgkanaler. De av oss som fortfarande kommer ihåg från skolan hur dot-produkten fungerar kommer snabbt att märka att dot-produkten ska returnera bara ett värde och inte en vektor. Men i koden ovan tilldelar vi resultatet till en float3 vektor. Detta är återigen en funktion i RenderScript. När du tilldelar ett endimensionellt nummer till en vektor kommer alla element i vektorn att ställas in på detta värde. Till exempel tilldelar följande 2.0f till var och en av de tre värdena i float3 vektorn:

float3 example = 2.0f;

Så resultatet av punktprodukten ovan tilldelas varje element i float3 vektorn ovan.

Nu kommer den del där vi faktiskt använder den globala variabeln saturationLevel att ändra bildens mättnad:

float3 newColor = mix(dotVector, f4.rgb, saturationLevel);

Detta använder den inbyggda mix() att blanda originalfärgen med punktproduktvektorn vi skapade ovan. Hur de blandas tillsammans bestäms av den globala saturationLevel variabeln. Så en saturationLevel0.0f orsakar att den resulterande färgen inte har någon del av de ursprungliga färgvärdena och kommer endast att bestå av värden i dotVector vilket resulterar i en svartvit eller grå färgad bild. Ett värde på 1.0f gör att den resulterande färgen helt består av de ursprungliga färgvärdena och värden över 1.0f multiplicerar originalfärgerna för att göra dem mer ljusa och intensiva.

return rsPackColorTo8888(newColor);

Detta är den sista delen i kärnan. rsPackColorTo8888() omvandlar float3 vektorn tillbaka till ett uchar4 värde som sedan returneras. De resulterande bytevärdena är fastklämda till ett intervall mellan 0 och 255, så att 1.0f högre än 1.0f resulterar i ett bytevärde på 255 och värden lägre än 0.0 kommer att resultera i ett bytevärde på 0 .

Och det är hela Kernel-implementeringen. Nu finns det bara en del kvar: Hur man kallar en kärnan i Java.

Ringer RenderScript i Java

Grunderna

Som redan nämnts ovan för varje RenderScript-fil genereras en Java-klass som låter dig interagera med dina skript. Dessa filer har prefixet ScriptC_ följt av namnet på RenderScript-filen. För att skapa en instans av dessa klasser behöver du först en instans av RenderScript klassen:

final RenderScript renderScript = RenderScript.create(context);

Den statiska metoden create() kan användas för att skapa en RenderScript instans från ett Context . Du kan sedan instansera Java-klassen som genererades för ditt skript. Om du ringde RenderScript-filen saturation.rs kallas ScriptC_saturation :

final ScriptC_saturation script = new ScriptC_saturation(renderScript);

På den här klassen kan du nu ställa in mättnadsnivån och ringa kärnan. Sättaren som genererades för variabeln saturationLevel kommer att ha prefixet set_ följt av variabelns namn:

script.set_saturationLevel(1.0f);

Det finns också en getter förinställd med get_ som låter dig få den mättnadsnivå som för närvarande är inställd:

float saturationLevel = script.get_saturationLevel();

Kärnor som du definierar i ditt RenderScript förinställs med forEach_ följt av namnet på Kernel-metoden. Kernel vi har skrivit förväntar en ingångs Allocation och en utgång Allocation som dess parametrar:

script.forEach_saturation(inputAllocation, outputAllocation);

Ingångs Allocation behöver innehålla den inmatade bilden, och efter forEach_saturation metoden har avslutat den utgående fördelning kommer att innehålla de modifierade bilddata.

När du har en Allocation kan du kopiera data från och till dessa Allocations med metoderna copyFrom() och copyTo() . Till exempel kan du kopiera en ny bild till din ingång `Allokering genom att ringa:

inputAllocation.copyFrom(inputBitmap);

På samma sätt kan du hämta resultatbilden genom att ringa copyTo() på utgången Allocation :

outputAllocation.copyTo(outputBitmap);

Skapa tilldelningsinstanser

Det finns många sätt att skapa en Allocation . När du har en Allocation kan du kopiera nya data från och till de Allocations med copyTo() och copyFrom() som förklarats ovan, men för att skapa dem från början måste du veta med vilken typ av data du exakt arbetar med. Låt oss börja med input Allocation :

Vi kan använda den statiska metoden createFromBitmap() för att snabbt skapa vår input Allocation från en Bitmap :

final Allocation inputAllocation = Allocation.createFromBitmap(renderScript, image);

I det här exemplet ingångsbilden förändras aldrig så vi behöver aldrig ändra ingångs Allocation igen. Vi kan återanvända det varje gång saturationLevel ändras för att skapa en ny utgång Bitmap .

Skapa utgångs Allocation är lite mer komplicerat. Först måste vi skapa det som kallas en Type . En Type används för att berätta en Allocation med vilken typ av data den hanterar. Vanligtvis använder man klassen Type.Builder att snabbt skapa en lämplig Type . Låt oss ta en titt på koden först:

final Type outputType = new Type.Builder(renderScript, Element.RGBA_8888(renderScript))
        .setX(inputBitmap.getWidth())
        .setY(inputBitmap.getHeight())
        .create();

Vi arbetar med en normal 32 bit (eller med andra ord 4 byte) per pixel Bitmap med 4 färgkanaler. Det är därför vi väljer Element.RGBA_8888 att skapa Type . Sedan använder vi metoderna setX() och setY() att ställa in setY() bredd och höjd till samma storlek som ingångsbilden. Metoden create() skapar sedan Type med de parametrar som vi angav.

När vi har rätt Type vi skapa Allocation med den statiska metoden createTyped() :

final Allocation outputAllocation = Allocation.createTyped(renderScript, outputType);

Nu är vi nästan klara. Vi behöver också en utgång Bitmap där vi kan kopiera data från utgången Allocation . För att göra detta använder vi den statiska metoden createBitmap() att skapa en ny tom Bitmap med samma storlek och konfiguration som den inmatade Bitmap .

final Bitmap outputBitmap = Bitmap.createBitmap(
        inputBitmap.getWidth(),
        inputBitmap.getHeight(),
        inputBitmap.getConfig()
);

Och med det har vi alla pusselbitar för att köra vårt RenderScript.

Fullständigt exempel

Låt oss nu sammansätta allt detta i ett exempel:

// Create the RenderScript instance
final RenderScript renderScript = RenderScript.create(context);

// Create the input Allocation 
final Allocation inputAllocation = Allocation.createFromBitmap(renderScript, inputBitmap);

// Create the output Type.
final Type outputType = new Type.Builder(renderScript, Element.RGBA_8888(renderScript))
        .setX(inputBitmap.getWidth())
        .setY(inputBitmap.getHeight())
        .create();

// And use the Type to create am output Allocation
final Allocation outputAllocation = Allocation.createTyped(renderScript, outputType);

// Create an empty output Bitmap from the input Bitmap
final Bitmap outputBitmap = Bitmap.createBitmap(
        inputBitmap.getWidth(),
        inputBitmap.getHeight(),
        inputBitmap.getConfig()
);

// Create an instance of our script
final ScriptC_saturation script = new ScriptC_saturation(renderScript);

// Set the saturation level
script.set_saturationLevel(2.0f);

// Execute the Kernel
script.forEach_saturation(inputAllocation, outputAllocation);

// Copy the result data to the output Bitmap
outputAllocation.copyTo(outputBitmap);

// Display the result Bitmap somewhere
someImageView.setImageBitmap(outputBitmap);

Slutsats

Med den här introduktionen bör du vara redo att skriva dina egna RenderScript-kärnor för enkel bildmanipulation. Det finns dock några saker du måste tänka på:

  • RenderScript fungerar bara i applikationsprojekt : För närvarande kan RenderScript-filer inte ingå i ett biblioteksprojekt.
  • Se upp för minnet : RenderScript är mycket snabbt, men det kan också vara minnesintensivt. Det bör aldrig finnas mer än en instans av RenderScript när som helst. Du bör också återanvända så mycket som möjligt. Normalt behöver du bara skapa dina Allocation gång och kan återanvända dem i framtiden. Detsamma gäller för utmatning Bitmaps eller dina skriptinstanser. Återanvända så mycket som möjligt.
  • Gör ditt arbete i bakgrunden : Återigen är RenderScript mycket snabbt, men inte direkt på något sätt. Alla kärnor, särskilt komplexa, bör köras från UI-tråden i en AsyncTask eller något liknande. Men för det mesta behöver du inte oroa dig för minnesläckor. Alla RenderScript-relaterade klasser använder bara applikationens Context och orsakar därför inte minnesläckor. Men du måste fortfarande oroa dig för de vanliga saker som läcka View , Activity eller någon Context som du använder själv!
  • Använd inbyggda grejer : Det finns många fördefinierade skript som utför uppgifter som suddighet, blandning, konvertering, storleksändring. Och det finns många fler inbyggda metoder som hjälper dig att implementera dina kärnor. Chansen är stor att om du vill göra något finns det antingen ett skript eller en metod som redan gör det du försöker göra. Uppfinna inte hjulet igen.

Om du snabbt vill komma igång och leka med verklig kod rekommenderar jag att du tittar på exemplet GitHub-projekt som implementerar exakt exemplet som talas om i den här tutorialen. Du hittar projektet här . Ha kul med RenderScript!

Oskärpa en bild

Detta exempel visar hur man använder Renderscript API för att oskärpa en bild (med hjälp av Bitmap). Detta exempel använder ScriptInstrinsicBlur tillhandahållet av Android Renderscript API (API> = 17).

public class BlurProcessor {
    
    private RenderScript rs;
    private Allocation inAllocation;
    private Allocation outAllocation;
    private int width;
    private int height;

    private ScriptIntrinsicBlur blurScript;

    public BlurProcessor(RenderScript rs) {
        this.rs = rs;
    }
    
    public void initialize(int width, int height) {
        blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
        blurScript.setRadius(7f); // Set blur radius. 25 is max

        if (outAllocation != null) {
            outAllocation.destroy();
            outAllocation = null;
        }
        
        // Bitmap must have ARGB_8888 config for this type
        Type bitmapType = new Type.Builder(rs, Element.RGBA_8888(rs))
            .setX(width)
            .setY(height)
            .setMipmaps(false) // We are using MipmapControl.MIPMAP_NONE
            .create();
        
        // Create output allocation
        outAllocation = Allocation.createTyped(rs, bitmapType);

        // Create input allocation with same type as output allocation
        inAllocation = Allocation.createTyped(rs, bitmapType);
    }

    public void release() {
        
        if (blurScript != null) {
            blurScript.destroy();
            blurScript = null;
        }
    
        if (inAllocation != null) {
            inAllocation.destroy();
            inAllocation = null;
        }

        if (outAllocation != null) {
            outAllocation.destroy();
            outAllocation = null;
        }
    }

    public Bitmap process(Bitmap bitmap, boolean createNewBitmap) {
        if (bitmap.getWidth() != width || bitmap.getHeight() != height) {
            // Throw error if required
            return null;
        }
        
        // Copy data from bitmap to input allocations
        inAllocation.copyFrom(bitmap);

        // Set input for blur script
        blurScript.setInput(inAllocation);

        // process and set data to the output allocation
        blurScript.forEach(outAllocation);
        
        if (createNewBitmap) {
            Bitmap returnVal = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            outAllocation.copyTo(returnVal);
            return returnVal;
        }

        outAllocation.copyTo(bitmap);
        return bitmap;
    }
}    

Varje skript har en kärna som bearbetar data och de åberopas vanligtvis via forEach metoden.

public class BlurActivity extends AppCompatActivity {
    private BlurProcessor blurProcessor;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // setup layout and other stuff

        
        blurProcessor = new BlurProcessor(Renderscript.create(getApplicationContext()));
    }

    private void loadImage(String path) {
        // Load image to bitmap
        Bitmap bitmap = loadBitmapFromPath(path);
        
        // Initialize processor for this bitmap
        blurProcessor.release();
        blurProcessor.initialize(bitmap.getWidth(), bitmap.getHeight());
        
        // Blur image
        Bitmap blurImage = blurProcessor.process(bitmap, true); // Use newBitamp as false if you don't want to create a new bitmap
    }
}

Detta avslutade exemplet här. Det rekommenderas att göra behandlingen i en bakgrundstråd.

Oskärpa en vy

BlurBitmapTask.java

public class BlurBitmapTask extends AsyncTask<Bitmap, Void, Bitmap> {
    private final WeakReference<ImageView> imageViewReference;
    private final RenderScript renderScript;

    private boolean shouldRecycleSource = false;

    public BlurBitmapTask(@NonNull Context context, @NonNull ImageView imageView) {
        // Use a WeakReference to ensure
        // the ImageView can be garbage collected
        imageViewReference = new WeakReference<>(imageView);
        renderScript = RenderScript.create(context);
    }

    // Decode image in background.
    @Override
    protected Bitmap doInBackground(Bitmap... params) {
        Bitmap bitmap = params[0];
        return blurBitmap(bitmap);
    }

    // Once complete, see if ImageView is still around and set bitmap.
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (bitmap == null || isCancelled()) {
            return;
        }

        final ImageView imageView = imageViewReference.get();
        if (imageView == null) {
            return;
        }

        imageView.setImageBitmap(bitmap);
    }

    public Bitmap blurBitmap(Bitmap bitmap) {
        // https://plus.google.com/+MarioViviani/posts/fhuzYkji9zz

        //Let's create an empty bitmap with the same size of the bitmap we want to blur
        Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
                Bitmap.Config.ARGB_8888);

        //Instantiate a new Renderscript


        //Create an Intrinsic Blur Script using the Renderscript
        ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));

        //Create the in/out Allocations with the Renderscript and the in/out bitmaps
        Allocation allIn = Allocation.createFromBitmap(renderScript, bitmap);
        Allocation allOut = Allocation.createFromBitmap(renderScript, outBitmap);

        //Set the radius of the blur
        blurScript.setRadius(25.f);

        //Perform the Renderscript
        blurScript.setInput(allIn);
        blurScript.forEach(allOut);

        //Copy the final bitmap created by the out Allocation to the outBitmap
        allOut.copyTo(outBitmap);

        // recycle the original bitmap
        // nope, we are using the original bitmap as well :/
        if (shouldRecycleSource) {
            bitmap.recycle();
        }

        //After finishing everything, we destroy the Renderscript.
        renderScript.destroy();

        return outBitmap;
    }

    public boolean isShouldRecycleSource() {
        return shouldRecycleSource;
    }

    public void setShouldRecycleSource(boolean shouldRecycleSource) {
        this.shouldRecycleSource = shouldRecycleSource;
    }
}

Användande:

ImageView imageViewOverlayOnViewToBeBlurred
        .setImageDrawable(ContextCompat.getDrawable(this, android.R.color.transparent));
View viewToBeBlurred.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_LOW);
viewToBeBlurred.setDrawingCacheEnabled(true);
BlurBitmapTask blurBitmapTask = new BlurBitmapTask(this, imageViewOverlayOnViewToBeBlurred);
blurBitmapTask.execute(Bitmap.createBitmap(viewToBeBlurred.getDrawingCache()));
viewToBeBlurred.setDrawingCacheEnabled(false);


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow