수색…


소개

RenderScript는 고성능 그래픽 렌더링 및 원시 계산 코드를 작성할 수있는 스크립팅 언어입니다. 시스템이 나중에 실행할 수있는 프로세서의 원시 코드로 컴파일되는 성능 중요한 코드를 작성하는 수단을 제공합니다. 이것은 CPU, 멀티 코어 CPU 또는 심지어 GPU 일 수 있습니다. 궁극적으로는 개발자가 쉽게 사용할 수없는 많은 요인에 따라 다르지만 내부 플랫폼 컴파일러가 지원하는 아키텍처에 따라 달라집니다.

시작하기

RenderScript는 Android에서 고성능 병렬 계산을 허용하는 프레임 워크입니다. 작성한 스크립트는 병렬로 사용 가능한 모든 프로세서 (예 : CPU, GPU 등)에서 실행되어 예약 및 실행 방법 대신 달성하려는 작업에 집중할 수 있습니다.

스크립트는 C99 기반 언어로 작성됩니다 (C99는 C 프로그래밍 언어 표준의 구 버전 임). 각 스크립트마다 Java 코드에서 RenderScript와 쉽게 상호 작용할 수있는 Java 클래스가 만들어집니다.

프로젝트 설정하기

Android 프레임 워크 라이브러리 또는 지원 라이브러리를 사용하여 앱에서 RenderScript에 액세스하는 두 가지 방법이 있습니다. API 레벨 11 이전에 장치를 타겟팅하지 않으려는 경우에도 여러 가지 장치에서 장치 호환성을 보장하므로 항상 지원 라이브러리 구현을 사용해야합니다. 지원 라이브러리 구현을 사용하려면 최소한 빌드 도구 버전 18.1.0 !

이제 응용 프로그램의 build.gradle 파일을 설정할 수 있습니다.

android {
    compileSdkVersion 24
    buildToolsVersion '24.0.1'

    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 24

        renderscriptTargetApi 18
        renderscriptSupportModeEnabled true
    }
}
  • renderscriptTargetApi : 필요한 모든 RenderScript 기능을 제공하는 가장 빠른 API 레벨로 설정해야합니다.
  • renderscriptSupportModeEnabled : 지원 라이브러리 RenderScript 구현을 사용할 수있게합니다.

RenderScript의 작동 원리

일반적인 RenderScript는 커널과 함수의 두 가지로 구성됩니다. 함수는 마치 소리처럼 들린다. 입력을 받아들이고, 그 입력으로 무엇인가하고 출력을 반환한다. 커널은 RenderScript의 진정한 힘이 나오는 곳입니다.

커널은 Allocation 내 모든 요소에 대해 실행되는 함수입니다. AllocationBitmap 또는 byte 배열과 같은 데이터를 RenderScript 에 전달하는 데 사용할 수 있으며 커널에서 결과를 얻는데도 사용됩니다. 커널은 하나의 Allocation 을 입력으로 사용하고 다른 하나는 출력으로 사용하거나 하나의 Allocation 내에서 데이터를 수정할 수 있습니다.

하나의 커널을 쓸 수도 있지만, Gaussian Image Blur와 같은 일반적인 작업을 수행하는 데 사용할 수있는 미리 정의 된 커널이 많이 있습니다.

모든 RenderScript 파일에 대해 이미 언급했듯이 클래스와 상호 작용하기 위해 생성됩니다. 이러한 클래스는 항상 ScriptC_ 접두사와 RenderScript 파일의 이름으로 시작됩니다. 예를 들어, RenderScript 파일이 example 이라고하면 생성 된 Java 클래스는 ScriptC_example 이라고 ScriptC_example . 모든 사전 정의 된 스크립트는 접두어로 시작하는 Script 가우시안 이미지 블러 스크립트를 호출 - 예를 들어, ScriptIntrinsicBlur .

첫 번째 RenderScript 작성하기

다음 예제는 GitHub의 예제를 기반으로합니다. 그것은 이미지의 채도를 수정하여 기본적인 이미지 조작을 수행합니다. 여기 에서 소스 코드를 찾아서 직접 사용해보고 싶다면 체크 아웃하십시오. 결과가 어떻게 보이는지에 대한 빠른 gif가 있습니다.

데모 사진

RenderScript 상용구

