Freehand Image Crop draw inside bitmap region - android

Trying to achieve freehand cropping of an image, so I'm able to draw on the image. But it goes outside bitmap region. I just wanna restrict that user can only draw inside bitmap region, check below screen shot.
I am trying to implement functionality like Photoshop lasso tool.
Its drawing outside view region, which generates incorrect output.
Output
Code#
onDraw
public void onDraw(Canvas canvas) {
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, rect, rect, null);
// RectF r = new RectF();
// Matrix matrix = new Matrix();
// matrix.mapRect(r);
// Log.i(TAG, "Rect " + r.left + " " + r.top + " " + r.right + " " +
// r.bottom + " ");
// canvas.clipRect(r.left, r.top, r.right, r.bottom);
Path path = new Path();
boolean first = true;
for (int i = 0; i < points.size(); i += 2) {
Point point = points.get(i);
if (first) {
first = false;
path.moveTo(point.x, point.y);
} else if (i < points.size() - 1) {
Point next = points.get(i + 1);
path.quadTo(point.x, point.y, next.x, next.y);
} else {
mlastpoint = points.get(i);
path.lineTo(point.x, point.y);
}
}
canvas.drawPath(path, paint);
}
onCrop
Bitmap resultingImage = Bitmap.createBitmap(widthOfscreen,heightOfScreen, bitmap1.getConfig());
Canvas canvas = new Canvas(resultingImage);
Paint paint = new Paint();
paint.setAntiAlias(true);
Path path = new Path();
for (int i = 0; i < SomeView.points.size(); i++) {
path.lineTo(SomeView.points.get(i).x, SomeView.points.get(i).y);
}
// path.lineTo(150, 0);
// path.lineTo(230, 120);
// path.lineTo(70, 120);
// path.lineTo(150, 0);
canvas.drawPath(path, paint);
if(crop){
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
}else{
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));
}
suggest me to achieve my goal.

late answer but use full for other u can override onmeasure method and set your image bitmap width and height in that method and resize your canvas so now you can draw only in your canvas.so your image come center.it for drawpath only on your bitmap.
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
height = bitmap.getHeight();
width = bitmap.getWidth();
setMeasuredDimension(width,height);
}
and then change in your oncrop method so you can slove it esaly.
Bitmap resultingImage = Bitmap.createBitmap(yourbitmap.getwidth(),yourbitmap.getheight(), yourbitmap.getConfig());

There is one way to achieve your goal..
Follow below steps:
1) Make one image like as inside part of crop image should be transparent and outside part should be background of canvas check below Image.
2) Draw that image on top of your canvas.
3) Draw anything on your canvas and drawagain that image on top of the canvas.
Image:

You can ignore all Touch Events that are outside your image view. Remember the last event location that is inside your image view and connect it with the next event location that is inside the view. This should work when both events are part of a single movement (without lifting your finger), but it might be more complicated when the drawing is done outside your view and then a new drawing starts inside. Try to cover this case too.

Related

Canvas draw color inside drawable. Dont touch transparent part of image

I have a drawable with transparent left and right parts. I need to draw some progress inside it.
startDrawable.setBounds(0, 0, startDrawable.getIntrinsicWidth(), canvas.getHeight());
startDrawable.draw(canvas);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLACK);
Path path = new Path();
path.moveTo(0, 0);
path.lineTo(startDrawable.getIntrinsicWidth() / 2, 0);
path.lineTo(startDrawable.getIntrinsicWidth() / 2, canvas.getHeight());
canvas.drawPath(path, paint);
But unfortunately this code fill transparent parts too and it looks like black rectangle.
I want to see something like this. Does it possible to draw black color only inside not trasparent part of image ??
You can create two different Bitmaps:
one that includes your normal background, lines, shapes and any draw you want (be sure to stay INSIDE your choosed bounds)
one that is the shape used to CUT the previous one via "Paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.xxxxxxx))" method (do a "PorterDuffXfermode" search on Google Images to see all mixes possibilities)
In this way you are free to draw what you want in a normal rectangular/squared Bitmap, and at the end you apply a Mask (over the whole Bitmap) using a free shape (triangular, circular, etc..). Same tecnique is used to create a circular picture starting from the original rectangular version.
For example this code creates a rounded version of a rectangular Bitmap:
#Nullable
public static Bitmap getRoundedBitmap(#Nullable final Bitmap bmp, final int radius) {
if ((bmp == null) || (radius < 1)) return null;
Bitmap cBitmap;
if (bmp.getWidth() != radius || bmp.getHeight() != radius) {
float cSmallest = Math.min(bmp.getWidth(), bmp.getHeight());
float cFactor = cSmallest / radius;
try {
cBitmap = Bitmap.createScaledBitmap(bmp, (int)(bmp.getWidth() / cFactor), (int)(bmp.getHeight() / cFactor), true);
} catch (Exception e) {
cBitmap = null;
}
} else cBitmap = bmp;
if (cBitmap == null) return null;
final Bitmap cOutput = Bitmap.createBitmap(radius, radius, Bitmap.Config.ARGB_8888);
final Canvas cCanvas = new Canvas(cOutput);
final Paint cPaint = new Paint();
final Rect cRect = new Rect(0, 0, radius, radius);
cPaint.setAntiAlias(true);
cPaint.setFilterBitmap(true);
cPaint.setDither(true);
cPaint.setStyle(Paint.Style.FILL);
cCanvas.drawARGB(0, 0, 0, 0);
cPaint.setColor(Color.BLACK);
cCanvas.drawCircle(radius / 2f, radius / 2f, radius / 2f, cPaint);
cPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//draws the rectangular Bitmap and use the special Paint object that has the circular "mask" set
cCanvas.drawBitmap(cBitmap, cRect, cRect, cPaint);
return cOutput;
}

How to create jigsaw puzzle pieces without using mask?

