Android ScriptIntrinsicBlur не размывает все изображение и генерирует прозрачный Edge
У меня есть некоторые проблемы с RenderScript ScriptIntrinsic Blur - на некоторых устройствах он не размывает весь образ. Я уменьшаю входное изображение и слежу за тем, чтобы ширина была кратной 4 (потому что это предложил Роман Нурик: https://plus.google.com/+RomanNurik/posts/TLkVQC3M6jW)
@SuppressLint("NewApi")
private Bitmap blurRenderScript(Bitmap smallBitmap) {
Bitmap output = Bitmap.createBitmap(smallBitmap.getWidth(), smallBitmap.getHeight(), smallBitmap.getConfig());
RenderScript rs = RenderScript.create(getContext());
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
Allocation inAlloc = Allocation.createFromBitmap(rs, smallBitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_GRAPHICS_TEXTURE);
Allocation outAlloc = Allocation.createFromBitmap(rs, output);
script.setRadius(BLUR_RADIUS);
script.setInput(inAlloc);
script.forEach(outAlloc);
outAlloc.copyTo(output);
rs.destroy();
MutableBitmap.delete(smallBitmap);
return output;
}
Он работает с Nexus 4:
![Nexus 4 before blurring]()
![Nexus 4 after blurring]()
Но на Галактике S4 правая сторона имеет прозрачный край:
![Galaxy S4 before blurring]()
![Galaxy S4 after blurring]()
Надеюсь, вы поймете, что я имею в виду - если вы откроете картинку в gimp или вы увидите ее лучше. Это не зависит от размера изображения. Я также попробовал его с большими и меньшими изображениями, и результат всегда был одинаковым. Это также происходит на Nexus 7 2012, например. Кроме того, прозрачные артефакты иногда находятся на нижнем или левом краю. Заранее благодарим за помощь!
Nexus 4: 4.4.2/Номер сборки KOT49H
Galaxy S4: 4.2.2/номер сборки JDQ39.I9505XXUDMGG
Ответы
Ответ 1
Я не уверен, почему это может сработать, но для меня это было сделано.
Попробуйте вместо
Bitmap output = Bitmap.createBitmap(smallBitmap.getWidth(), smallBitmap.getHeight(), smallBitmap.getConfig());
перейдите в Bitmap.Config.ARGB_8888 так
Bitmap output = Bitmap.createBitmap(smallBitmap.getWidth(), smallBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Ответ 2
Я предполагаю, что вы используете android.renderscript вместо поддержки lib android.v8.rderscript. (или старой поддержки lib?)
Если это правда, то это известная ошибка, которая может быть исправлена только при обновлении системы, что может быть нецелесообразно для пользователей.
Один из способов решения этой проблемы - использовать библиотеку поддержки RenderScript: здесь вы можете найти подробные инструкции: http://developer.android.com/guide/topics/renderscript/compute.html#access-rs-apis
В основном вам просто нужно изменить импорт:
import android.support.v8.renderscript.*;
И настройте свой build.gradle:
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
minSdkVersion 8
targetSdkVersion 19
renderscriptTargetApi 18
renderscriptSupportModeEnabled true
}
}
Есть несколько преимуществ использования поддержки lib:
- Поддержка устройств обратно в API 8.
- Может быть обновлено с помощью Build-Tools, чтобы включить исправления ошибок и обходные пути.
С другой стороны, для достижения этой цели ему необходимо объединить несколько разделяемых библиотек, которые сделают ваше приложение более сильным.
Ответ 3
Мне все еще приходилось работать над тем, чтобы снять эту прозрачность, поэтому я закончил просто обрезать изображение на 25 пикселей после того, как я размыл его. Определенно не идеально, но он работал достаточно хорошо для моего применения ScriptIntrinsicBlur:
output = Bitmap.createBitmap(nbm, 25, 25, bm.getWidth() - 25, bm.getHeight() - 25);
Ответ 4
H! Это для всех людей, которым необходимо увеличить радиус ScriptIntrinsicBlur, чтобы получить более сильное гауссовское размытие.
Вместо того, чтобы поместить радиус более 25, вы можете уменьшить изображение и получить тот же результат. Я написал класс под названием GaussianBlur. Ниже вы можете увидеть, как использовать и всю реализацию класса.
Использование:
GaussianBlur gaussian = new GaussianBlur(context);
gaussian.setMaxImageSize(60);
gaussian.setRadius(25); //max
Bitmap output = gaussian.render(<your bitmap>,true);
Drawable d = new BitmapDrawable(getResources(),output);
Класс:
public class GaussianBlur {
private final int DEFAULT_RADIUS = 25;
private final float DEFAULT_MAX_IMAGE_SIZE = 400;
private Context context;
private int radius;
private float maxImageSize;
public GaussianBlur(Context context) {
this.context = context;
setRadius(DEFAULT_RADIUS);
setMaxImageSize(DEFAULT_MAX_IMAGE_SIZE);
}
public Bitmap render(Bitmap bitmap, boolean scaleDown) {
RenderScript rs = RenderScript.create(context);
if (scaleDown) {
bitmap = scaleDown(bitmap);
}
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
Allocation inAlloc = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_GRAPHICS_TEXTURE);
Allocation outAlloc = Allocation.createFromBitmap(rs, output);
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, inAlloc.getElement()); // Element.U8_4(rs));
script.setRadius(getRadius());
script.setInput(inAlloc);
script.forEach(outAlloc);
outAlloc.copyTo(output);
rs.destroy();
return output;
}
public Bitmap scaleDown(Bitmap input) {
float ratio = Math.min((float) getMaxImageSize() / input.getWidth(), (float) getMaxImageSize() / input.getHeight());
int width = Math.round((float) ratio * input.getWidth());
int height = Math.round((float) ratio * input.getHeight());
return Bitmap.createScaledBitmap(input, width, height, true);
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
public float getMaxImageSize() {
return maxImageSize;
}
public void setMaxImageSize(float maxImageSize) {
this.maxImageSize = maxImageSize;
}
}
;)