RenderScript 파일은 프로젝트의 src/main/rs 폴더에 있습니다. 각 파일의 파일 확장자는 .rs 이며 맨 위에 두 개의 #pragma 문이 있어야합니다.

#pragma version(1)
#pragma rs java_package_name(your.package.name)
  • #pragma version(1) : 사용중인 RenderScript의 버전을 설정하는 데 사용할 수 있습니다. 현재 버전 1 만 있습니다.

  • #pragma rs java_package_name(your.package.name) :이 특정 RenderScript와 상호 작용하도록 생성 된 Java 클래스의 패키지 이름을 설정하는 데 사용할 수 있습니다.

일반적으로 각 RenderScript 파일에 설정해야하는 또 다른 #pragma 가 있으며 부동 소수점 정밀도를 설정하는 데 사용됩니다. 부동 소수점 정밀도를 세 가지 다른 수준으로 설정할 수 있습니다.

  • #pragma rs_fp_full : 이것은 가장 정밀도가 가장 엄격한 가장 엄격한 설정이며 아무 것도 지정하지 않으면 기본값입니다. 높은 부동 소수점 정밀도가 필요한 경우이 값을 사용해야합니다.
  • #pragma rs_fp_relaxed : 이는 부동 소수점 정밀도가 높지는 않지만, 일부 아키텍처에서는 스크립트가 더 빨리 실행될 수있는 최적화를 허용합니다.
  • #pragma rs_fp_imprecise : 이렇게하면 정밀도가 떨어지고 부동 소수점 정밀도가 스크립트에 실제로 중요하지 않은 경우 사용해야합니다.

대부분의 스크립트는 #pragma rs_fp_relaxed 사용할 수 있습니다.

전역 변수

이제 C 코드와 마찬가지로 전역 변수 나 상수를 정의 할 수 있습니다.

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

float saturationLevel = 0.0f;

gMonoMult 변수는 float3 유형입니다. 이것은 그것이 3 개의 부동 소수로 구성된 벡터임을 의미합니다. 다른 float 변수 saturationValue 는 상수가 아니므로 런타임에 원하는 값으로 설정할 수 있습니다. 커널이나 함수에서 이와 같은 변수를 사용할 수 있으므로 RenderScript에서 입력을주고받는 또 다른 방법입니다. 상수가 아닌 각 변수에 대해 getter 및 setter 메소드가 연관된 Java 클래스에서 생성됩니다.

커널

그러나 이제는 커널을 구현할 수 있습니다. 이 예제에서는 이미지의 채도를 수정하는 데 Kernel에서 사용 된 수학을 설명하지는 않지만 대신 Kernel을 구현하는 방법과 사용 방법에 중점을 둡니다. 이 장의 끝에서이 커널의 코드가 실제로 무엇을하는지 빨리 설명 할 것입니다.

일반적으로 커널

먼저 소스 코드를 살펴 보겠습니다.

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);
}

보시다시피, 하나의 예외가있는 일반적인 C 함수처럼 보입니다 : 반환 유형과 메소드 이름 사이의 __attribute__((kernel)) . 이것이 RenderScript에이 메소드가 Kernel임을 알려주는 것입니다. 또 다른주의 할 점은이 메서드는 uchar4 매개 변수를 받아들이고 다른 uchar4 값을 반환 uchar4 입니다. uchar4 는 이전 장에서 설명한 float3 변수와 마찬가지로 벡터입니다. 여기에는 0에서 255 사이의 바이트 값만있는 4 개의 uchar 값이 들어 있습니다.

여러 가지 방법으로 이러한 개별 값에 액세스 할 수 있습니다. 예를 들어 in.r 은 픽셀의 빨간색 채널에 해당하는 바이트를 반환합니다. 우리는 uchar4 사용합니다. 각 픽셀은 적색은 r , 녹색은 g , 파란색은 b , 알파 a b 의 4 가지 값으로 구성되어 있습니다.이 축약 형으로 액세스 할 수 있습니다. RenderScript를 사용하면 벡터에서 원하는만큼의 값을 가져 와서 다른 벡터를 만들 수 있습니다. 예를 들어 in.rgb 는 알파 값이없는 픽셀의 빨강, 녹색 및 파랑 부분을 포함하는 uchar3 값을 반환합니다.

