Android
RenderScript
Ricerca…
introduzione
RenderScript è un linguaggio di scripting che consente di scrivere rendering grafico ad alte prestazioni e codice di calcolo raw. Fornisce un mezzo per scrivere codice critico delle prestazioni che il sistema compila successivamente in codice nativo per il processore su cui può essere eseguito. Questa potrebbe essere la CPU, una CPU multi-core o anche la GPU. In definitiva, ciò dipende da molti fattori che non sono prontamente disponibili per lo sviluppatore, ma dipende anche da quale architettura supporta il compilatore di piattaforma interno.
Iniziare
RenderScript è un framework per consentire il calcolo parallelo ad alte prestazioni su Android. Gli script scritti verranno eseguiti su tutti i processori disponibili (ad es. CPU, GPU, ecc.) In parallelo, consentendo all'utente di concentrarsi sull'attività che si desidera ottenere anziché su come è pianificata ed eseguita.
Gli script sono scritti in un linguaggio basato su C99 (C99 è una vecchia versione dello standard del linguaggio di programmazione C). Per ogni script viene creata una classe Java che consente di interagire facilmente con RenderScript nel codice Java.
Impostazione del tuo progetto
Esistono due modi diversi per accedere a RenderScript nella tua app, con le librerie di Android Framework o la libreria di supporto. Anche se non desideri utilizzare i dispositivi di destinazione prima dell'API 11, devi sempre utilizzare l'implementazione della Libreria di supporto perché garantisce la compatibilità dei dispositivi su molti dispositivi diversi. Per utilizzare l'implementazione della libreria di supporto è necessario utilizzare almeno gli strumenti di compilazione versione 18.1.0
!
Ora consente di configurare il file build.gradle dell'applicazione:
android {
compileSdkVersion 24
buildToolsVersion '24.0.1'
defaultConfig {
minSdkVersion 8
targetSdkVersion 24
renderscriptTargetApi 18
renderscriptSupportModeEnabled true
}
}
-
renderscriptTargetApi
: questo dovrebbe essere impostato sulla versione più recente del livello API che fornisce tutte le funzionalità RenderScript richieste. -
renderscriptSupportModeEnabled
: abilita l'uso dell'implementazione RenderScript della libreria di supporto.
Come funziona RenderScript
Un tipico RenderScript consiste di due cose: i kernel e le funzioni. Una funzione è proprio quello che sembra: accetta un input, fa qualcosa con quell'input e restituisce un output. Un kernel è da dove proviene il vero potere di RenderScript.
Un kernel è una funzione che viene eseguita su ogni elemento all'interno di Allocation
. Allocation
può essere utilizzata per passare dati come una Bitmap
o una matrice di byte
a un RenderScript
e vengono anche utilizzati per ottenere un risultato da un kernel. I kernel possono prendere una Allocation
come input e un'altra come output oppure possono modificare i dati all'interno di una sola Allocation
.
Puoi scrivere il tuo kernel, ma ci sono anche molti kernel predefiniti che puoi usare per eseguire operazioni comuni come un Gaussian Image Blur.
Come già accennato per ogni file RenderScript, viene generata una classe per interagire con esso. Queste classi iniziano sempre con il prefisso ScriptC_
seguito dal nome del file RenderScript. Ad esempio, se il tuo file RenderScript è chiamato example
la classe Java generata verrà chiamata ScriptC_example
. Tutti gli script predefiniti iniziano solo con lo Script
prefisso, ad esempio lo script di sfocatura immagine gaussiana si chiama ScriptIntrinsicBlur
.
Scrivi il tuo primo RenderScript
Il seguente esempio è basato su un esempio su GitHub. Esegue la manipolazione di base delle immagini modificando la saturazione di un'immagine. Puoi trovare il codice sorgente qui e verificarlo se vuoi giocarci da solo. Ecco una rapida gif di come dovrebbe apparire il risultato:
RenderScript Boilerplate
I file RenderScript risiedono nella cartella src/main/rs
nel tuo progetto. Ogni file ha l'estensione del file .rs
e deve contenere due istruzioni #pragma
nella parte superiore:
#pragma version(1)
#pragma rs java_package_name(your.package.name)
#pragma version(1)
: può essere usato per impostare la versione di RenderScript che stai utilizzando. Attualmente c'è solo la versione 1.#pragma rs java_package_name(your.package.name)
: può essere usato per impostare il nome del pacchetto della classe Java generata per interagire con questo particolare RenderScript.
C'è un altro #pragma
che dovresti normalmente impostare in ciascuno dei tuoi file RenderScript e che è usato per impostare la precisione in virgola mobile. È possibile impostare la precisione in virgola mobile su tre diversi livelli:
-
#pragma rs_fp_full
: questa è l'impostazione più rigorosa con la massima precisione ed è anche il valore predefinito se non si specifica nulla. Dovresti usarlo se hai bisogno di una precisione in virgola mobile elevata. -
#pragma rs_fp_relaxed
: questo garantisce un'elevata precisione in virgola mobile, ma su alcune architetture consente una serie di ottimizzazioni che possono far sì che i tuoi script possano girare più velocemente. -
#pragma rs_fp_imprecise
: questo garantisce una precisione ancora minore e dovrebbe essere usato se la precisione in virgola mobile non è veramente importante per il tuo script.
La maggior parte degli script può usare #pragma rs_fp_relaxed
meno che non sia veramente necessaria un'elevata precisione in virgola mobile.
Variabili globali
Ora, proprio come nel codice C, puoi definire variabili o costanti globali:
const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
float saturationLevel = 0.0f;
La variabile gMonoMult
è di tipo float3
. Ciò significa che è un vettore costituito da 3 numeri float. L'altra variabile float
denominata saturationValue
non è costante, pertanto è possibile impostarla in fase di esecuzione su un valore che ti piace. Puoi usare variabili come questa nei tuoi Kernel o funzioni e quindi sono un altro modo per dare input o ricevere output dai tuoi RenderScripts. Per ogni variabile non costante verrà generato un metodo getter e setter sulla classe Java associata.
Noccioli
Ma ora iniziamo ad implementare il Kernel. Per gli scopi di questo esempio non ho intenzione di spiegare la matematica usata nel kernel per modificare la saturazione dell'immagine, ma invece si concentrerà su come implementare un kernel e su come usarlo. Alla fine di questo capitolo spiegherò rapidamente cosa sta facendo il codice in questo kernel.
Kernels in generale
Diamo prima un'occhiata al codice sorgente:
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);
}
Come puoi vedere sembra una normale funzione C con un'eccezione: __attribute__((kernel))
tra il tipo di ritorno e il nome del metodo. Questo è ciò che dice a RenderScript che questo metodo è un kernel. Un'altra cosa che potresti notare è che questo metodo accetta un parametro uchar4
e restituisce un altro valore uchar4
. uchar4
è - come la variabile float3
discussa nel capitolo precedente - un vettore. Contiene 4 valori uchar
che sono solo valori byte nell'intervallo compreso tra 0 e 255.
È possibile accedere a questi singoli valori in molti modi diversi, ad esempio in.r
restituirebbe il byte che corrisponde al canale rosso di un pixel. Usiamo un uchar4
poiché ogni pixel è composto da 4 valori - r
per rosso, g
per verde, b
per blu e a
per alpha - e puoi accedervi con questa stenografia. RenderScript consente anche di prendere qualsiasi numero di valori da un vettore e creare un altro vettore con essi. Ad esempio in.rgb
restituirebbe un valore uchar3
che contiene solo le parti rossa, verde e blu del pixel senza il valore alfa.
Durante il runtime RenderScript chiamerà questo metodo Kernel per ogni pixel di un'immagine, motivo per cui il valore restituito e il parametro sono solo un valore uchar4
. RenderScript eseguirà molte di queste chiamate in parallelo su tutti i processori disponibili, motivo per cui RenderScript è così potente. Ciò significa anche che non devi preoccuparti del thread o della sicurezza dei thread, puoi semplicemente implementare ciò che vuoi fare su ciascun pixel e RenderScript si prenderà cura di tutto il resto.
Quando si chiama un Kernel in Java vengono fornite due variabili di Allocation
, una che contiene i dati di input e un'altra che riceverà l'output. Vostro metodo Kernel verrà chiamato per ogni valore nell'input Allocation
e scriverà il risultato all'uscita Allocation
.
Metodi dell'API Runtime di RenderScript
Nel kernel sopra sono usati alcuni metodi forniti fuori dalla scatola. RenderScript fornisce molti di questi metodi e sono fondamentali per qualsiasi cosa tu debba fare con RenderScript. Tra questi ci sono i metodi per fare operazioni matematiche come sin()
e metodi helper come mix()
che mescola due valori in base ad altri valori. Ma ci sono anche metodi per operazioni più complesse quando si tratta di vettori, quaternioni e matrici.
Il riferimento dell'API RenderScript Runtime ufficiale è la migliore risorsa là fuori se vuoi saperne di più su un particolare metodo o stai cercando un metodo specifico che esegua un'operazione comune come il calcolo del prodotto punto di una matrice. Puoi trovare questa documentazione qui .
Implementazione del kernel
Ora diamo un'occhiata alle specifiche di ciò che questo kernel sta facendo. Ecco la prima riga del kernel:
float4 f4 = rsUnpackColor8888(in);
Chiama la prima linea di costruzione metodo rsUnpackColor8888()
che trasforma uchar4
valore di un float4
valori. Ogni canale di colore viene anche trasformato nell'intervallo 0.0f - 1.0f
dove 0.0f
corrisponde a un valore di byte di 0
e 1.0f
a 255
. Lo scopo principale di questo è rendere molto più semplici tutti i calcoli in questo Kernel.
float3 dotVector = dot(f4.rgb, gMonoMult);
Questa riga successiva utilizza il metodo incorporato dot()
per calcolare il prodotto punto di due vettori. gMonoMult
è un valore costante abbiamo definito alcuni capitoli sopra. Dal momento che entrambi i vettori devono essere della stessa lunghezza per calcolare il prodotto punto e anche dal momento che vogliamo solo influenzare i canali di colore e non il canale alfa di un pixel usiamo la scorciatoia .rgb
per ottenere un nuovo vettore float3
che contiene solo il canali di colore rosso, verde e blu. Quelli di noi che ancora ricordano a scuola come funziona il prodotto dot noteranno subito che il prodotto puntino dovrebbe restituire solo un valore e non un vettore. Tuttavia nel codice sopra stiamo assegnando il risultato a un vettore float3
. Questa è ancora una caratteristica di RenderScript. Quando assegni un numero unidimensionale a un vettore, tutti gli elementi nel vettore saranno impostati su questo valore. Ad esempio il seguente snippet assegnerà 2.0f
a ciascuno dei tre valori nel vettore float3
:
float3 example = 2.0f;
Quindi il risultato del prodotto punto sopra è assegnato a ciascun elemento nel vettore float3
sopra.
Ora arriva la parte in cui effettivamente usiamo la variabile globale saturationLevel
per modificare la saturazione dell'immagine:
float3 newColor = mix(dotVector, f4.rgb, saturationLevel);
Questo usa il metodo integrato mix()
per mescolare insieme il colore originale con il vettore di punti prodotto che abbiamo creato sopra. Il modo in cui vengono mescolati insieme è determinato dalla variabile global saturationLevel
. Quindi un livello di saturationLevel
pari a 0.0f
farà sì che il colore risultante non abbia parte dei valori di colore originali e consisterà solo di valori nel dotVector
che si traduce in un'immagine in bianco e nero o in grigio. Un valore di 1.0f
farà sì che il colore risultante sia completamente composto da valori di colore originali e valori superiori a 1.0f
moltiplicheranno i colori originali per renderli più luminosi e intensi.
return rsPackColorTo8888(newColor);
Questa è l'ultima parte del kernel. rsPackColorTo8888()
trasforma il vettore float3
in un valore uchar4
che viene quindi restituito. I valori di byte risultanti vengono bloccati su un intervallo compreso tra 0 e 255, pertanto valori float superiori a 1.0f
generano un valore di byte pari a 255 e valori inferiori a 0.0
generano un valore di byte pari a 0
.
E questa è l'intera implementazione del kernel. Ora c'è solo una parte rimanente: come chiamare un kernel in Java.
Richiamo di RenderScript in Java
Nozioni di base
Come già detto sopra per ogni file RenderScript, viene generata una classe Java che consente di interagire con gli script. Questi file hanno il prefisso ScriptC_
seguito dal nome del file RenderScript. Per creare un'istanza di queste classi è necessario innanzitutto un'istanza della classe RenderScript
:
final RenderScript renderScript = RenderScript.create(context);
Il metodo statico create()
può essere utilizzato per creare un'istanza RenderScript
da un Context
. È quindi possibile creare un'istanza della classe Java che è stata generata per il tuo script. Se hai chiamato il file RenderScript saturation.rs
la classe si chiamerà ScriptC_saturation
:
final ScriptC_saturation script = new ScriptC_saturation(renderScript);
Su questa classe ora puoi impostare il livello di saturazione e chiamare il kernel. Il setter che è stato generato per la variabile saturationLevel
avrà il prefisso set_
seguito dal nome della variabile:
script.set_saturationLevel(1.0f);
C'è anche un getter con prefisso get_
che ti permette di ottenere il livello di saturazione attualmente impostato:
float saturationLevel = script.get_saturationLevel();
I kernel definiti in RenderScript sono preceduti da forEach_
seguito dal nome del metodo Kernel. Il kernel che abbiamo scritto si aspetta Allocation
input e Allocation
output come parametri:
script.forEach_saturation(inputAllocation, outputAllocation);
L' Allocation
input deve contenere l'immagine di input e, al termine del metodo forEach_saturation
, l'allocazione di output conterrà i dati di immagine modificati.
Una volta Allocation
un'istanza di Allocation
è possibile copiare i dati da e verso tali Allocations
utilizzando i metodi copyFrom()
e copyTo()
. Ad esempio è possibile copiare una nuova immagine nel proprio input `Assegnazione chiamando:
inputAllocation.copyFrom(inputBitmap);
Allo stesso modo è possibile recuperare l'immagine risultato chiamando copyTo()
sull'uscita Allocation
:
outputAllocation.copyTo(outputBitmap);
Creare istanze di allocazione
Esistono molti modi per creare Allocation
. Una volta che hai un'istanza di Allocation
puoi copiare nuovi dati da e verso quelle Allocations
con copyTo()
e copyFrom()
come spiegato sopra, ma per crearli inizialmente devi sapere con che tipo di dati stai lavorando esattamente. Iniziamo con l' Allocation
degli input:
Possiamo usare il metodo statico createFromBitmap()
per creare rapidamente l' Allocation
input da una Bitmap
:
final Allocation inputAllocation = Allocation.createFromBitmap(renderScript, image);
In questo esempio l'immagine di input non cambia mai, quindi non è più necessario modificare di nuovo l' Allocation
input. Possiamo riutilizzarlo ogni volta che saturationLevel
cambia per creare un nuovo Bitmap
output.
Creare l'output L' Allocation
è un po 'più complessa. Per prima cosa dobbiamo creare ciò che è chiamato un Type
. Un Type
è usato per dire Allocation
con che tipo di dati sta trattando. Di solito si usa la classe Type.Builder
per creare rapidamente un Type
appropriato. Diamo prima un'occhiata al codice:
final Type outputType = new Type.Builder(renderScript, Element.RGBA_8888(renderScript))
.setX(inputBitmap.getWidth())
.setY(inputBitmap.getHeight())
.create();
Stiamo lavorando con un normale Bitmap
a 32 bit (o in altre parole 4 byte) per pixel con 4 canali di colore. Ecco perché stiamo scegliendo Element.RGBA_8888
per creare il Type
. Quindi usiamo i metodi setX()
e setY()
per impostare la larghezza e l'altezza dell'immagine di output alla stessa dimensione dell'immagine di input. Il metodo create()
crea quindi il Type
con i parametri che abbiamo specificato.
Una volta che abbiamo il Type
corretto possiamo creare l' Allocation
dell'output con il metodo statico createTyped()
:
final Allocation outputAllocation = Allocation.createTyped(renderScript, outputType);
Ora abbiamo quasi finito. Abbiamo anche bisogno di un output Bitmap
in cui possiamo copiare i dati dalla uscita Allocation
. Per fare questo usiamo il metodo statico createBitmap()
per creare una nuova Bitmap
vuota con le stesse dimensioni e la stessa configurazione della Bitmap
input.
final Bitmap outputBitmap = Bitmap.createBitmap(
inputBitmap.getWidth(),
inputBitmap.getHeight(),
inputBitmap.getConfig()
);
E con questo abbiamo tutti i pezzi del puzzle per eseguire il nostro RenderScript.
Esempio completo
Ora mettiamo insieme tutto questo in un solo esempio:
// 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);
Conclusione
Con questa introduzione dovresti essere pronto a scrivere i tuoi kernel RenderScript per una semplice manipolazione delle immagini. Tuttavia ci sono alcune cose da tenere a mente:
- RenderScript funziona solo nei progetti di applicazione : attualmente i file RenderScript non possono far parte di un progetto di libreria.
- Attenzione per la memoria : RenderScript è molto veloce, ma può anche richiedere un uso intensivo della memoria. Non ci dovrebbe mai essere più di una istanza di
RenderScript
in qualsiasi momento. Dovresti anche riutilizzare il più possibile. Normalmente è sufficiente creare le istanze diAllocation
una sola volta e riutilizzarle in futuro. Lo stesso vale per leBitmaps
output o le istanze di script. Riutilizzare il più possibile. - Fai il tuo lavoro in background : Ancora RenderScript è molto veloce, ma non istantaneo in alcun modo. Qualsiasi kernel, specialmente quelli complessi, dovrebbe essere eseguito fuori dal thread dell'interfaccia utente in un
AsyncTask
o qualcosa di simile. Tuttavia per la maggior parte non devi preoccuparti di perdite di memoria. Tutte le classi correlate a RenderScript utilizzano solo l'applicazioneContext
e quindi non causano perdite di memoria. Ma devi ancora preoccuparti delle solite cose come perdite diView
,Activity
o qualsiasi istanza diContext
che usi tu stesso! - Usa elementi incorporati : esistono numerosi script predefiniti che eseguono attività come sfocatura dell'immagine, fusione, conversione, ridimensionamento. E ci sono molti altri metodi incorporati che ti aiutano a implementare i tuoi kernel. È probabile che se vuoi fare qualcosa, c'è uno script o un metodo che fa già ciò che stai cercando di fare. Non reinventare la ruota.
Se vuoi iniziare subito a giocare con il codice reale ti consiglio di dare un'occhiata al progetto GitHub di esempio che implementa l'esatto esempio di cui si parla in questo tutorial. Puoi trovare il progetto qui . Divertiti con RenderScript!
Sfocare un'immagine
Questo esempio dimostra come usare l'API Renderscript per sfocare un'immagine (usando Bitmap). Questo esempio utilizza ScriptInstrinsicBlur fornito da 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;
}
}
Ogni script ha un kernel che elabora i dati ed è generalmente invocato tramite il metodo forEach
.
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
}
}
Questo ha concluso l'esempio qui. Si consiglia di eseguire l'elaborazione in un thread in background.
Sfocare una vista
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;
}
}
Uso:
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);