I am trying to create a jigsaw puzzle game, and I would like to know of alternative ways of creating puzzle pieces without using mask. Currently I have jigsaw pieces by taking a full image, breaking that image up into four pieces (lets say the puzzle is 2x2) and then storing and applying a mask to each piece. It looks like the below
// create standard puzzle pieces
arryPieceEndPos = new int[mCols][mRows];
arryPieceImg = new Bitmap[mCols * mRows];
arryIsPieceLocked = new boolean[mCols * mRows];
int pos = 0;
for (int c = 0; c < mCols; c++) {
for (int r = 0; r < mRows; r++) {
arryPieceImg[pos] = Bitmap.createBitmap(mBitmap,
c * mPieceWidth, r * mPieceHeight,
mPieceWidth, mPieceHeight);
arryIsPieceLocked[pos] = false;
arryPieceEndPos[c][r] = pos;
pos++;
}
}
I then use a helper method to apply a mask to each piece
private Bitmap maskMethod(Bitmap bmpOriginal, Bitmap bmpMask) {
// adjust mask bitmap if size is not the size of the puzzle piece
if (bmpMask.getHeight() != mPieceHeight ||
bmpMask.getWidth() != mPieceWidth) {
Log.e("TEST", "Resize Error :: H (mask): " + bmpMask.getHeight() + " // W (mask): " +
bmpMask.getWidth());
Log.d("TEST", "Resize Error :: H (norm): " + mPieceHeight + " // W (norm): " +
mPieceWidth);
}
Canvas canvas = new Canvas();
Bitmap combine = Bitmap.createBitmap(bmpOriginal.getWidth(), bmpOriginal.getHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(combine);
Paint paint = new Paint();
paint.setFilterBitmap(false);
canvas.drawBitmap(bmpOriginal, 0, 0, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(bmpMask, 0, 0, paint);
paint.setXfermode(null);
return combine;
}
I saw this post > http://java.dzone.com/news/connect-pictures-android for connecting pieces together, however, this does not go over generating pieces programmatically without masks. Can anyone provide code examples of how this can be accomplished? The only clue I have is that I should be using Path, however, I am still not sure how. Thanks in advance!
A puzzle piece is a pretty complex view to create, but I can help you understand how to use path. Here is the link to the developer website: http://developer.android.com/reference/android/graphics/Path.html
Look into this link. I made a small thing for you to start. The one thing you need to figure out is how to cut a small circle out of the path, which I wouldn't know. I think you have to look into clipping to have your path follow a circle (you could also do clipping for creating the circle outside the piece, I just haven't done clipping before).
private Bitmap getPuzzleBitmap(Bitmap bitmap)
{
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
calculatePuzzlePath(bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawPath(puzzlePath, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
private void calculatePuzzlePath(int width, int height)
{
float radius = (height / 2) - 5;
float smallRadius = radius / 3;
radius -= smallRadius * 2;
float centerX = width/2;
float centerY = height/2;
puzzlePath = new Path();
// Bottom right
puzzlePath.moveTo(centerX + radius, centerY + radius);
// Top right
puzzlePath.lineTo(centerX + radius, centerY - radius);
// Center top
puzzlePath.lineTo(centerX, centerY - radius);
// Add outside circle to center top
puzzlePath.addCircle(centerX, centerY - radius - ((radius / 3) / 2), radius / 3, Path.Direction.CCW);
// Top left
puzzlePath.lineTo(centerX - radius, centerY - radius);
// Bottom left
puzzlePath.lineTo(centerX - radius, centerY + radius);
//Bottom right
puzzlePath.lineTo(centerX + radius, centerY + radius);
}
I hope this is sufficient to get started with this.
Good luck!

Android: How to blur the edge of a circle using onDraw method?

I have the following method:
protected void onDraw(Canvas i_Canvas) {
int x = (int) m_X;
int y = (int) m_Y;
Path path = new Path();
path.addCircle(
m_Cx,
m_Cy,
m_Radius,
Path.Direction.CCW);
i_Canvas.clipPath(path);
Rect rect = new Rect(x, y, x + 240, y + 240);
i_Canvas.drawBitmap(m_FullImageBitmap, rect, rect, m_Paint);
}
Using this I am trying to create a cropped area of some bitmap in a circle shape.
I also want to blur the edges of that circle area. For example: 5px from the edge towards the centre of the shape will be blurred. How can I implement this?
I think you would have to apply a BlurMaskFilter when drawing the image:
m_Paint = new Paint(0);
m_Paint.setColor(0xffffffff);
m_Paint.setMaskFilter(new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL));

NullPointerException when trying to draw a graph using Android Drawing

I want to sketch a graph that track the user weight progress,
I am writing a method that I can call in the onCreat event,
this is my code:
public void drawGraph(){
Display display = getWindowManager().getDefaultDisplay();
private int width = display.getWidth();
private int height = display.getHeight();
Paint paint = new Paint();
Canvas canvas =new Canvas();
paint.setColor(Color.GRAY);
canvas.drawLine(0, 0, 0, height, paint); // the x-axes represent the date
canvas.drawLine(0, height, width, height, paint); // the y-axes represent the weight
paint.setColor(Color.RED);
canvas.drawLine(0, max, width, max, paint); //draw the maximum healthy weight
paint.setColor(Color.YELLOW);
canvas.drawLine(0, min, width, min, paint); // draw the minimum healthy weight
paint.setColor(Color.GREEN);
canvas.drawLine(0, gW, width, gW, paint); // draw the goal weight
int xDis = width/weekNumbers;
int y;
Path path = new Path();
for (int i = 0; i <= Weightvalues; i++){
Cursor c = db.rawQuery("SELECT CURRENTWEIGHT FROM WEIGHT WHERE DATECREATED > " + startDate, null);
int weight;
if (c!=null){
if (c.moveToFirst()){
do{
weight = c.getInt(0);
// I want now to find out for each entry the point represent it on the graph
y = Math.round(weight * y / range); //range is the difference between the maximum weight and the minimum weight
if (i==1)
path.moveTo(0, y);
else
path.lineTo(0 + i*xDis, height-y);
}while(c.moveToNext());
}
}
}
paint.setColor(Color.BLUE);
canvas.drawPath(path, paint);
}
this is the onCreat event
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.weight_chart);
helper = new DataBaseHelper(this);
drawGraph();
}
when i run the program i faced this error
ERROR/AndroidRuntime(738): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{*********.WeightChart}: java.lang.NullPointerException
Can any body review it for me and tell me where i went wrong
Best regards
You seem to use Canvas without assigning it a Bitmap to do drawing onto. To get your image on screen, one way is to define ImageView in your layout xml;
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/graph_image" />
Accompanied with following changes to your drawGraph method;
...
Bitmap bitmap = BitmapCreateBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas = new Canvas(bitmap);
...
Do your drawing stuff..
...
ImageView iv = (ImageView)findViewById(R.id.graph_image);
iv.setImageBitmap(bitmap);
}

How to rotate a drawable with anti-aliasing enabled

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);

Categories

Resources