런타임시 RenderScript는 이미지의 각 픽셀에 대해이 Kernel 메서드를 호출하므로 반환 값과 매개 변수는 단 하나의 uchar4 값입니다. RenderScript는 사용 가능한 모든 프로세서에서 이러한 호출을 병렬로 실행하므로 RenderScript가 그토록 강력합니다. 이것은 또한 스레딩이나 스레드 안전성에 대해 걱정할 필요가 없다는 것을 의미합니다. 각 픽셀에 수행하려는 작업을 구현할 수 있으며 RenderScript가 나머지 작업을 처리합니다.

Java에서 Kernel을 호출 할 때 두 개의 Allocation 변수를 제공합니다. 하나는 입력 데이터를 포함하고 다른 하나는 출력을 수신합니다. 커널 메서드는 입력 Allocation 각 값에 대해 호출되고 그 결과를 출력 Allocation 씁니다.

RenderScript 런타임 API 메소드

위의 커널에서는 몇 가지 방법을 사용하여 즉시 사용할 수 있습니다. RenderScript는 이러한 많은 메소드를 제공하며 RenderScript로 수행하려는 거의 모든 작업에 필수적입니다. 그 중 sin() 과 같은 수학 연산을 수행하는 메소드와 다른 값에 따라 두 값을 혼합하는 mix() 와 같은 헬퍼 메소드가 있습니다. 그러나 벡터, 쿼터니언 및 행렬을 다룰 때 더 복잡한 연산을 수행하는 방법도 있습니다.

공식 RenderScript Runtime API Reference 는 특정 메소드에 대해 더 많이 알고 싶거나 매트릭스의 내적을 계산하는 것과 같은 공통 연산을 수행하는 특정 메소드를 찾고있는 경우 가장 적합한 리소스입니다. 이 설명서는 여기에서 찾을 수 있습니다.

커널 구현

이제이 커널이하는 일의 특성을 살펴 보겠습니다. 다음은 커널의 첫 번째 행입니다.

float4 f4 = rsUnpackColor8888(in);

첫 번째 줄은 uchar4 값을 float4 값으로 변환하는 내장 된 메서드 rsUnpackColor8888() 을 호출합니다. 또한 각 색상 채널은 0.0f - 1.0f 범위로 변환됩니다. 여기서 0.0f01.0f 에서 255 의 바이트 값에 해당합니다. 이것의 주요 목적은이 커널에서 모든 수학을 훨씬 더 단순하게 만드는 것입니다.

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

이 다음 줄에서는 내장 된 메서드 dot() 를 사용하여 두 벡터의 내적을 계산합니다. gMonoMult 는 위의 몇 장을 정의한 상수 값입니다. 두 벡터 모두 내적을 계산할 때 길이가 같아야하고 픽셀의 알파 채널이 아닌 색상 채널에만 영향을주기를 원하기 때문에 .rgb 를 사용하여 새 float3 벡터를 얻습니다. 빨강, 녹색 및 파랑 색 채널. 우리가 지금까지 학교에서 똑똑한 제품이 어떻게 작동 하는지를 기억하는 사람들은 내적 제품이 벡터가 아닌 단지 하나의 가치만을 돌려 주어야한다는 것을 빨리 알게 될 것입니다. 위의 코드에서 결과를 float3 벡터에 지정합니다. 이것은 다시 RenderScript의 기능입니다. 벡터에 1 차원 숫자를 할당하면 벡터의 모든 요소가이 값으로 설정됩니다. 예를 들어, 다음 스 니펫은 float3 벡터의 세 값 각각에 2.0f 를 할당합니다.

float3 example = 2.0f;

위의 내적 결과는 위의 float3 벡터의 각 요소에 할당됩니다.

이제 우리는 실제로 전역 변수 saturationLevel 을 사용하여 이미지의 saturationLevel 를 수정하는 부분을 얻습니다.

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

이것은 내장 된 방법 mix() 를 사용하여 원래 색상과 위에서 만든 내적 벡터를 혼합합니다. 이들이 어떻게 혼합되는지는 전역 saturationLevel 변수에 의해 결정됩니다. 따라서 saturationLevel0.0f 이면 결과 색상에 원래 색상 값이 dotVector 의 값으로 구성되어 흑백 또는 회색으로 표시된 이미지가됩니다. 1.0f 의 값을 지정하면 결과 색상이 원래 색상 값으로 완전히 구성되며 1.0f 를 초과하면 원래 색상이 배가되어 더 밝고 강렬 해집니다.

