Hi everyone, I am new to android dev.
I have an app that will erase part of the bitmap. I am using matrix to scale rotate the image. Without scaling, the transparent eraser is same size with the circle, but when i scale the bitmap the eraser transparent is bigger than the circle size which is fixed. Can someone help me out?.. I am struggling this for 1 week now.
Here's the code I am using:
RectF r = new RectF();
matrix.mapRect(r);
// sol1
float scaledX = (lastX - r.left) + 48; // adjust to the tip of eraser
float scaledY = (lastY - r.top) - 137; // adjust to the tip of eraser
float[] values = new float[9];
matrix.getValues(values);
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;
Bitmap bmOverlay = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(),
Bitmap.Config.ARGB_8888);
System.out.println("bitmap.getWidth() " + bitmap.getWidth() +
" bitmap.getHeight() " + bitmap.getHeight());
Canvas c = new Canvas(bmOverlay);
c.drawColor(Color.TRANSPARENT, Mode.CLEAR);
c.drawBitmap(bitmap, 0, 0, null);
c.drawCircle(scaledX, scaledY, 13.0f, mPaint); // punch a hole
bitmap = bmOverlay; // update the main bitmap
Finally I am able to achieved:
I just comment the below lines :).
// cursor
paintCursorRed.setColor(0xffff0000);
paintCursorRed.setStyle(Style.STROKE);
paintCursorBlackdraw.setColor(0xffffff00);
paintCursorBlackdraw.setStyle(Style.STROKE);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.BEVEL);
mPaint.setStrokeCap(Paint.Cap.SQUARE);
//mPaint.setStrokeWidth(15);
//mPaint.setTextSize(15);
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
mPaint.setAntiAlias(true);
// mPaint.setMaskFilter(new BlurMaskFilter(5, Blur.NORMAL));
Related
When drawing the text though, it gets blurred and not that crisp like when using below code. The only code I've used for the text painting on image can some one help me to solve this issue
code
public static Bitmap drawMultilineTextToBitmap(Context gContext, Bitmap bitmap, String gText) {
// prepare canvas
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
//Bitmap bitmap = BitmapFactory.decodeResource(resources, gResId);
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
// set default bitmap config if none
if (bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
TextPaint paint = new TextPaint(Paint.LINEAR_TEXT_FLAG|Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
paint.setColor(Color.rgb(0, 0, 0));
paint.setFakeBoldText(true);
paint.setTextSize(10);
int textWidth = canvas.getWidth() - (int) (16 * scale);
// init StaticLayout for text
StaticLayout textLayout = new StaticLayout(gText, paint,
canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f,
false);
// get height of multiline text
int textHeight = textLayout.getHeight();
// get position of text's top left corner
float x = (bitmap.getWidth() - textWidth);
float y = (bitmap.getHeight() - textHeight);
// draw text to the Canvas Left
canvas.save();
//canvas.translate(x, y);
canvas.translate((canvas.getWidth() / 2) - (textLayout.getWidth() / 2), y);
textLayout.draw(canvas);
canvas.restore();
return bitmap;
}
image
I guess here:
paint.setAntiAlias(true);
should be false. And two more methods which may relate to this issue:
paint.setAntiAlias(false);
paint.setFilterBitmap(false);
paint.setDither(true);
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.
I am trying to draw a avatar bitmap using this code. But the bitmap is pixelated. Here is my Code. Currently I use createScaledBitmap to resize the avatar image. Also the Text are a little smaller on some devices with a high resolution
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.card_nodpi, opt) ;
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(40);
paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
canvas.drawText("The quick brown fox", x, y, paint);
Paint paint2 = new Paint();
paint2.setColor(Color.BLACK);
paint2.setTextSize(30);
canvas.drawText("The quick brown fox", x, y + (40), paint2);
canvas.drawText("The quick brown fox", x, y + ((40 * 2)), paint2);
if (avatar != null) {
Bitmap img = Bitmap.createScaledBitmap(avatar, 250, 250, false);
canvas.drawBitmap(img, bitmap.getWidth() - img.getWidth() - x, y - 40, new Paint(Paint.FILTER_BITMAP_FLAG));
}
imageView.setImageBitmap(bitmap);
createScaledBitmap can produce some funky/bad quality images.
Try out this solution here:
https://stackoverflow.com/a/7468636/4557530
Let me know if that does anything for you!
Alternatively,
try this, I used this code before thanks to some blog, which I don't remember anymore
Bitmap newBM = Bitmap.createBitmap(newWidth, newHeight, Config.ARGB_8888);
float scaleX = newWidth / (float) origBM.getWidth();
float scaleY = newHeight / (float) origBM.getHeight();
float pivX = 0;
float pivY = 0;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY);
Canvas canvas = new Canvas(newBM);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(origBM, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG));
I want to rotate my text by 180 degrees when drawing it on a bitmap. The bitmap itself could also be rotated as there is nothing else drawn on it other than the text. It isn't clear to me though what I should be using in the code below to rotate the text: ImageView, canvas, paint, bitmap???
ImageView ivImage = (ImageView)findViewById(R.id.ivImage);
DisplayMetrics metrics = getResources().getDisplayMetrics();
int width = metrics.widthPixels;
int height = metrics.heightPixels;
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
Bitmap bitmap = Bitmap.createBitmap(width, height, conf);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
paint.setTextSize((int) (200 * 1));
// draw text to the Canvas center
Rect bounds = new Rect();
paint.setTextAlign(Align.CENTER);
String text = "HELP";
paint.getTextBounds(text, 0, text.length(), bounds);
int x = bitmap.getWidth() / 2; // (bitmap.getWidth() - bounds.width())/2;
int y = bitmap.getHeight() / 2; // (bitmap.getHeight() + bounds.height())/2;
canvas.drawText(text, x * 1, y * 1, paint);
ivImage.setImageBitmap(bitmap);
I hope this could help. This is how i did when creating a clock
// Save canvas in current state
canvas.save();
// Rotate canvas around center and draw
canvas.rotate(degrees, canvasWidth/2, canvasHeigth/2);
canvas.drawText(text, x, y, paint)
// Restore canvas, rotates it back to original
canvas.restore();
Hi, genious!
What's the problem?
I tried to draw text in front of marker. I'm going to get clear bitmap and draw text but bitmap is still clear - where is the text?
I tried to convert View to bitmap but it's also wasn't good idea.
PS: scale >= 1
mMap.addMarker(new MarkerOptions()
.position(new LatLng(56.83789, 60.5986)) .icon(BitmapDescriptorFactory.fromBitmap(drawTextToBitmap(getApplicationContext(), R.drawable.ic_maps_marker,"19"))));
//here I'm trying to draw text bitmap
public static Bitmap drawTextToBitmap(Context gContext,int gResId,String gText) {
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap =
BitmapFactory.decodeResource(resources, gResId);
android.graphics.Bitmap.Config bitmapConfig =
bitmap.getConfig();
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLACK);
paint.setTextSize((int) (14 * scale));
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
Rect bounds = new Rect();
paint.getTextBounds(gText, 0, gText.length(), bounds);
int x = (bitmap.getWidth() - bounds.width())/2;
int y = (bitmap.getHeight() + bounds.height())/2;
canvas.drawText(gText, x * scale, y * scale, paint);
return bitmap;
}
Density was only necessary to determinate the size of the text. To draw text on canvas should not use scale, because of displacements x and y calculated for particular bitmap.
Try this:
canvas.drawText(gText, x, y, paint);
This work on 4 devices: