I need to create a clipping mask with a shape of a circular sector.
I am able to draw one using the following:
paint.setColor(0x88FF0000);
paint.setStyle(Style.FILL);
canvas.drawArc(oval, 0, 30, true, paint);
I want to use it as a clipping path, so I've tried:
Path path = new Path();
path.addArc(oval, 0, 30);
canvas.clipPath(path, Op.REPLACE);
However addArc doesn't have the useCenter parameter so what I get is not a sector but a segment.
Ok, it seems there is no proper way doing this using a clipping mask.
However there is an alternate way using PorterDuffXfermode. See Xfermodes in ApiDemos.
I simply draw a sector using drawArc over my image with the DST_OUT operator. This makes the part of the image covered by the sector invisible (not drawn).
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(0xFFFFFFFF);
paint.setStyle(Style.FILL);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
drawable.draw(canvas);
canvas.drawArc(oval, 30, 90, true, paint);
I needed to tweak the AChartEngine library for Android to turn the pie chart into a donut chart. I needed to replace the following:
canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint);
by using the Path class in order to be able to use clipping. The following code did the job for me:
Path path = new Path();
path.moveTo(oval.centerX(), oval.centerY());
path.addArc(oval, startAngle, sweepAngle);
path.lineTo(oval.centerX(), oval.centerY());
canvas.drawPath(path, paint);
I hope this saves some headaches to people not familiar with the Canvas API as myself.
Related
I want to draw smooth semicircle with drawArc() method. But what I get is:
RectF oval = new RectF(x - cornerRadius, y - cornerRadius, x + cornerRadius,y + cornerRadius);
canvas.drawArc(oval, start, 180, true, cornerPaint);
What's wrong with my code?
The problem has gone after I have created Paint from zero, not copying it from another Paint. Seems like another paint had parameters that affected line shape.
I'm developing my own custom control. It's rectangle with a text inside. Text could be longer then rectangle so I need to cut it. Please help me style clipped text to make it understandable that there is more text. Last characters should have opacity.
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// draw button
paint.setColor(Color.parseColor("#b33232"));
canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
paint.reset();
// draw text
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
paint.setTextSize(16);
canvas.drawText("My very very long text", 5, 24, paint);
paint.reset();
First image is what I have
Second is what I need to get
I think TextUtils.ellipsize is what u want.
Check this..
TextUtils
i create a rectangle in a specific size, and now i want rotate it to 45 degree, i used canvas.rotate, matrix, but not working. how is the proper way to rotate canvas in android? and i'm curios about Path.Direction.CW, is it used for rotation? but i don't see any rotation function in Path()
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setColor(Color.BLUE);
paint.setAlpha(75);
Path path = new Path();
path.addRect(166, 748, 314, 890, Path.Direction.CW);
canvas.rotate(45);
canvas.drawPath(path, paint);
To draw a rotated rectangle you need to rotate the canvas before drawing, (then rotate it back to right-side up if you're drawing anything else). Canvas.rotate() just alters the canvas's transformation matrix, which transforms shapes drawn after the call.
canvas.save();
canvas.rotate(45);
canvas.drawRect(166, 748, 314, 890, paint);
canvas.restore();
Path.Direction has nothing to do with rotation transforms. From the docs:
Specifies how closed shapes (e.g. rects, ovals) are oriented when they
are added to a path.
If you want to draw something from (x,y) point, you have to rotate the canvas around (x,y) point. For doing this you should use
canvas.rotate(45,x,y);
so,
canvas.save();
canvas.rotate(45,x,y);
//all drawing from (x,y) point
canvas.restore();
Proper way should be something like this:
Path path = new Path();
path.addRect(166, 748, 314, 890, Path.Direction.CW);
canvas.save(); // first save the state of the canvas
canvas.rotate(45); // rotate it
canvas.drawPath(path, paint); // draw on it
canvas.restore(); // restore previous state (rotate it back)
So this is what I have for a vignette style effect in Android (image is a Bitmap):
public void vignette() {
float radius = (float) (image.getWidth()/1.5);
RadialGradient gradient = new RadialGradient(image.getWidth()/2, image.getHeight()/2, radius, Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP);
Canvas canvas = new Canvas(image);
canvas.drawARGB(1, 0, 0, 0);
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setShader(gradient);
final Rect rect = new Rect(0, 0, image.getWidth(), image.getHeight());
final RectF rectf = new RectF(rect);
canvas.drawRect(rectf, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(image, rect, rect, paint);
}
This "works" but there are a couple of problems. First of all, this is not really a vignette, it's just a gradient so you can see bits of the black going nearly all the way to the center rather than feathering out closer to the edges.
The RadialGradient used also only allows for setting the radius of a circle rather than an ellipse. An ellipse would be able to more effectively match the dimensions of a non-square image than a circle.
The quality of the gradient is also not superb.
I'm trying to replicate the vignetteImage method from ImageMagick (I'm referring specifically to the php version). I have this code in PHP that produces the style of image that I want:
$im = new IMagick('city.png');
$im->vignetteImage($width/1.5, 350, 20, 20);
I've tried building ImageMagick with the NDK but have been unsuccessful in properly linking the various image libraries (I've only successfully built with gif support but no png, jpeg or tiff).
I've also attached an image comparing the two methods shown above. The image on the left was generated with ImageMagick through php and the image on the right was generated using the method shown above for Android.
If you look carefully at the image on left, tf uses exponential increase in Alpha (transparency) vs. image on right which is very linear.
Clearly Shader.TitleMode.CLAMP is a linear function. What you should do instead is use RadialGradient(float x, float y, float radius, int[] colors, float[] positions, Shader.TileMode tile) to define 10 or more points on the image with exponentially decreasing color values (black to transparent).
Alternatively, you can refer gallery 3d source for ICS gallery http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/4.0.1_r1/com/android/gallery3d/photoeditor/filters/VignetteFilter.java?av=h
I know this is an old discussion but it may help someone.
You can use AccelerateInterpolator to generate the points that Taranfx had mentioned and it will lock awesome.
I'm trying to draw a transparent circle, but it just doesn't work.
when I'm drawing a bitmap it works, but a circle doesn't become transparent.
Here's my code in short:
Paint paint = new Paint();
paint.setAlpha(125);
canvas.drawBitmap(bitmap, sourceRect, destRect, paint); // this works fine
canvas.drawCircle(x, y, radius, paint); // the circle is drawn but not transparent
I found it.
paint.setAlpha must come after paint.setColor