return rsPackColorTo8888(newColor);

이것은 커널의 마지막 부분입니다. rsPackColorTo8888()float3 벡터를 다시 uchar4 값으로 변환 한 다음 반환합니다. 결과 바이트 값은 0에서 255 사이의 범위로 고정되므로 1.0f 보다 큰 부동 소수점 값은 255의 바이트 값이되고 0.0 보다 작은 값은 0 의 바이트 값이됩니다.

이것이 바로 전체 커널 구현입니다. 이제 Java로 커널을 호출하는 방법이 하나만 남아 있습니다.

Java에서 RenderScript 호출하기

기초

이미 각 RenderScript 파일에 대해 언급했듯이 스크립트와 상호 작용할 수있는 Java 클래스가 생성됩니다. 이 파일의 접두어는 ScriptC_ 이며 RenderScript 파일의 이름이 뒤에옵니다. 이러한 클래스의 인스턴스를 만들려면 먼저 RenderScript 클래스의 인스턴스가 필요합니다.

final RenderScript renderScript = RenderScript.create(context);

정적 메서드 create() 를 사용하여 Context 에서 RenderScript 인스턴스를 만들 수 있습니다. 그런 다음 스크립트에 대해 생성 된 Java 클래스를 인스턴스화 할 수 있습니다. RenderScript 파일 saturation.rs 를 호출하면 클래스는 ScriptC_saturation 이라고 ScriptC_saturation .

final ScriptC_saturation script = new ScriptC_saturation(renderScript);

이 클래스에서 이제 채도 레벨을 설정하고 커널을 호출 할 수 있습니다. saturationLevel 변수에 대해 생성 된 setter는 set_ 접두어 다음에 변수 이름 set_ .

script.set_saturationLevel(1.0f);

현재 설정되어있는 채도 레벨을 얻을 수있는 get_ 접두사가 붙은 getter도 있습니다.

float saturationLevel = script.get_saturationLevel();

RenderScript에서 정의한 커널에는 forEach_ 와 Kernel 메소드의 이름이 접두어로 forEach_ 습니다. 우리가 작성한 커널은 입력 Allocation 과 출력 Allocation 을 매개 변수로 기대합니다.

script.forEach_saturation(inputAllocation, outputAllocation);

입력 Allocation 은 입력 이미지를 포함해야하고 forEach_saturation 메소드가 완료되면 출력 할당에 수정 된 이미지 데이터가 포함됩니다.

