In my custom views OnDraw method I draw a Bitmap to the center of the Canvas with
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect r = canvas.getClipBounds();
displayWidth = r.right;
displayHeight = r.bottom;
camera.applyToCanvas(canvas);
float zW = (float)bitmapWidth / (float)displayWidth;
float zH = (float)bitmapHeight / (float)displayHeight;
float z = 0.0f;
if (zW>1 || zH>1) {
z = Math.max(zW, zH);
}
canvas.drawColor(Color.DKGRAY);
canvas.drawBitmap(bitmap, (displayWidth/2.0f - (bitmapWidth)/2.0f), (displayHeight/2.0f - bitmapHeight/2.0f), paint);
if (z>0) {
camera.translate(z, -z, z);
}
}
If the Bitmap is larger in height or width is larger then Canvas size (displayWidth, displayHeight), how can I use the Camera class to autozoom to fit the Bitmap and center it to the Canvas. Any ideas?
Try to create a Matrix instance and initialize it using
public boolean setRectToRect (RectF src, RectF dst, Matrix.ScaleToFit stf)
You need to do this only once and keep the matrix in memory. Note that Matrix.ScaleToFit define the CENTER value.
Later when you draw the bitmap use this version of the drawBitmap:
public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)
Related
I'm developing a custom view and I need to draw drawables inside.
Those drawable must have their position relative.
Here is my code :
#Override
protected void onDraw(Canvas canvas) {
//drawBackground(canvas);
float height = (float) getHeight();
float width = (float) getWidth();
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(width, height);
drawFlowChart(canvas);
drawDrawables(canvas);
canvas.restore();
}
private void drawDrawables(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
Resources res = getResources();
Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.motor);
canvas.drawBitmap(bitmap, 0.51f, 0.35f, null);
canvas.restore();
}
But it draw nothing.
Any idea ?
I tried to use the drawBitmap(bitmap, src, dest, paint) but I don't know how to position my bitmap with relative position with this definition.
May be getHeight() and getWidth() function that you call in onDraw return 0 so that canvas scaled and nothing to see.
You can refer two that link to update width and height of canvas to draw:
Android getWidth() return 0 in View's onDraw
Android: How to get a custom View's height and width?
I want to diasplay image(bitmap) in SurfaceView using Canvas. My requirement is that size of the canvas greater than image.I need space(eg:10 dp) in each side of the image in Canvas. How I can scale this?
Thanks
Mikahail
You can draw rectangle of desired Canvas size, and then draw your image with parameters (11, 11) which will draw it 10px from corner for each dimension.
Put this method in your SurfaceView Class :D
public void draw(Canvas canvas) {
final float scaleFactoryX = getWidth() / (WIDTH * 1.f);
final float scaleFactoryY = getHeight() / (HEIGHT * 1.f);
if (canvas != null) {
final int savedState = canvas.save();
canvas.scale(scaleFactoryX, scaleFactoryY);
canvas.restoreToCount(savedState);
}
}
Does anyone know how to make the radius of the circle be fixed although other stuff in the same canvas be scaled. I don't really know how to get the scale factor of the circle dynamically. Thanks
Canvas c = new Canvas(image);
c.drawColor(Color.TRANSPARENT, Mode.CLEAR);
c.drawBitmap(bm, 0, 0, null);
c.drawCircle(cx, cy, radius, mPaint);
Canvas c = new Canvas(image); // This image has a matrix that every time I scaled on the image the cursor will also change. I want the cursor size to stay as 13.0f.
Code:
public void draw(Canvas canvas, Paint paint) { //This is access from the main onDraw();
paint.setColorFilter(colorFilter);
// scaled bitmap base on the scaling of the bitmap
canvas.drawBitmap(bitmap, matrix, paint);
if(activateCursor == true){
if(isTouched == true && ActivityMainEditor.IS_ERASING == true){
RectF r = new RectF();
matrix.mapRect(r);
// sol1
float scaledX = (lastX - r.left) + 48;
float scaledY = (lastY - r.top) - 137;
float[] values = new float[9];
matrix.getValues(values);
// mScalingFactor shall contain the scale/zoom factor
float scalex = values[Matrix.MSCALE_X];
float skewy = values[Matrix.MSKEW_Y];
float scale = (float) Math.sqrt(scalex * scalex + skewy * skewy);
scaledX /= scale;
scaledY /= scale;
// cursor adjustment
I have used this lines to make the circle radius will always be the same although scaling the bitmap, but it's not accurate when not scaled yet is okay but when scaled bigger the cursor will got bigger also.
float scaleCursor = (float) Math.sqrt((scalex - 5) * (scalex - 5) + (skewy - 2) * (skewy - 2));
float cursorSize = (13.0f / scaleCursor); // 13.0f fixed circle radius
drawACircle(canvas, bitmap, scaledX, scaledY, cursorSize);
}
}
}
private Bitmap drawACircle(Canvas c, Bitmap bm, float cx, float cy, float radius)
{
Bitmap bmOverlay = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
Canvas cd = new Canvas(bmOverlay);
cd.drawColor(Color.TRANSPARENT, Mode.CLEAR);
cd.drawBitmap(bm, 0, 0, null);
// the line in which the circle will also get scaled :(
cd.drawCircle(cx, cy, radius, mPaint);
// update the main bitmap
bitmap = bmOverlay;
if(saveNow == true){
imageHistory.add(bitmap);
saveNow = false;
}
return bmOverlay;
}
It's simple:
c.scale(x,y); // scales the whole canvas (preconcat the matrix with the scale factor)
c.save(); // saves this matrix
// Do all your drawing here except the `drawCircle`.
c.restore(); // restores the original matrix
c.drawCircle(cx, cy, radius, mPaint);
Once you call restore(), the matrix is returned to the original one. You can now draw the circle in the normal fashion.
UPDATE:
Make x and y as fields in the CustomView, that way you can modify them outside the onDraw method. So in the onTouch or onTouchEvent, you can modify the x and y and call invalidate(). This will call onDraw and here it will scale. This will get you what you are looking for. In case of global scaling, always go with the canvas.scale() rather than scaling individual draw elements. This will keep things simple.
please help me to draw a text with rounded rectangle as background. I have to draw many texts on a canvas and the text has rounded background. SO what I am trying is to write a function "createTextBitmap" which return a bitmap image so that we can draw image(which return by the function) on a main canvas.
the 'createTextBitmap'function can return a created bitmap, the bitmap image is the one,which contains the text with rounded edge background...
i have tried one, which gives below.
private Bitmap ProcessingBitmap(String text,Paint paint, boolean lastPoint){
Bitmap bm1 = null;
Bitmap newBitmap = null;
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
float width = bounds.width();
float height =bounds.height();
float radius;
if (width > height){
radius = height/4;
}else{
radius = width/4;
}
Paint paint1 = new Paint();
paint1.setColor(Color.GREEN);
paint1.setStrokeWidth(5);
paint1.setStyle(Paint.Style.FILL);
float center_x, center_y;
center_x = width/4;
center_y = height/4;
final RectF rect = new RectF();
rect.set(center_x - radius,
center_y - radius,
center_x + radius,
center_y + radius);
Canvas canvas2 = new Canvas();
canvas2.drawRoundRect(rect, 0, 0, paint);
canvas2.drawText(text, 0, 0, paint);
return newBitmap;
}
and my question is How can we convert this canvas2 to a bitmap image? and image has the size of text bounds,
which look like
to convert your canvas into bitmap please do the following :
public Bitmap convertCanvasToBitmap(int width , int height) {
Bitmap drawnBitmap = null;
try {
drawnBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
Canvas canvas = new Canvas(drawnBitmap);
// now draw anything you want to the canvas
} catch (Exception e) {
e.printStackTrace();
}
return drawnBitmap;
}
so the idea is just pass the bitmap to the canvas , draw with the canvas it will be drawn into your bitmap .
and please refer to this answer here to see how to deal with the text size in the bitmap .
and please give me some feedback
Hope that helps .
you can create a bitmap, then call draw on that bitmap, something like this:
newBitmap = Bitmap.createBitmap(rect.width, rect.height, Bitmap.Config.ARGB_8888);
Canvas canvas2 = new Canvas(newBitmap);
I need to rotate an ImageView by a few degrees. I'm doing this by subclassing ImageView and overloading onDraw()
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.scale(0.92f,0.92f);
canvas.translate(14, 0);
canvas.rotate(1,0,0);
super.onDraw(canvas);
canvas.restore();
}
The problem is that the image that results shows a bunch of jaggies.
http://img.skitch.com/20100608-gmdy4sexsm1c71di9rgiktdjhu.png
How can I antialias an ImageView that I need to rotate in order to eliminate jaggies? Is there a better way to do this?
If you know that your Drawable is a BitmapDrawable, you can use anti-aliasing in the bitmap's Paint to do something like the following:
/**
* Not as full featured as ImageView.onDraw(). Does not handle
* drawables other than BitmapDrawable, crop to padding, or other adjustments.
*/
#Override
protected void onDraw(Canvas canvas) {
final Drawable d = getDrawable();
if( d!=null && d instanceof BitmapDrawable && ((BitmapDrawable)d).getBitmap()!=null ) {
final Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
final int paddingLeft = getPaddingLeft();
final int paddingTop = getPaddingTop();
canvas.save();
// do my rotation and other adjustments
canvas.scale(0.92f,0.92f);
canvas.rotate(1,0,0);
if( paddingLeft!=0 )
canvas.translate(paddingLeft,0);
if( paddingTop!=0 )
canvas.translate(0,paddingTop);
canvas.drawBitmap( ((BitmapDrawable)d).getBitmap(),0,0,p );
canvas.restore();
}
}
Set antialias and filterBitmap to the paint that draw's the bitmap.
I had a similar problem and this worked for me:
Paint bitmapPaint = new Paint();
bitmapPaint.setAntiAlias(true);
bitmapPaint.setFilterBitmap(true);
I did the following to get it to work:
In AndroidManifest.xml I enabled hardware-acceleration <application android:hardwareAccelerated="true">.
Instead of using a custom draw-method, I changed the layer-type of the parent-view to hardware-accelerated with anti-aliasing enabled and added my subviews as follows:
Paint layerPaint = new Paint();
layerPaint.setAntiAlias(true);
layerPaint.setFilterBitmap(true);
layerPaint.setDither(true);
RelativeLayout parentLayout = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.myLayout, null);
parentLayout.setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint);
parentLayout.addView(myChildView);
I have to add that clipping cannot be disabled when using this approach.
This rotation solves just one part of problem - jagged edges, but the image instead became wierd.
ifound only one solution yet:
in ondraw or dispatch draw method
Bitmap bmp = ((BitmapDrawable)image.getDrawable()).getBitmap();
double scale = (0.0+bmp.getWidth()+40.0)/getWidth();
if (scale > 1){
bmp = Bitmap.createScaledBitmap(bmp, getWidth()-40, (int) (bmp.getHeight()/scale), true);
}
canvas.drawColor(Color.TRANSPARENT);
canvas.save();
canvas.translate(20, yShift);
int left = borderSize;
int top = borderSize;
int right = bmp.getWidth() - borderSize;
int bottom = bmp.getHeight() - borderSize;
if(showText){
mPaint.setColor(Color.WHITE);
canvas.rotate(getAngel());
canvas.drawRect(left, top, right, bottom, mPaint);
canvas.translate(0,0);
textFrame.draw(canvas);
}else{
// rotaed bitmap
mMatrix.setRotate(getAngel());
// draw bitmap after creation of new rotated bitmap from rotated matrix
canvas.drawBitmap(Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mMatrix, true)
, 0, 0, mPaint);
}
canvas.restore();
#Primoz990's solution worked for me :) I also enabled Dithering, so my final code which removes the jagged edges on rotation is this:
Paint bitmapPaint = new Paint();
bitmapPaint.setAntiAlias(true);
bitmapPaint.setFilterBitmap(true);
bitmapPaint.setDither(true);