Get a vignette effect by shaders - java

Im trying to create a vignette effect for my app. I've been searching a lot for help achieving this but was unable to find anything.
I recently found this tutorial.
And i tried to implement it in my app with this code:
public int[] drawBitmap(Bitmap originalBitmap){
Bitmap mask;
Paint paint = new Paint();
mask = convertToAlphaMask(BitmapFactory.decodeResource(context.getResources(), R.drawable.spot_mask));
Shader shader = createShader(mask);
paint.setShader(shader);
Bitmap tempBit = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(tempBit);
canvas.drawBitmap(originalBitmap, 0, 0,paint);
tempBit.getPixels(pixels, 0, tempBit.getWidth(), 0, 0, tempBit.getWidth(), tempBit.getHeight());
return pixels;
}
private static Bitmap convertToAlphaMask(Bitmap input) {
Bitmap a = Bitmap.createBitmap(input.getWidth(), input.getHeight(), Bitmap.Config.ALPHA_8);
Canvas c = new Canvas(a);
c.drawBitmap(input, 0.0f, 0.0f, null);
return a;
}
private static Shader createShader(Bitmap b) {
return new BitmapShader(b, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
}
But the effect of this looks like this:(the only change is at the top of the image)
http://postimg.org/image/rrivq28v1/
What have I done wrong?
Also, are there any other alternatives for applying a vignette effect on a bitmap?
Thanks!

After long time i found it
public Bitmap vignett(Bitmap bm, int p){
Bitmap image = Bitmap.createBitmap(bm.getWidth(),bm.getHeight(), Bitmap.Config.ARGB_8888);
int rad;
Canvas canvas = new Canvas(image);
canvas.drawBitmap(bm, 0, 0, new Paint());
if(bm.getWidth()<bm.getHeight()){
int o = (bm.getHeight()*2)/100;
rad = bm.getHeight() - o*p/3;
}else{
int o = (bm.getWidth()*2)/100;
rad = bm.getWidth() - o*p/3;
}
Rect rect = new Rect(0, 0, bm.getWidth(), bm.getHeight());
RectF rectf = new RectF(rect);
int[] colors = new int[] { 0, 0, Color.BLACK };
float[] pos = new float[] { 0.0f, 0.1f, 1.0f };
Shader linGradLR = new RadialGradient(rect.centerX(), rect.centerY(),rad, colors, pos, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(linGradLR);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setAlpha(255);
canvas.drawRect(rectf, paint);
return image;
}
here int p is standard value of seekbar from 1 to 100;
for intensity of effect u can set paint.setAlpha 0 to 255!!!

My first answer got deleted because i pointed to my solution via link. So I'll answer your question right here. The trick is to use 4 linear gradients. Applying them will give you a result that comes pretty close to a true Vignette effect. And it's freaking fast too ;) So here's part of my solution.
First you must create a canvas:
Canvas canvas = new Canvas(bitmapOut);
canvas.drawBitmap(mVignette.getBitmapIn(), 0, 0, null);
Then you define how far the effect should reach into your image:
int tenthLeftRight = (int)(width/5);
int tenthTopBottom = (int)(height/5);
Now you create your four shaders:
// Gradient left - right
Shader linGradLR = new LinearGradient(0, height/2, tenthLeftRight/2, height/2, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
// Gradient top - bottom
Shader linGradTB = new LinearGradient(width/2, 0, width/2, tenthTopBottom, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
// Gradient right - left
Shader linGradRL = new LinearGradient(width, height/2, (width-tenthLeftRight), height/2, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
// Gradient bottom - top
Shader linGradBT = new LinearGradient(width/2, height, width/2, (height - tenthTopBottom), Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
Now all that's left to do is to draw on the canvas:
Paint paint = new Paint();
paint.setShader(linGradLR);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setAlpha(125);
// Rect for Grad left - right
Rect rect = new Rect(0, 0, tenthLeftRight, height);
RectF rectf = new RectF(rect);
canvas.drawRect(rectf, paint);
// Rect for Grad top - bottom
paint.setShader(linGradTB);
rect = new Rect(0, 0, width, tenthTopBottom);
rectf = new RectF(rect);
canvas.drawRect(rectf, paint);
// Rect for Grad right - left
paint.setShader(linGradRL);
rect = new Rect(width, 0, width - tenthLeftRight, height);
rectf = new RectF(rect);
canvas.drawRect(rectf, paint);
// Rect for Grad bottom - top
paint.setShader(linGradBT);
rect = new Rect(0, height - tenthTopBottom, width, height);
rectf = new RectF(rect);
canvas.drawRect(rectf, paint);

Related

createBitmap simple crop android

Code im using:
Bitmap cropImg = Bitmap.createBitmap(bitmap, cropW, cropH, newWidth, newHeight);
Not a java programmer but as i understand it everything is from top left.
my dimensions are
cropW: '696',
cropH: '72',
newWidth: '1200',
newHeight:'1800',
But i end up with the top left of the image..
What i really would like would be like give it 4 points and it takes out the image in the middle.
Im using this as a plugin with Cordova/Phonegap if it makes a difference.
Any help or explanation would be helpful.
Thanks
use Below Function
public Bitmap getCircleBitmap(Bitmap bm) {
int sice = Math.min((bm.getWidth()), (bm.getHeight()));
Bitmap bitmap = ThumbnailUtils.extractThumbnail(bm, sice, sice);
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setFilterBitmap(true);
paint.setColor(color);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawOval(rectF, paint);
//canvas.drawCircle(50, 50, 50, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}

How to cut a circle from a different shapes of bitmap in android

How can i cut a circle from a different shapes of bitmap in android.
I tried this code, but some images are stretched:
public Bitmap getRoundedShape(Bitmap scaleBitmapImage) {
int targetWidth = 240;
int targetHeight = 200;
Bitmap targetBitmap = Bitmap.createBitmap(targetWidth,
targetHeight,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
path.addCircle(((float) targetWidth - 1) / 2,
((float) targetHeight - 1) / 2,
(Math.min(((float) targetWidth),
((float) targetHeight)) / 2),
Path.Direction.CCW);
canvas.clipPath(path);
Bitmap sourceBitmap = scaleBitmapImage;
canvas.drawBitmap(sourceBitmap,new Rect(0, 0, sourceBitmap.getWidth(),
sourceBitmap.getHeight()),
new Rect(0, 0, targetWidth, targetHeight), null);
return targetBitmap;
}
If you want a circular cut of an image, you need to find the largest square that centers the image. Considering this, following line fixes your stretching problem:
Bitmap bitmap = ThumbnailUtils.extractThumbnail(bitmap, radius, radius, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
This method creates a circular cut of the target bitmap:
private Bitmap getCircularBitmap(int radius, Bitmap bitmap) {
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
Bitmap bmp = Bitmap.createBitmap(radius, radius, conf);
Canvas canvas = new Canvas(bmp);
// creates a centered bitmap of the desired size
bitmap = ThumbnailUtils.extractThumbnail(bitmap, radius, radius, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);
RectF rect = new RectF(0, 0, radius, radius);
canvas.drawRoundRect(rect, radius, radius, paint);
return bmp;
}
One approach would be to use a BitmapShader.
The idea is to use a Paint with a BitmapShader to draw a texture using the bitmap. Then you just draw a circle on the canvas.
Here is an excellent example of using the BitmapShader. In this example, a rectangle with rounded corners is drawn, but it could just as easily be a circle.
Android Recipe #1, image with rounded corners

How do i place a water mark image on image that i just took a picture of it in Android?

How do I place a water mark (company logo, image) on an picture I've just taken?
I need to do it on Android.
Can you please help?
You can draw the bitmap to a Canvas, and use the Canvas drawText methods or drawBitmap methods to add text or image. Ex:
drawingCache = Bitmap.createBitmap(300, 400, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(drawingCache);
Paint paint = new Paint();
// Draw your bitmap to the canvas
canvas.drawBitmap(bitmap, 0, 0, paint);
Paint watermarkPaint = new Paint();
watermarkPaint.setColor(Color.WHITE);
watermarkPaint.setAlpha(150);
watermarkPaint.setTextSize(30);
watermarkPaint.setTextAlign(Paint.Align.LEFT);
watermarkPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
canvas.drawText("Watermark", 100, 100, watermarkPaint);
Try this
public static Bitmap mark(Bitmap src) {
int w = src.getWidth();
int h = src.getHeight();
int pw=w-170;
int ph=h-170;
Bitmap result = Bitmap.createBitmap(w, h, src.getConfig());
Canvas canvas = new Canvas(result);
Bitmap resized = Bitmap.createScaledBitmap(src, 150, 150, true);
canvas.drawBitmap(src, 0, 0, null);
Paint paint = new Paint();
paint.setColor(Color.TRANSPARENT);
paint.setAlpha(50);
paint.setTextSize(20);
paint.setAntiAlias(true);
paint.setUnderlineText(false);
canvas.drawBitmap(resized,pw,ph,paint);
return result;
}
You can try using any of these jar's in Android.
Im4Java looks most promising.

setPolyToPoly not applied

Can anyone help me with a graphics issue I am having. This code does not apply the setPolyToPoly at all.. it does the Camera rotation, but not the polyToPoly transformation .. I dont understand why..
final Camera camera = mCamera;
final Matrix matrix = t.getMatrix();
camera.save();
camera.translate(x, y, z);
camera.getMatrix(matrix);
camera.restore();
matrix.setPolyToPoly(sourceArr, 0, destArr, 0, sourceArr.length >> 1);
matrix.preTranslate(-0, -height);
matrix.postTranslate(0, height);
This sample does not fit your question entirely but might put you in the right direction. In this sample a matrix is applied to a bitmap that puts in a perspective. If I compare to your snippet, you do set the polytopoly but it is not applied to the camera.
Bitmap bitmap2 = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
Canvas canvas2 = new Canvas(bitmap2);
canvas2.drawColor(Color.WHITE);
Paint rectPaint2 = new Paint();
rectPaint2.setColor(Color.GREEN);
canvas2.drawRect(20, 20, 180, 180, rectPaint2);
Matrix matrix2 = new Matrix();
float deform2 = 20f;
float[] src2 = new float[] { 0, 0, bitmap2.getWidth(), 0, bitmap2.getWidth(), bitmap2.getHeight(), 0, bitmap2.getHeight() };
float[] dst2 = new float[] { 0, 0, bitmap2.getWidth() - deform2, deform2, bitmap2.getWidth() - deform2, bitmap2.getHeight() - deform2, 0, bitmap2.getHeight() };
matrix2.setPolyToPoly(src2, 0, dst2, 0, src2.length >> 1);
Bitmap bMatrix2= Bitmap.createBitmap(bitmap2, 0, 0, bitmap2.getWidth(), bitmap2.getHeight(), matrix2, true);
ImageView ivSecond = (ImageView) findViewById(R.id.ivSecond);
ivSecond.setImageBitmap(bMatrix2);

How to draw a filled triangle in android canvas?

So I'm drawing this triangle in android maps using the code below in my draw method:
paint.setARGB(255, 153, 29, 29);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setAntiAlias(true);
Path path = new Path();
path.moveTo(point1_returned.x, point1_returned.y);
path.lineTo(point2_returned.x, point2_returned.y);
path.moveTo(point2_returned.x, point2_returned.y);
path.lineTo(point3_returned.x, point3_returned.y);
path.moveTo(point3_returned.x, point3_returned.y);
path.lineTo(point1_returned.x, point1_returned.y);
path.close();
canvas.drawPath(path, paint);
The pointX_returned are the coordinates which I'm getting from the fields. They are basically latitudes and longitudes.
The result is a nice triangle but the insider is empty and therefore I can see the map. Is there a way to fill it up somehow?
Ok I've done it. I'm sharing this code in case someone else will need it:
super.draw(canvas, mapView, true);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(2);
paint.setColor(android.graphics.Color.RED);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setAntiAlias(true);
Point point1_draw = new Point();
Point point2_draw = new Point();
Point point3_draw = new Point();
mapView.getProjection().toPixels(point1, point1_draw);
mapView.getProjection().toPixels(point2, point2_draw);
mapView.getProjection().toPixels(point3, point3_draw);
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
path.moveTo(point1_draw.x,point1_draw.y);
path.lineTo(point2_draw.x,point2_draw.y);
path.lineTo(point3_draw.x,point3_draw.y);
path.lineTo(point1_draw.x,point1_draw.y);
path.close();
canvas.drawPath(path, paint);
//canvas.drawLine(point1_draw.x,point1_draw.y,point2_draw.x,point2_draw.y, paint);
return true;
Thanks for the hint Nicolas!
You probably need to do something like :
Paint red = new Paint();
red.setColor(android.graphics.Color.RED);
red.setStyle(Paint.Style.FILL);
And use this color for your path, instead of your ARGB. Make sure the last point of your path ends on the first one, it makes sense also.
Tell me if it works please !
you can also use vertice :
private static final int verticesColors[] = {
Color.LTGRAY, Color.LTGRAY, Color.LTGRAY, 0xFF000000, 0xFF000000, 0xFF000000
};
float verts[] = {
point1.x, point1.y, point2.x, point2.y, point3.x, point3.y
};
canvas.drawVertices(Canvas.VertexMode.TRIANGLES, verts.length, verts, 0, null, 0, verticesColors, 0, null, 0, 0, new Paint());
Using #Pavel's answer as guide, here's a helper method if you don't have the points but have start x,y and height and width. Also can draw inverted/upside down - which is useful for me as it was used as end of vertical barchart.
private void drawTriangle(int x, int y, int width, int height, boolean inverted, Paint paint, Canvas canvas){
Point p1 = new Point(x,y);
int pointX = x + width/2;
int pointY = inverted? y + height : y - height;
Point p2 = new Point(pointX,pointY);
Point p3 = new Point(x+width,y);
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
path.moveTo(p1.x,p1.y);
path.lineTo(p2.x,p2.y);
path.lineTo(p3.x,p3.y);
path.close();
canvas.drawPath(path, paint);
}
this function shows how to create a triangle from bitmap. That is, create triangular shaped cropped image. Try the code below or download demo example
public static Bitmap getTriangleBitmap(Bitmap bitmap, int radius) {
Bitmap finalBitmap;
if (bitmap.getWidth() != radius || bitmap.getHeight() != radius)
finalBitmap = Bitmap.createScaledBitmap(bitmap, radius, radius,
false);
else
finalBitmap = bitmap;
Bitmap output = Bitmap.createBitmap(finalBitmap.getWidth(),
finalBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
Paint paint = new Paint();
final Rect rect = new Rect(0, 0, finalBitmap.getWidth(),
finalBitmap.getHeight());
Point point1_draw = new Point(75, 0);
Point point2_draw = new Point(0, 180);
Point point3_draw = new Point(180, 180);
Path path = new Path();
path.moveTo(point1_draw.x, point1_draw.y);
path.lineTo(point2_draw.x, point2_draw.y);
path.lineTo(point3_draw.x, point3_draw.y);
path.lineTo(point1_draw.x, point1_draw.y);
path.close();
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(finalBitmap, rect, rect, paint);
return output;
}
The function above returns an triangular image drawn on canvas. Read more
private void drawArrows(Point[] point, Canvas canvas, Paint paint) {
float [] points = new float[8];
points[0] = point[0].x;
points[1] = point[0].y;
points[2] = point[1].x;
points[3] = point[1].y;
points[4] = point[2].x;
points[5] = point[2].y;
points[6] = point[0].x;
points[7] = point[0].y;
canvas.drawVertices(VertexMode.TRIANGLES, 8, points, 0, null, 0, null, 0, null, 0, 0, paint);
Path path = new Path();
path.moveTo(point[0].x , point[0].y);
path.lineTo(point[1].x,point[1].y);
path.lineTo(point[2].x,point[2].y);
canvas.drawPath(path,paint);
}
Don't moveTo() after each lineTo()
In other words, remove every moveTo() except the first one.
Seriously, if I just copy-paste OP's code and remove the unnecessary moveTo() calls, it works.
Nothing else needs to be done.
EDIT: I know the OP already posted his "final working solution", but he didn't state why it works. The actual reason was quite surprising to me, so I felt the need to add an answer.
You need remove path.moveTo after first initial.
Path path = new Path();
path.moveTo(point1_returned.x, point1_returned.y);
path.lineTo(point2_returned.x, point2_returned.y);
path.lineTo(point3_returned.x, point3_returned.y);
path.lineTo(point1_returned.x, point1_returned.y);
path.close();

Categories