Allocation 인스턴스가 있으면 copyFrom()copyTo() 메서드를 사용하여 해당 Allocations 에서 데이터를 복사 할 수 있습니다. 예를 들어 새로운 이미지를`호출로 할당 '입력에 복사 할 수 있습니다 :

inputAllocation.copyFrom(inputBitmap);

출력에서 copyTo() 를 호출하여 결과 이미지를 검색 할 수있는 것과 같은 방식으로 Allocation :

outputAllocation.copyTo(outputBitmap);

할당 인스턴스 만들기

Allocation 을 만드는 방법에는 여러 가지가 있습니다. 당신은 일단 Allocation 인스턴스를 당신은 그에게 새로운 데이터를 복사 할 수 있습니다 AllocationscopyTo()copyFrom() 위의 설명처럼,하지만 당신은 당신이 정확하게 작업 할 데이터의 종류와 알아야 처음을 만들 수 있습니다. 입력 Allocation 부터 시작합시다.

우리는 정적 메서드 createFromBitmap() 을 사용하여 Bitmap 에서 입력 Allocation 을 신속하게 만들 수 있습니다.

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

이 예제에서는 입력 이미지가 결코 변경되지 않으므로 입력 Allocation 다시 수정할 필요가 없습니다. 새 출력 Bitmap 을 만들기 위해 saturationLevel 변경 될 때마다 다시 사용할 수 있습니다.

출력 Allocation 생성은 좀 더 복잡합니다. 먼저 Type 이라고 불리는 것을 만들어야합니다. Type 얘기하는 데 사용되는 Allocation 이 다루는 데이터의 종류와 있습니다. 일반적으로 Type.Builder 클래스를 사용하여 적절한 Type 을 빠르게 만듭니다. 먼저 코드를 살펴 보겠습니다.

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

우리는 4 컬러 채널을 가진 픽셀 Bitmap 당 일반 32 비트 (또는 다른 말로하면 4 바이트)로 작업하고 있습니다. 이것이 Type 을 생성하기 위해 Element.RGBA_8888 을 선택하는 이유입니다. 그런 다음 setX()setY() 메서드를 사용하여 출력 이미지의 너비와 높이를 입력 이미지와 동일한 크기로 설정합니다. 그런 다음 create() 메서드는 지정한 매개 변수로 Type 을 만듭니다.

올바른 TypecreateTyped() static 메소드 createTyped() 사용하여 출력 Allocation 을 만들 수 있습니다.

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

이제 거의 완료되었습니다. 또한 Output Allocation 에서 데이터를 복사 할 수있는 출력 Bitmap 필요합니다. 이를 위해 정적 메서드 createBitmap() 을 사용하여 입력 Bitmap 과 크기와 구성이 동일한 새 비어있는 Bitmap 을 만듭니다.

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

그리고 그걸로 우리는 RenderScript를 실행하기위한 모든 퍼즐 조각을 가지고 있습니다.

전체 예제

이제이 모든 것을 하나의 예제로 정리해 보겠습니다.

// 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);

결론

이 소개를 통해 간단한 이미지 조작을 위해 자신 만의 RenderScript 커널을 작성해야합니다. 그러나 유의해야 할 몇 가지 사항이 있습니다.

  • RenderScript는 응용 프로그램 프로젝트에서만 작동합니다 . 현재 RenderScript 파일은 라이브러리 프로젝트의 일부가 될 수 없습니다.
  • 메모리 조심 : RenderScript는 매우 빠르지 만 메모리를 많이 소비 할 수도 있습니다. 언제든지 RenderScript 인스턴스가 RenderScript 개 이상 있어서는 안됩니다. 또한 가능한 한 많이 재사용해야합니다. 일반적으로 Allocation 인스턴스를 한 번만 만들어야 나중에 재사용 할 수 있습니다. 출력 Bitmaps 또는 스크립트 인스턴스도 마찬가지입니다. 가능한 한 많이 재사용하십시오.
  • 백그라운드에서 작업하십시오 . 다시 RenderScript는 매우 빠르지 만 어떤 방식 으로든 즉각적이지는 않습니다. 어떤 커널, 특히 복잡한 것들은 AsyncTask 같은 UI 스레드에서 실행되어야합니다. 그러나 대부분의 경우 메모리 누수에 대해 걱정할 필요가 없습니다. 모든 RenderScript 관련 클래스는 응용 프로그램 Context 만 사용하므로 메모리 누수가 발생하지 않습니다. 하지만 당신은 여전히 ​​자신이 사용하는 View , Activity 또는 Context 인스턴스가 누출되는 것과 같은 평범한 것들에 대해 걱정해야합니다!
  • 내장 된 도구 사용 : 이미지 흐리게 처리, 혼합, 변환, 크기 조정과 같은 작업을 수행하는 미리 정의 된 스크립트가 많이 있습니다. 그리고 커널을 구현하는 데 도움이되는 많은 메소드가 내장되어 있습니다. 기회는 당신이 무언가를하고 싶다면 당신이하려는 것을 이미 수행 한 스크립트 나 방법이 있다는 것입니다. 바퀴를 재발 명하지 마십시오.

실제 코드로 빠르게 시작하고 놀고 싶다면이 튜토리얼에서 설명한 정확한 예제를 구현 한 GitHub 프로젝트 예제를 살펴 보는 것이 좋습니다. 여기 에서 프로젝트를 찾을 수 있습니다. RenderScript를 사용해보십시오!

이미지를 흐리게 처리한다.

이 예제에서는 Renderscript API를 사용하여 비트 맵을 사용하여 이미지를 흐리게 표시하는 방법을 보여줍니다. 이 예에서는 Android Renderscript API (API> = 17)에서 제공하는 ScriptInstrinsicBlur 를 사용합니다.

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;
    }
}    

각 스크립트는 데이터를 처리하는 커널을 가지고 있으며 일반적으로 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
    }
}

이것으로 여기 예제를 결론 지었다. 백그라운드 스레드에서 처리하는 것이 좋습니다.

보기 흐리게하기

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;
    }
}

용법:

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
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow