Using the Drawline function to create a "pencil stroke" - android

Ok so I'm making a game and I'm having a problem, that Is I don't have
anyway of going about this, Making a line that looks like a pencil stroke.
I start out with
drawLine(float startX, float startY, float stopX,float stopY, Paint paint);
of course
and then I I use all the stuff involved with Paint() and the paint
class so I set the color and the thickness in the paint...
So What I'm wondering is how do I give my paint a texture that
resembles a pencil stroke. is there a way I can make the paint look
like a repeated bitmap, what are my options with this.
Thanks, Brian
p.s. if you want more detail I can expound on it a little more like
give you the exact code that I'm using and explain more about my
game....
also here are links to the paint class and the canvas class if you
need them.
http://developer.android.com/reference/android/graphics/Paint.html
http://developer.android.com/reference/android/graphics/Canvas.html
Also
void drawBitmap(int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, Paint paint)
Treat the specified array of colors as a bitmap, and draw it."
Can I use that I'm really not sure what its saying.
please even if you have a little information please reply.

"void drawBitmap(int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, Paint paint) Treat the specified array of colors as a bitmap, and draw it." Can I use that I'm really not sure what its saying.
It seems you would want this version of the Canvas.drawBitmap() series of methods: drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint).
Ideally you could make your own texture and either stretch it or tile it.. I'm not sure how to tile, but a link in the "Related" section to the right points at TileMode.REPEAT of class BitmapShader.
If your texture isn't going to have any noise ( or anything else that would distort upon stretching ) you may just want to use Drawable.draw() and use a 9-patch for your pencil-stroke.

Related

Android custom View dimensions and canvas coordinates

I have custom View that should paint a bitmap. I've created a simple line(bmp 1x50 px) to check where will be drawn exactly. In my onDraw(Canvas c) I'm using this line of code:
canvas.drawBitmap(bitmap, 0, 0, paint);
Where paint is simple Paint object, without any fancy settings. The problem is that this line shows at the middle of the view, not on top, as I thought it would be.
I'm setting View properties in layout xml:
<com.example.CustomView
android:id="#+id/costom_view"
android:layout_width="230px"
android:layout_height="188px"
android:layout_marginTop="10px"
custom:srcDraw="#drawable/menu_indicators_level_draw_up" />
This custom property is the ID of the bitmap I use to draw on canvas.
Why won't the View behave properly? And why does my canvas have a size if 800x450 (size of the screen i suppose) and not 230x188 like I defined in the layout?
And very important thing, I want to multiply the same bitmap on this view many times. At the end of work I want to draw this line from bottom to top of my View.
i think what you should use to draw the line above the bitmap is the follwing :
drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
and give it the right coordinates to be drawn on top of the bitmap .
Hope that helps .

Create bitmap mask programmatically

