I am trying to make the bottom part of an Image blur for the view on top it like in the image.
I tried blurring it using Rendenscript but I am not able to blur only
The following code will blur out left and right sides of image using the following:
Inside ViewPictureActivity:
private void applyBlur(final ImageView image) {
image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
image.getViewTreeObserver().removeOnPreDrawListener(this);
image.buildDrawingCache();
Bitmap bmp = image.getDrawingCache();
blur(bmp, image);
return true;
}
});
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void blur(Bitmap bkg, View view) {
float radius = 20;
Bitmap overlay = Bitmap.createBitmap((int) (view.getMeasuredWidth()),
(int) (view.getMeasuredHeight()), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(overlay);
canvas.translate(-view.getLeft(), -view.getTop());
canvas.drawBitmap(bkg, 100, 0,null);
canvas.drawBitmap(bkg, -95,0,null);
RenderScript rs = RenderScript.create(getApplicationContext());
Allocation overlayAlloc = Allocation.createFromBitmap(
rs, overlay);
ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(
rs, overlayAlloc.getElement());
blur.setInput(overlayAlloc);
blur.setRadius(radius);
blur.forEach(overlayAlloc);
overlayAlloc.copyTo(overlay);
view.setBackground(new BitmapDrawable(
getResources(), overlay));
rs.destroy();
}//end blur
Add this class to your project:
public class ZoomableImageView extends android.support.v7.widget.AppCompatImageView
{
Matrix matrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int CLICK = 3;
int mode = NONE;
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 4f;
float[] m;
float redundantXSpace, redundantYSpace;
float width, height;
float saveScale = 1f;
float right, bottom, origWidth, origHeight, bmWidth, bmHeight;
ScaleGestureDetector mScaleDetector;
Context context;
public ZoomableImageView(Context context, AttributeSet attr)
{
super(context, attr);
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
mScaleDetector.onTouchEvent(event);
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction())
{
//when one finger is touching
//set the mode to DRAG
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
break;
//when two fingers are touching
//set the mode to ZOOM
case MotionEvent.ACTION_POINTER_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = ZOOM;
break;
//when a finger moves
//If mode is applicable move image
case MotionEvent.ACTION_MOVE:
//if the mode is ZOOM or
//if the mode is DRAG and already zoomed
if (mode == ZOOM || (mode == DRAG && saveScale > minScale))
{
float deltaX = curr.x - last.x;// x difference
float deltaY = curr.y - last.y;// y difference
float scaleWidth = Math.round(origWidth * saveScale);// width after applying current scale
float scaleHeight = Math.round(origHeight * saveScale);// height after applying current scale
//if scaleWidth is smaller than the views width
//in other words if the image width fits in the view
//limit left and right movement
if (scaleWidth < width)
{
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
//if scaleHeight is smaller than the views height
//in other words if the image height fits in the view
//limit up and down movement
else if (scaleHeight < height)
{
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
}
//if the image doesnt fit in the width or height
//limit both up and down and left and right
else
{
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
//move the image with the matrix
matrix.postTranslate(deltaX, deltaY);
//set the last touch location to the current
last.set(curr.x, curr.y);
}
break;
//first finger is lifted
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
// second finger is lifted
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true;
}
});
}
@Override
public void setImageBitmap(Bitmap bm)
{
super.setImageBitmap(bm);
bmWidth = bm.getWidth();
bmHeight = bm.getHeight();
}
public void setMaxZoom(float x)
{
maxScale = x;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
{
@Override
public boolean onScaleBegin(ScaleGestureDetector detector)
{
mode = ZOOM;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector)
{
float mScaleFactor = detector.getScaleFactor();
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale)
{
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
}
else if (saveScale < minScale)
{
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
if (origWidth * saveScale <= width || origHeight * saveScale <= height)
{
matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
if (mScaleFactor < 1)
{
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1)
{
if (Math.round(origWidth * saveScale) < width)
{
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
else
{
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
}
}
}
}
else
{
matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
}
return true;
}
}
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
//Fit to screen.
float scale;
float scaleX = width / bmWidth;
float scaleY = height / bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
saveScale = 1f;
// Center the image
redundantYSpace = height - (scale * bmHeight) ;
redundantXSpace = width - (scale * bmWidth);
redundantYSpace /= 2;
redundantXSpace /= 2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = width - 2 * redundantXSpace;
origHeight = height - 2 * redundantYSpace;
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
setImageMatrix(matrix);
}
}
I used the following layout to display the image:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.yourpackagename">
<com.example.yourpackagename.ZoomableImageView
android:id="@+id/zivImage"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Using the code in your ViewPictureActivity:
ZoomableImageView zifImage = findViewById(R.id.zivImage);
zifImage.setImageBitmap(HelperClass.clientImageBitmap);
applyBlur(zifImage);
Code used in this answer is taken from above answer and modified.
Hope this helps.
Add these two classes to your app,
1> BlurKit.Java
public class BlurKit {
private static BlurKit instance;
private RenderScript rs;
public static void init(Context context) {
if (instance != null) {
return;
}
instance = new BlurKit();
instance.rs = RenderScript.create(context);
}
public Bitmap blur(Bitmap src, int radius) {
final Allocation input = Allocation.createFromBitmap(rs, src);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius(radius);
script.setInput(input);
script.forEach(output);
}
output.copyTo(src);
return src;
}
public Bitmap blur(View src, int radius) {
Bitmap bitmap = getBitmapForView(src, 1f);
return blur(bitmap, radius);
}
public Bitmap fastBlur(View src, int radius, float downscaleFactor) {
Bitmap bitmap = getBitmapForView(src, downscaleFactor);
return blur(bitmap, radius);
}
private Bitmap getBitmapForView(View src, float downscaleFactor) {
Bitmap bitmap = Bitmap.createBitmap(
(int) (src.getWidth() * downscaleFactor),
(int) (src.getHeight() * downscaleFactor),
Bitmap.Config.ARGB_4444
);
Canvas canvas = new Canvas(bitmap);
Matrix matrix = new Matrix();
matrix.preScale(downscaleFactor, downscaleFactor);
canvas.setMatrix(matrix);
src.draw(canvas);
return bitmap;
}
public static BlurKit getInstance() {
if (instance == null) {
throw new RuntimeException("BlurKit not initialized!");
}
return instance;
}
}
2> BlurLayout.Java
public class BlurLayout extends FrameLayout {
public static final float DEFAULT_DOWNSCALE_FACTOR = 0.12f;
public static final int DEFAULT_BLUR_RADIUS = 12;
public static final int DEFAULT_FPS = 60;
// Customizable attributes
/** Factor to scale the view bitmap with before blurring. */
private float mDownscaleFactor;
/** Blur radius passed directly to stackblur library. */
private int mBlurRadius;
/** Number of blur invalidations to do per second. */
private int mFPS;
// Calculated class dependencies
/** Reference to View for top-parent. For retrieval see {@link #getActivityView() getActivityView}. */
private WeakReference<View> mActivityView;
public BlurLayout(Context context) {
super(context, null);
}
public BlurLayout(Context context, AttributeSet attrs) {
super(context, attrs);
BlurKit.init(context);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.BlurLayout,
0, 0);
try {
mDownscaleFactor = a.getFloat(R.styleable.BlurLayout_downscaleFactor, DEFAULT_DOWNSCALE_FACTOR);
mBlurRadius = a.getInteger(R.styleable.BlurLayout_blurRadius, DEFAULT_BLUR_RADIUS);
mFPS = a.getInteger(R.styleable.BlurLayout_fps, DEFAULT_FPS);
} finally {
a.recycle();
}
if (mFPS > 0) {
Choreographer.getInstance().postFrameCallback(invalidationLoop);
}
}
/** Choreographer callback that re-draws the blur and schedules another callback. */
private Choreographer.FrameCallback invalidationLoop = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
invalidate();
Choreographer.getInstance().postFrameCallbackDelayed(this, 1000 / mFPS);
}
};
/**
* {@inheritDoc}
*/
@Override
public void invalidate() {
super.invalidate();
Bitmap bitmap = blur();
if (bitmap != null) {
setBackground(new BitmapDrawable(bitmap));
}
}
/**
* Recreates blur for content and sets it as the background.
*/
private Bitmap blur() {
if (getContext() == null) {
return null;
}
// Check the reference to the parent view.
// If not available, attempt to make it.
if (mActivityView == null || mActivityView.get() == null) {
mActivityView = new WeakReference<>(getActivityView());
if (mActivityView.get() == null) {
return null;
}
}
// Calculate the relative point to the parent view.
Point pointRelativeToActivityView = getPositionInScreen();
// Set alpha to 0 before creating the parent view bitmap.
// The blur view shouldn't be visible in the created bitmap.
setAlpha(0);
// Screen sizes for bound checks
int screenWidth = mActivityView.get().getWidth();
int screenHeight = mActivityView.get().getHeight();
// The final dimensions of the blurred bitmap.
int width = (int) (getWidth() * mDownscaleFactor);
int height = (int) (getHeight() * mDownscaleFactor);
// The X/Y position of where to crop the bitmap.
int x = (int) (pointRelativeToActivityView.x * mDownscaleFactor);
int y = (int) (pointRelativeToActivityView.y * mDownscaleFactor);
// Padding to add to crop pre-blur.
// Blurring straight to edges has side-effects so padding is added.
int xPadding = getWidth() / 8;
int yPadding = getHeight() / 8;
// Calculate padding independently for each side, checking edges.
int leftOffset = -xPadding;
leftOffset = x + leftOffset >= 0 ? leftOffset : 0;
int rightOffset = xPadding;
rightOffset = x + getWidth() + rightOffset <= screenWidth ? rightOffset : screenWidth - getWidth() - x;
int topOffset = -yPadding;
topOffset = y + topOffset >= 0 ? topOffset : 0;
int bottomOffset = yPadding;
bottomOffset = y + height + bottomOffset <= screenHeight ? bottomOffset : 0;
// Create parent view bitmap, cropped to the BlurLayout area with above padding.
Bitmap bitmap;
try {
bitmap = getDownscaledBitmapForView(
mActivityView.get(),
new Rect(
pointRelativeToActivityView.x + leftOffset,
pointRelativeToActivityView.y + topOffset,
pointRelativeToActivityView.x + getWidth() + Math.abs(leftOffset) + rightOffset,
pointRelativeToActivityView.y + getHeight() + Math.abs(topOffset) + bottomOffset
),
mDownscaleFactor
);
} catch (NullPointerException e) {
return null;
}
// Blur the bitmap.
bitmap = BlurKit.getInstance().blur(bitmap, mBlurRadius);
//Crop the bitmap again to remove the padding.
bitmap = Bitmap.createBitmap(
bitmap,
(int) (Math.abs(leftOffset) * mDownscaleFactor),
(int) (Math.abs(topOffset) * mDownscaleFactor),
width,
height
);
// Make self visible again.
setAlpha(1);
// Set background as blurred bitmap.
return bitmap;
}
/**
* Casts context to Activity and attempts to create a view reference using the window decor view.
* @return View reference for whole activity.
*/
private View getActivityView() {
Activity activity;
try {
activity = (Activity) getContext();
} catch (ClassCastException e) {
return null;
}
return activity.getWindow().getDecorView().findViewById(android.R.id.content);
}
/**
* Returns the position in screen. Left abstract to allow for specific implementations such as
* caching behavior.
*/
private Point getPositionInScreen() {
return getPositionInScreen(this);
}
/**
* Finds the Point of the parent view, and offsets result by self getX() and getY().
* @return Point determining position of the passed in view inside all of its ViewParents.
*/
private Point getPositionInScreen(View view) {
if (getParent() == null) {
return new Point();
}
ViewGroup parent;
try {
parent = (ViewGroup) view.getParent();
} catch (Exception e) {
return new Point();
}
if (parent == null) {
return new Point();
}
Point point = getPositionInScreen(parent);
point.offset((int) view.getX(), (int) view.getY());
return point;
}
/**
* Users a View reference to create a bitmap, and downscales it using the passed in factor.
* Uses a Rect to crop the view into the bitmap.
* @return Bitmap made from view, downscaled by downscaleFactor.
* @throws NullPointerException
*/
private Bitmap getDownscaledBitmapForView(View view, Rect crop, float downscaleFactor) throws NullPointerException {
View screenView = view.getRootView();
int width = (int) (crop.width() * downscaleFactor);
int height = (int) (crop.height() * downscaleFactor);
if (screenView.getWidth() <= 0 || screenView.getHeight() <= 0 || width <= 0 || height <= 0) {
throw new NullPointerException();
}
float dx = -crop.left * downscaleFactor;
float dy = -crop.top * downscaleFactor;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(bitmap);
Matrix matrix = new Matrix();
matrix.preScale(downscaleFactor, downscaleFactor);
matrix.postTranslate(dx, dy);
canvas.setMatrix(matrix);
screenView.draw(canvas);
return bitmap;
}
/**
* Sets downscale factor to use pre-blur.
* See {@link #mDownscaleFactor}.
*/
public void setDownscaleFactor(float downscaleFactor) {
this.mDownscaleFactor = downscaleFactor;
invalidate();
}
/**
* Sets blur radius to use on downscaled bitmap.
* See {@link #mBlurRadius}.
*/
public void setBlurRadius(int blurRadius) {
this.mBlurRadius = blurRadius;
invalidate();
}
/**
* Sets FPS to invalidate blur with.
* See {@link #mFPS}.
*/
public void setFPS(int fps) {
this.mFPS = fps;
}
}
in XML file:
<FrameLayout
android:id="@+id/fl_uploadedView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/_10sdp">
<ImageView
android:id="@+id/dv_uploadedPic"
android:layout_width="match_parent"
android:layout_height="@dimen/_150sdp"
android:contentDescription="@string/app_name"
android:scaleType="centerCrop"
android:src="@color/gray" />
<BlurLayout
android:id="@+id/ll_blurView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom">
<TextView
android:id="@+id/tv_fileName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:padding="@dimen/_5sdp"
android:textSize="@dimen/_10sdp"
/>
</BlurLayout>
</FrameLayout>
Do not forget to add this to values > attr.xml
<!--
Blur Layout start
-->
<declare-styleable name="BlurLayout">
<attr name="downscaleFactor" format="float" />
<attr name="blurRadius" format="integer" />
<attr name="fps" format="integer" />
</declare-styleable>
<!--
Blur Layout end
-->
This can be achieved in following steps:
Extract the background image of LinearLayout by cropping background Image. Now extend LinearLayout Class.
Override OnDraw(Canvas mCanvas) method.
Create two methods in your Custom LinearLayout Class:
First call the DrawBitmap function by giving the offset you got from ViewPager to background image so that image moves when the use swipe the screen.
Finally draw the color with your transparency level
I hope this will solve your problem.
Sample Code for this
How to Blur a View
Try applyBlur
method:
private void applyBlur(ImageView image) {
image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
image.getViewTreeObserver().removeOnPreDrawListener(this);
image.buildDrawingCache();
Bitmap bmp = image.getDrawingCache();
blur(bmp, text);
return true;
}
});
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void blur(Bitmap bkg, View view) {
long startMs = System.currentTimeMillis();
float radius = 20;
Bitmap overlay = Bitmap.createBitmap((int) (view.getMeasuredWidth()),
(int) (view.getMeasuredHeight()), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(overlay);
canvas.translate(-view.getLeft(), -view.getTop());
canvas.drawBitmap(bkg, 0, 0, null);
RenderScript rs = RenderScript.create(getActivity());
Allocation overlayAlloc = Allocation.createFromBitmap(
rs, overlay);
ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(
rs, overlayAlloc.getElement());
blur.setInput(overlayAlloc);
blur.setRadius(radius);
blur.forEach(overlayAlloc);
overlayAlloc.copyTo(overlay);
view.setBackground(new BitmapDrawable(
getResources(), overlay));
rs.destroy();
}