I have this code in onDraw().
radius = drawGmpImage(this.gmpImage, canvas);
canvas.drawCircle(kHorizontalOffset, kScreenVerticalOffset, radius , maskPaint);
drawGmpImage creates a complex graphic which is a circle with many lines drawn on it. It's a library function which I cannot change. The lines are polygons and can extend beyond the circumference of the circle.
The need is to "blank out" everything drawn outside the circle.
This is a port from iOS and the original developers solution is to use a simple bitmap mask, stored as a resource, with a transparent circle which matches the size of the circle drawn. Simply drawing the bitmap over the drawn circle has the desired effect but is not an option on Android as I need to support all possible resolutions and ratios.
Therefore, the canvas.drawCircle() call is the beginning of my attempt to mask out everything outside the circle. It works fine in that a filled circle is drawn over my drawn circle so that the only thing left are the polygon lines outside the drawn circles circumference. Radius is the radius of the drawn circle.
How can I invert this so that I am left with the contents of the circle?
Why is it that you can spend hours working on something, give up, ask the question, then stumble upon the answer 20 minutes later? The joys of life.
Path path = new Path();
path.addCircle(kHorizontalOffset, kScreenVerticalOffset, radius, Path.Direction.CW);
canvas.clipPath(path);
I'd missed the clipPath method which will take any path and use it as a clipping region. Adding my masking circle to the path does exactly what I need.
[EDIT]
This works well, but there is a problem. It doesn't work if hardware acceleration is turned on. I could turn acceleration off, but then I lose a lot of performance in the rest of the draw which is complex.
Here's how I finally solved it:
In onSizeChanged(), create a bitmap mask. I draw a transparent circle in the right place on the bitmap using this paint. The key to is to use a PorterDuffXfermode.
maskPaint = new Paint();
maskPaint.setColor(Color.TRANSPARENT);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
maskPaint.setStyle(Paint.Style.FILL);
then create the bitmap
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
createMask(w,h,this.radius);
}
private void createMask(int w,int h, int radius){
if (mask!=null){mask.recycle();}
mask = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas maskCanvas = new Canvas(mask);
maskCanvas.drawCircle(w, h, radius, maskPaint);
}
Then in onDraw(), I simply draw the mask over the entire view:
#Override
protected void onDraw(Canvas canvas){
// draw the image();
setRadius(drawGmpImage(this.gmpImage, canvas));
canvas.drawCircle(kHorizontalOffset, kScreenVerticalOffset, radius , maskPaint);
// overlay the mask bitmap
if (mask != null) {
canvas.drawBitmap(mask, 0f, 0f, bitmapPaint);
}
If the radius changes, the mask is recreated:
private void setRadius(int radius){
this.radius = radius;
createMask(kHorizontalOffset, kScreenVerticalOffset, radius);
}
I don't know how to achieve this using masks, hence another approach :
you could draw the radius in a specific colour, say black.
Than Floodfill from one of the corners. I ve created a Floodfill algorithm before its not very difficult. You start in the upperleft corner, set that pixel to your desired colo. Then you look at the neighbouring pixels. If they are black, you stop in that direction, if not, you change the colour and look at the neighbouring pixels again.
Good luck

Vignette in Android

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.

Android: DrawText with background contrast

How to "set up" a paint to accomplish the "second" image above?
paint.setColor(Color.BLACK);
canvas.drawText(strValue, x, y, paint);
First Image: text all in black as result of that code above.
Second Image: better constrat to backgroud colors (edited with graphic editor just to illustrate here)
Note that "31" is partially black and partially white (but it could be any other color with a better contrast to red, as "36" could be to blue).
You could draw with PixelXorXfermode.
the only solution I could think of is that first on your onDraw you have a variable Canvas that you equals to the actual one and then you draw your number,
paint.setColor(Color.BLACK);
canvas.drawText(strValue, x, y, paint);
then you draw the red Rect
canvas.drawRect(myRect, redPaint);
then you draw your line
canvas.drawline(mStartX,mStartY, mFinishX, mFinishY, myLinePaint);
and at the very end outside your onDraw, you call a method like this one:
public void myMethod(){
Paint paint = new Paint();
paint.setColor(Color.BLACK);
this.canvas.drawText(strValue, x, y, paint);
//here you will define the area that you will mark as dirty
//(wich can have the same values as your red Rect)
Rect myRect = new Rect();
myRect.set(x0,y0,x1,y1);
//and finally here you invalidate ONLY the red area
this.canvas.invalidate(myRect);
}
Note: this will require that on your onDraw you verify that the global Canvas is not null
and if so, then you equals your global to the actual.
I'm not sure if this will actually work, however is the only solution I could think of doing so.
PixelXorXfermode is not good method when AntiAlias is set.
if you can get the red rectangle, I think use canvas.clipRect is better. like this
textpaint.setColor(black);
canvas.drawText(str,x,y,textpaint);
Rect oldClipRect = canvas.getClipBounds();
canvas.clipRect(rcRed,Op.REPLACE);
textpaint.setColor(white);
canvas.drawText(str,x,y,textpaint);
canvas.clipRect(oldclipRect,Op.REPLACE);

Android Bitmap Drawing

Can you draw a Bitmap to a Canvas by telling it to draw Bitmap's X,Y at Canvas' X1,Y1? Rather than drawing Bitmap's 0,0 at Canvas X1, Y1?
That's truly possible the Canvas.drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) is here to help. You can specify src region to draw. Look at Canvas docs for more.
Also you may use Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height) to extract that part of original image you want to render. Then just render extracted Bitmap as ususal. More info about the method is available on Google's docs.

Categories

Resources