I'm drawing a rectangle on a Canvas in Android. How do I drag it around on the screen? I have an onTouchEvent() method in my class that listens to MotionEvent(s). How do I use this to drag my rectangle around while preserving it's size.
My code is as follows:
public class CustomSquareView3 extends View {
private Rect rect;
private Paint paint;
public static int rotation = 45;
Canvas canvas;
int x1 = 200;
int x2 = 400;
int y1 = 200;
int y2 = 400;
public CustomSquareView3(Context context){
super(context);
int x = 50;
int y = 50;
int sideLength = 200;
rect = new Rect(x1,y1, x2, y2);
paint = new Paint();
paint.setColor(Color.GRAY);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.save();
canvas.rotate(rotation, (x1+x2)/2, (y1+y2)/2);
canvas.drawRect(rect, paint);
Paint paint2 = new Paint();
paint2.setColor(Color.WHITE);
paint2.setTextSize(50);
canvas.drawText("Hi", (x1+x2)/2, (y1+y2)/2, paint2);
canvas.restore();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int motionEvent = event.getAction();
float xMove = event.getX();
float yMove = event.getY();
switch (motionEvent){
case MotionEvent.ACTION_DOWN : {
x1 = (int) event.getX();
y1 = (int) event.getY();
rect = new Rect(x1, y1, x2, y2);
break;
}
case MotionEvent.ACTION_MOVE : {
x1 = (int) event.getX();
y1 = (int) event.getY();
rect = new Rect(x1, y1, x2, y2);
break;
}
case MotionEvent.ACTION_UP : {
x1 = (int) event.getX();
y1 = (int) event.getY();
rect = new Rect(x1, y1, x2, y2);
break;
}
default:
return false;
}
invalidate();
return true;
}
}
The above code resizes the rectangle every time I touch the screen. How do I get a smooth drag gesture in the code such that the size of the rectangle is maintained when it is dragged around the screen?
See this example:
class ViewPort extends View {
List<Layer> layers = new LinkedList<Layer>();
int[] ids = {R.drawable.layer0, R.drawable.layer1, R.drawable.layer2};
public ViewPort(Context context) {
super(context);
Resources res = getResources();
for (int i = 0; i < ids.length; i++) {
Layer l = new Layer(context, this, BitmapFactory.decodeResource(res, ids[i]));
layers.add(l);
}
}
#Override
protected void onDraw(Canvas canvas) {
for (Layer l : layers) {
l.draw(canvas);
}
}
private Layer target;
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
target = null;
for (int i = layers.size() - 1; i >= 0; i--) {
Layer l = layers.get(i);
if (l.contains(event)) {
target = l;
layers.remove(l);
layers.add(l);
invalidate();
break;
}
}
}
if (target == null) {
return false;
}
return target.onTouchEvent(event);
}
}
class Layer implements MatrixGestureDetector.OnMatrixChangeListener {
Matrix matrix = new Matrix();
Matrix inverse = new Matrix();
RectF bounds;
View parent;
Bitmap bitmap;
MatrixGestureDetector mgd = new MatrixGestureDetector(matrix, this);
public Layer(Context ctx, View p, Bitmap b) {
parent = p;
bitmap = b;
bounds = new RectF(0, 0, b.getWidth(), b.getHeight());
matrix.postTranslate(50 + (float) Math.random() * 50, 50 + (float) Math.random() * 50);
}
public boolean contains(MotionEvent event) {
matrix.invert(inverse);
float[] pts = {event.getX(), event.getY()};
inverse.mapPoints(pts);
if (!bounds.contains(pts[0], pts[1])) {
return false;
}
return Color.alpha(bitmap.getPixel((int) pts[0], (int) pts[1])) != 0;
}
public boolean onTouchEvent(MotionEvent event) {
mgd.onTouchEvent(event);
return true;
}
#Override
public void onChange(Matrix matrix) {
parent.invalidate();
}
public void draw(Canvas canvas) {
canvas.drawBitmap(bitmap, matrix, null);
}
}
class MatrixGestureDetector {
private static final String TAG = "MatrixGestureDetector";
private int ptpIdx = 0;
private Matrix mTempMatrix = new Matrix();
private Matrix mMatrix;
private OnMatrixChangeListener mListener;
private float[] mSrc = new float[4];
private float[] mDst = new float[4];
private int mCount;
interface OnMatrixChangeListener {
void onChange(Matrix matrix);
}
public MatrixGestureDetector(Matrix matrix, MatrixGestureDetector.OnMatrixChangeListener listener) {
this.mMatrix = matrix;
this.mListener = listener;
}
public void onTouchEvent(MotionEvent event) {
if (event.getPointerCount() > 2) {
return;
}
int action = event.getActionMasked();
int index = event.getActionIndex();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
int idx = index * 2;
mSrc[idx] = event.getX(index);
mSrc[idx + 1] = event.getY(index);
mCount++;
ptpIdx = 0;
break;
case MotionEvent.ACTION_MOVE:
for (int i = 0; i < mCount; i++) {
idx = ptpIdx + i * 2;
mDst[idx] = event.getX(i);
mDst[idx + 1] = event.getY(i);
}
mTempMatrix.setPolyToPoly(mSrc, ptpIdx, mDst, ptpIdx, mCount);
mMatrix.postConcat(mTempMatrix);
if(mListener != null) {
mListener.onChange(mMatrix);
}
System.arraycopy(mDst, 0, mSrc, 0, mDst.length);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (event.getPointerId(index) == 0) ptpIdx = 2;
mCount--;
break;
}
}
}
You have to redo it a little. Use your rectangle instead of bitmaps.
Related
Here is My code, I am trying to zoom at the specific area but my code is not working properly. I want my code to work as Autocad Canvas zoom in out can anyone know to zoom canvas just like AutoCAD canvas. I want to make the CAD application work the same as AutoCAD work please help me.
I want My code to work as zoom in-out canvas drag move canvas.
public class Custom_Canvas extends View implements View.OnTouchListener {
private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
Paint paint = new Paint();
// See onTouchEvent!
private float initX = 0f;
private float initY = 0f;
// x and y coord of canvas center!
private float canvasX = 0f;
private float canvasY = 0f;
private boolean drag = false;
private boolean firstdraw = true;
ScaleGestureDetector scaleGestureDetector;
private float scalefactor = 1f;
private float scalePointX, scalePointY;
float min_zoom = 0.1f;
float max_zoom = 10f;
private float lastfocusX = -1;
private float lastfocusY = -1;
#SuppressLint("ClickableViewAccessibility")
public Custom_Canvas(Context context, AttributeSet attrs){
super(context, attrs);
this.setOnTouchListener(this);
scaleGestureDetector = new ScaleGestureDetector(context,new Scalelistener());
paint.setColor(Color.WHITE);
}
#SuppressLint("ClickableViewAccessibility")
public Custom_Canvas(Context context) {
super(context);
this.setOnTouchListener(this);
paint.setColor(Color.WHITE);
scaleGestureDetector = new ScaleGestureDetector(context,new Scalelistener());
}
#SuppressLint("DrawAllocation")
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
if(firstdraw){
canvasX = getWidth()/2f;
canvasY = getHeight()/2f;
firstdraw = false;
}
canvas.scale(scalefactor,scalefactor,scalePointX,scalePointY);
canvas.translate(canvasX,canvasY);
canvas.drawCircle(0,0,20f,paint);
// canvas.drawCircle(100,100,20f,paint);
canvas.restore();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
scaleGestureDetector.onTouchEvent(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
float x = event.getX()/scalefactor;
float y = event.getY()/scalefactor;
// drag = true;
initX = x;
initY = y;
mActivePointerId = event.getPointerId(0);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
// case MotionEvent.ACTION_POINTER_DOWN:
final int p = event.findPointerIndex(mActivePointerId);
final float x1 = event.getX(p) / scalefactor;
final float y1 = event.getY(p) / scalefactor;
if (!scaleGestureDetector.isInProgress()) {
// if (drag) {
float dx = x1 - initX;
float dy = y1 - initY;
canvasX += dx ;
canvasY += dy ;
invalidate();
// }
}
initX = x1;
initY = y1;
break;
case MotionEvent.ACTION_POINTER_UP:
// drag = false;
final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
initX = event.getX(newPointerIndex)/scalefactor;
initY = event.getY(newPointerIndex)/scalefactor;
mActivePointerId = event.getPointerId(newPointerIndex);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// drag = false;
mActivePointerId = INVALID_POINTER_ID;
break;
}
return true;
}
private class Scalelistener extends ScaleGestureDetector.SimpleOnScaleGestureListener{
#Override
public boolean onScale(ScaleGestureDetector detector) {
scalefactor *= detector.getScaleFactor();
scalePointX = detector.getFocusX();
scalePointY = detector.getFocusY();
Toast.makeText(getContext(), " "+scalePointX+" "+scalePointY, Toast.LENGTH_SHORT).show();
if(lastfocusX == -1){
lastfocusX = scalePointX;
}
if(lastfocusY == -1){
lastfocusY = scalePointY;
}
canvasX += (scalePointX - lastfocusX);
canvasY += (scalePointY - lastfocusY);
scalefactor = Math.max(min_zoom,Math.min(scalefactor,max_zoom));
lastfocusX = scalePointX;
lastfocusY = scalePointY;
invalidate();
return true;
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
lastfocusX = -1;
lastfocusY = -1;
return true;
}
#Override
public void onScaleEnd(ScaleGestureDetector detector) { }
}
How can i implement freehand cropping on Imageview.
Using below code i'm able to draw freehand path and can able to crop image but i'm facing some other problems
Now what i have tried so far
Here is my code
code for cropping image using canvas
public class SomeView extends View implements View.OnTouchListener {
private Paint paint;
int DIST = 2;
boolean flgPathDraw = true;
Point mfirstpoint = null;
boolean bfirstpoint = false;
Point mlastpoint = null;
Bitmap bitmap;
Context mContext;
public SomeView(Context c, Bitmap bitmap) {
super(c);
mContext = c;
this.bitmap = bitmap;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0));
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
this.setOnTouchListener(this);
points = new ArrayList<Point>();
bfirstpoint = false;
}
public SomeView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
points = new ArrayList<Point>();
bfirstpoint = false;
this.setOnTouchListener(this);
}
public void onDraw(Canvas canvas) {
/*Rect dest = new Rect(0, 0, getWidth(), getHeight());
paint.setFilterBitmap(true);
canvas.drawBitmap(bitmap, null, dest, paint);*/
canvas.drawBitmap(bitmap, 0, 0, null);
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);
}
public boolean onTouch(View view, MotionEvent event) {
// if(event.getAction() != MotionEvent.ACTION_DOWN)
// return super.onTouchEvent(event);
Point point = new Point();
point.x = (int) event.getX();
point.y = (int) event.getY();
if (flgPathDraw) {
if (bfirstpoint) {
if (comparepoint(mfirstpoint, point)) {
// points.add(point);
points.add(mfirstpoint);
flgPathDraw = false;
showcropdialog();
} else {
points.add(point);
}
} else {
points.add(point);
}
if (!(bfirstpoint)) {
mfirstpoint = point;
bfirstpoint = true;
}
}
invalidate();
Log.e("Hi ==>", "Size: " + point.x + " " + point.y);
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d("Action up*****~~>>>>", "called");
mlastpoint = point;
if (flgPathDraw) {
if (points.size() > 12) {
if (!comparepoint(mfirstpoint, mlastpoint)) {
flgPathDraw = false;
points.add(mfirstpoint);
showcropdialog();
}
}
}
}
return true;
}
private boolean comparepoint(Point first, Point current) {
int left_range_x = (int) (current.x - 3);
int left_range_y = (int) (current.y - 3);
int right_range_x = (int) (current.x + 3);
int right_range_y = (int) (current.y + 3);
if ((left_range_x < first.x && first.x < right_range_x)
&& (left_range_y < first.y && first.y < right_range_y)) {
if (points.size() < 10) {
return false;
} else {
return true;
}
} else {
return false;
}
}
public void fillinPartofPath() {
Point point = new Point();
point.x = points.get(0).x;
point.y = points.get(0).y;
points.add(point);
invalidate();
}
public void resetView() {
points.clear();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
points = new ArrayList<Point>();
bfirstpoint = false;
flgPathDraw = true;
invalidate();
}
private void showcropdialog() {
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent;
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
cropImage();
break;
case DialogInterface.BUTTON_NEGATIVE:
/*// No button clicked
intent = new Intent(mContext, DisplayCropActivity.class);
intent.putExtra("crop", false);
mContext.startActivity(intent);
bfirstpoint = false;*/
resetView();
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Do you Want to save Crop or Non-crop image?")
.setPositiveButton("Crop", dialogClickListener)
.setNegativeButton("Non-crop", dialogClickListener).show()
.setCancelable(false);
}
}
Code for cropping bitmap
public void cropImage() {
setContentView(R.layout.activity_picture_preview);
imageView = findViewById(R.id.image);
int widthOfscreen = 0;
int heightOfScreen = 0;
DisplayMetrics dm = new DisplayMetrics();
try {
getWindowManager().getDefaultDisplay().getMetrics(dm);
} catch (Exception ex) {
}
widthOfscreen = dm.widthPixels;
heightOfScreen = dm.heightPixels;
Bitmap bitmap2 = mBitmap;
Bitmap resultingImage = Bitmap.createBitmap(widthOfscreen,
heightOfScreen, bitmap2.getConfig());
Canvas canvas = new Canvas(resultingImage);
Paint paint = new Paint();
Path path = new Path();
for (int i = 0; i < points.size(); i++) {
path.lineTo(points.get(i).x, points.get(i).y);
}
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap2, 0, 0, paint);
imageView.setImageBitmap(resultingImage);
}
Here what i get result using above code
Cropping image using Finger touch
This image showing result after cropping image
This is my expected output
Please check below screenshot for the same
This Image showing cropping image using Finger touch
This image showing result after cropping image
The Below problems i'am facing in above code
Unable to set bitmap in full screen using canvas
If i set bitmap in full screen in canvas than image is stretching
How to set transparent background to cropped bitmap
Unable to add border to cropped image
The result of image Cropping is not as expected
Here are some other post that i have tried so far
crop free hand selected part of image
Freehand cropping on the image in android
Android Freehand bitmap cropping
Android: Free Cropping of Image
implemanting freehand crop in android
Get the free hand cropping Image From the original in android
Darken parts of a free-hand cropped image in android
Android-freehand-image-crop
Android Top Image Cropper Libraries
Crop a shape from an Android bitmap
Freehand Image Crop draw inside bitmap region
none of the above post help to achieve my excepted output
If need more information please do let me know. Thanks in advance. Your efforts will be appreciated.
In general, your code looks OK, but I have a few comments:
Unable to set bitmap in full screen using canvas
If i set bitmap in full screen in canvas than image is stretching
The portion of the image that you are selecting needs to be placed in a smaller bitmap so the layout XML can position it as you like. You are creating a bitmap that is full screen. See the following demo for details.
How to set transparent background to cropped bitmap
I am unclear about what the issue is.
Unable to add border to cropped image
The result of image Cropping is not as expected
See below.
Here is a small demo app using your code. You didn't provide an MCVE, so I threw the following together for demonstration purposes. Other than getting the app to function I think that the only change is to draw the border in MainActivity.java. The border width starts at the cut-out path that the user draws and reaches inward to the cut-out. If you want to actually frame the cutout without losing any pixels, then you will need to expand the path to accommodate the frame which I arbitrarily set to 20 pixels.
I also had to create the layouts used, so you may want to look at those. They are posted below.
Here is the demo video with the code to follow:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Bitmap mBitmap;
private SomeView mSomeView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dog);
mSomeView = new SomeView(this, mBitmap);
LinearLayout layout = findViewById(R.id.layout);
LinearLayout.LayoutParams lp =
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
layout.addView(mSomeView, lp);
}
public void cropImage() {
setContentView(R.layout.activity_picture_preview);
ImageView imageView = findViewById(R.id.image);
Bitmap fullScreenBitmap =
Bitmap.createBitmap(mSomeView.getWidth(), mSomeView.getHeight(), mBitmap.getConfig());
Canvas canvas = new Canvas(fullScreenBitmap);
Path path = new Path();
List<Point> points = mSomeView.getPoints();
for (int i = 0; i < points.size(); i++) {
path.lineTo(points.get(i).x, points.get(i).y);
}
// Cut out the selected portion of the image...
Paint paint = new Paint();
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(mBitmap, 0, 0, paint);
// Frame the cut out portion...
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
canvas.drawPath(path, paint);
// Create a bitmap with just the cropped area.
Region region = new Region();
Region clip = new Region(0, 0, fullScreenBitmap.getWidth(), fullScreenBitmap.getHeight());
region.setPath(path, clip);
Rect bounds = region.getBounds();
Bitmap croppedBitmap =
Bitmap.createBitmap(fullScreenBitmap, bounds.left, bounds.top,
bounds.width(), bounds.height());
imageView.setImageBitmap(croppedBitmap);
}
}
SomeView.java
I don't think there were any substantive changes to this class.
public class SomeView extends View implements View.OnTouchListener {
private Paint paint;
private List<Point> points;
int DIST = 2;
boolean flgPathDraw = true;
Point mfirstpoint = null;
boolean bfirstpoint = false;
Point mlastpoint = null;
Bitmap bitmap;
Context mContext;
public SomeView(Context c, Bitmap bitmap) {
super(c);
mContext = c;
this.bitmap = bitmap;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0));
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
this.setOnTouchListener(this);
points = new ArrayList<Point>();
bfirstpoint = false;
}
public SomeView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
points = new ArrayList<Point>();
bfirstpoint = false;
this.setOnTouchListener(this);
}
public void onDraw(Canvas canvas) {
/*Rect dest = new Rect(0, 0, getWidth(), getHeight());
paint.setFilterBitmap(true); canvas.drawBitmap(bitmap, null, dest, paint);*/
canvas.drawBitmap(bitmap, 0, 0, null);
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);
}
public boolean onTouch(View view, MotionEvent event) {
// if(event.getAction() != MotionEvent.ACTION_DOWN)
// return super.onTouchEvent(event);
Point point = new Point();
point.x = (int) event.getX();
point.y = (int) event.getY();
if (flgPathDraw) {
if (bfirstpoint) {
if (comparepoint(mfirstpoint, point)) {
// points.add(point);
points.add(mfirstpoint);
flgPathDraw = false;
showcropdialog();
} else {
points.add(point);
}
} else {
points.add(point);
}
if (!(bfirstpoint)) {
mfirstpoint = point;
bfirstpoint = true;
}
}
invalidate();
Log.e("Hi ==>", "Size: " + point.x + " " + point.y);
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d("Action up*****~~>>>>", "called");
mlastpoint = point;
if (flgPathDraw) {
if (points.size() > 12) {
if (!comparepoint(mfirstpoint, mlastpoint)) {
flgPathDraw = false;
points.add(mfirstpoint);
showcropdialog();
}
}
}
}
return true;
}
private boolean comparepoint(Point first, Point current) {
int left_range_x = (int) (current.x - 3);
int left_range_y = (int) (current.y - 3);
int right_range_x = (int) (current.x + 3);
int right_range_y = (int) (current.y + 3);
if ((left_range_x < first.x && first.x < right_range_x)
&& (left_range_y < first.y && first.y < right_range_y)) {
if (points.size() < 10) {
return false;
} else {
return true;
}
} else {
return false;
}
}
public void fillinPartofPath() {
Point point = new Point();
point.x = points.get(0).x;
point.y = points.get(0).y;
points.add(point);
invalidate();
}
public void resetView() {
points.clear();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
points = new ArrayList<Point>();
bfirstpoint = false;
flgPathDraw = true;
invalidate();
}
private void showcropdialog() {
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent;
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
((MainActivity) mContext).cropImage();
break;
case DialogInterface.BUTTON_NEGATIVE:
/*// No button clicked
intent = new Intent(mContext, DisplayCropActivity.class); intent.putExtra("crop", false); mContext.startActivity(intent);
bfirstpoint = false;*/ resetView();
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Do you Want to save Crop or Non-crop image?")
.setPositiveButton("Crop", dialogClickListener)
.setNegativeButton("Non-crop", dialogClickListener).show()
.setCancelable(false);
}
public List<Point> getPoints() {
return points;
}
}
activity_main.xml
<LinearLayout
android:id="#+id/layout"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"/>
activity_picture_preview.xml
<android.support.constraint.ConstraintLayout x
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimary">
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="#drawable/dog" />
</android.support.constraint.ConstraintLayout>
If you want to create a cropped bitmap with a 100px border, use the following code in cropImage():
// Create a bitmap with just the cropped area.
Region region = new Region();
Region clip = new Region(0, 0, fullScreenBitmap.getWidth(), fullScreenBitmap.getHeight());
region.setPath(path, clip);
Rect sourceBounds = region.getBounds();
Rect destBounds =
new Rect(CROPPED_MARGIN, CROPPED_MARGIN, sourceBounds.width() + CROPPED_MARGIN,
sourceBounds.height() + CROPPED_MARGIN);
Bitmap croppedBitmap =
Bitmap.createBitmap(sourceBounds.width() + CROPPED_MARGIN * 2,
sourceBounds.height() + CROPPED_MARGIN * 2, mBitmap.getConfig());
canvas.setBitmap(croppedBitmap);
canvas.drawBitmap(fullScreenBitmap, sourceBounds, destBounds, null);
imageView.setImageBitmap(croppedBitmap);
// Add as member variable.
private static final int CROPPED_MARGIN = 100;
I have tried lots of solution for this problem in my project, but this code is working.
Here, i put my own project's Code Here. You can use it, if you found your solution in it.
public class CropView extends View implements View.OnTouchListener {
public static final String INTENT_KEY_CROP = "crop";
public static final String CACHE_KEY = "bitmap";
public static List<Point> points;
boolean flgPathDraw = true;
boolean bFirstPoint = false;
private Point firstPoint = null;
private Point lastPoint = null;
private final Bitmap originalImageBitmap;
private int canvasWidth;
private int canvasHeight;
private Paint paint;
private Context context;
private static LruCache<String, Bitmap> mMemoryCache;
private final ImageCropListener imageCropListener;
public interface ImageCropListener {
void onClickDialogPositiveButton();
void onClickDialogNegativeButton();
}
public static Bitmap getBitmapFromMemCache() {
return mMemoryCache.get(CACHE_KEY);
}
public CropView(Context c, Bitmap bm, ImageCropListener listener) {
super(c);
context = c;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setPathEffect(new DashPathEffect(new float[] { 10, 20 }, 0));
paint.setStrokeWidth(5);
paint.setColor(Color.WHITE);
this.setOnTouchListener(this);
points = new ArrayList<>();
bFirstPoint = false;
this.originalImageBitmap = bm;
this.imageCropListener = listener;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
#Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.getByteCount() / 1024;
}
};
}
public CropView(Context context, AttributeSet attrs, Bitmap bm,
ImageCropListener listener) {
super(context, attrs);
this.context = context;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
this.setOnTouchListener(this);
points = new ArrayList<>();
bFirstPoint = false;
this.originalImageBitmap = bm;
this.imageCropListener = listener;
}
public void addBitmapToMemoryCache(Bitmap bitmap) {
if (getBitmapFromMemCache() == null) {
mMemoryCache.put(CACHE_KEY, bitmap);
}
}
private float calcBitmapScale(int canvasWidth, int canvasHeight, int bmpWidth, int bmpHeight) {
float scale = (float)canvasWidth / (float)bmpWidth;
float tmp = bmpHeight * scale;
if (tmp < canvasHeight) {
scale = (float)canvasHeight / (float)bmpHeight;
return scale;
}
return scale;
}
public void onDraw(Canvas canvas) {
canvasWidth = canvas.getWidth();
canvasHeight = canvas.getHeight();
/* int bmpWidth = this.originalImageBitmap.getWidth();
int bmpHeight = this.originalImageBitmap.getHeight();
float toCanvasScale = this.calcBitmapScale(canvasWidth, canvasHeight, bmpWidth, bmpHeight);
float diffX = (bmpWidth * toCanvasScale - canvasWidth);
float diffY = (bmpHeight * toCanvasScale - canvasHeight);
float addX = (diffX / toCanvasScale) / 2;
float addY = (diffY / toCanvasScale) / 2;
Rect rSrc = new Rect((int)addX, (int)addY,
(int)((canvasWidth / toCanvasScale) + addX), (int)((canvasHeight /
toCanvasScale) + addY));
RectF rDest = new RectF(0, 0, canvasWidth, canvasHeight);
*/
canvas.drawBitmap(originalImageBitmap, 0, 0, null);
Path cropAreaPath = new Path();
boolean isFirstPoint = true;
for (int i = 0; i < points.size(); i += 2) {
Point point = points.get(i);
if (isFirstPoint) {
isFirstPoint = false;
// 最初の処理でPathのx,y座標をpointの座標に移動する
cropAreaPath.moveTo(point.x, point.y);
} else if (i < points.size() - 1) {
Point next = points.get(i + 1);
cropAreaPath.quadTo(point.x, point.y, next.x, next.y);
} else {
lastPoint = points.get(i);
cropAreaPath.lineTo(point.x, point.y);
}
}
canvas.drawPath(cropAreaPath, paint);
}
public boolean onTouch(View view, MotionEvent event) {
Point point = new Point();
point.x = (int) event.getX();
point.y = (int) event.getY();
if (flgPathDraw) {
if (bFirstPoint) {
if (comparePoint(firstPoint, point)) {
// points.add(point);
points.add(firstPoint);
flgPathDraw = false;
showCropDialog();
} else {
points.add(point);
}
} else {
points.add(point);
}
if (!(bFirstPoint)) {
firstPoint = point;
bFirstPoint = true;
}
}
invalidate();
//Log.e("Hi ==>", "Size: " + point.x + " " + point.y);
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d("Action up***>", "called");
lastPoint = point;
if (flgPathDraw) {
if (points.size() > 12) {
if (!comparePoint(firstPoint, lastPoint)) {
flgPathDraw = false;
points.add(firstPoint);
showCropDialog();
}
}
}
}
return true;
}
private boolean comparePoint(Point first, Point current) {
int left_range_x = (int) (current.x - 3);
int left_range_y = (int) (current.y - 3);
int right_range_x = (int) (current.x + 3);
int right_range_y = (int) (current.y + 3);
if ((left_range_x < first.x && first.x < right_range_x)
&& (left_range_y < first.y && first.y < right_range_y)) {
if (points.size() < 10) {
return false;
} else {
return true;
}
} else {
return false;
}
}
public void fillinPartofPath() {
Point point = new Point();
point.x = points.get(0).x;
point.y = points.get(0).y;
points.add(point);
invalidate();
}
public void resetView() {
points.clear();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
flgPathDraw = true;
invalidate();
}
private void showCropDialog() {
final Bitmap croppedImage = cropImage(this.originalImageBitmap);
DialogInterface.OnClickListener dialogClickListener = new
DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
addBitmapToMemoryCache(croppedImage);
imageCropListener.onClickDialogPositiveButton();
break;
case DialogInterface.BUTTON_NEGATIVE:
bFirstPoint = false;
resetView();
imageCropListener.onClickDialogNegativeButton();
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage("Do you Want to save Crop or Non-crop image?")
.setPositiveButton("Crop", dialogClickListener)
.setNegativeButton("Cancel", dialogClickListener).show()
.setCancelable(false);
}
private Bitmap cropImage(Bitmap image) {
Bitmap cropImage = Bitmap.createBitmap(canvasWidth, canvasHeight,
image.getConfig());
Canvas canvas = new Canvas(cropImage);
Paint paint = new Paint();
paint.setAntiAlias(true);
Path path = new Path();
for (int i = 0; i < CropView.points.size(); i++) {
path.lineTo(CropView.points.get(i).x, CropView.points.get(i).y);
}
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(originalImageBitmap, 0, 0, paint);
return cropImage;
}
class Point {
public float dy;
public float dx;
float x, y;
#Override
public String toString(){
return x + ", " + y;
}
}
}
Then You can get Crop Result..as like,
Bitmap cropBitmap = CropView.getBitmapFromMemCache();
cropBitmap = getBitmapWithTransparentBG(cropBitmap,Color.WHITE);
Drawable d = new BitmapDrawable(getResources(),cropBitmap);
public Bitmap getBitmapWithTransparentBG(Bitmap srcBitmap, int bgColor) {
Bitmap result = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);
int nWidth = result.getWidth();
int nHeight = result.getHeight();
for (int y = 0; y < nHeight; ++y)
for (int x = 0; x < nWidth; ++x) {
int nPixelColor = result.getPixel(x, y);
if (nPixelColor == bgColor)
result.setPixel(x, y, Color.TRANSPARENT);
}
return result;
}
I Think, This code will be perfect for your problem solution.. Thanks
I've made a program that clicks on the color of the image and displays the color in text, but for now I can only use a few basic colors, basic colors like black, red or yellow, etc. If I want to join other colors such as pink or light blue, how can I do, if I may, you can also set a range of colors it? set, for example # FF0000 ~ # FF6347 is red (color code used here 16bit)
My problem in Color.XXX this part can not be customized
int touchedRGB = orgbmp.getPixel(x, y);
if(touchedRGB == Color.BLACK)
colorshow.setText("Is Black");
if(touchedRGB == Color.RED)
colorshow.setText("Is RED");
if(touchedRGB == Color.GREEN)
colorshow.setText("Is GREEN");
if(touchedRGB == Color.BLUE)
colorshow.setText("Is Blue");
if(touchedRGB == Color.GRAY)
colorshow.setText("Is Gary");
if(touchedRGB == Color.YELLOW)
colorshow.setText("Is Yellow");
Your class should implement ColorPickerDialog.OnColorChangedListener
public class MainActivity implements ColorPickerDialog.OnColorChangedListener
{
private Paint mPaint;
mPaint = new Paint();
// on button click
new ColorPickerDialog(this, this, mPaint.getColor()).show();
}
ColorPicker Dialog
public class ColorPickerDialog extends Dialog {
public interface OnColorChangedListener {
void colorChanged(int color);
}
private OnColorChangedListener mListener;
private int mInitialColor;
private static class ColorPickerView extends View {
private Paint mPaint;
private Paint mCenterPaint;
private final int[] mColors;
private OnColorChangedListener mListener;
ColorPickerView(Context c, OnColorChangedListener l, int color) {
super(c);
mListener = l;
mColors = new int[] {
0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
0xFFFFFF00, 0xFFFF0000
};
Shader s = new SweepGradient(0, 0, mColors, null);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setShader(s);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(32);
mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCenterPaint.setColor(color);
mCenterPaint.setStrokeWidth(5);
}
private boolean mTrackingCenter;
private boolean mHighlightCenter;
#Override
protected void onDraw(Canvas canvas) {
float r = CENTER_X - mPaint.getStrokeWidth()*0.5f;
canvas.translate(CENTER_X, CENTER_X);
canvas.drawOval(new RectF(-r, -r, r, r), mPaint);
canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint);
if (mTrackingCenter) {
int c = mCenterPaint.getColor();
mCenterPaint.setStyle(Paint.Style.STROKE);
if (mHighlightCenter) {
mCenterPaint.setAlpha(0xFF);
} else {
mCenterPaint.setAlpha(0x80);
}
canvas.drawCircle(0, 0,
CENTER_RADIUS + mCenterPaint.getStrokeWidth(),
mCenterPaint);
mCenterPaint.setStyle(Paint.Style.FILL);
mCenterPaint.setColor(c);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(CENTER_X*2, CENTER_Y*2);
}
private static final int CENTER_X = 100;
private static final int CENTER_Y = 100;
private static final int CENTER_RADIUS = 32;
private int floatToByte(float x) {
int n = java.lang.Math.round(x);
return n;
}
private int pinToByte(int n) {
if (n < 0) {
n = 0;
} else if (n > 255) {
n = 255;
}
return n;
}
private int ave(int s, int d, float p) {
return s + java.lang.Math.round(p * (d - s));
}
private int interpColor(int colors[], float unit) {
if (unit <= 0) {
return colors[0];
}
if (unit >= 1) {
return colors[colors.length - 1];
}
float p = unit * (colors.length - 1);
int i = (int)p;
p -= i;
// now p is just the fractional part [0...1) and i is the index
int c0 = colors[i];
int c1 = colors[i+1];
int a = ave(Color.alpha(c0), Color.alpha(c1), p);
int r = ave(Color.red(c0), Color.red(c1), p);
int g = ave(Color.green(c0), Color.green(c1), p);
int b = ave(Color.blue(c0), Color.blue(c1), p);
return Color.argb(a, r, g, b);
}
private int rotateColor(int color, float rad) {
float deg = rad * 180 / 3.1415927f;
int r = Color.red(color);
int g = Color.green(color);
int b = Color.blue(color);
ColorMatrix cm = new ColorMatrix();
ColorMatrix tmp = new ColorMatrix();
cm.setRGB2YUV();
tmp.setRotate(0, deg);
cm.postConcat(tmp);
tmp.setYUV2RGB();
cm.postConcat(tmp);
final float[] a = cm.getArray();
int ir = floatToByte(a[0] * r + a[1] * g + a[2] * b);
int ig = floatToByte(a[5] * r + a[6] * g + a[7] * b);
int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b);
return Color.argb(Color.alpha(color), pinToByte(ir),
pinToByte(ig), pinToByte(ib));
}
private static final float PI = 3.1415926f;
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX() - CENTER_X;
float y = event.getY() - CENTER_Y;
boolean inCenter = java.lang.Math.sqrt(x*x + y*y) <= CENTER_RADIUS;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTrackingCenter = inCenter;
if (inCenter) {
mHighlightCenter = true;
invalidate();
break;
}
case MotionEvent.ACTION_MOVE:
if (mTrackingCenter) {
if (mHighlightCenter != inCenter) {
mHighlightCenter = inCenter;
invalidate();
}
} else {
float angle = (float)java.lang.Math.atan2(y, x);
// need to turn angle [-PI ... PI] into unit [0....1]
float unit = angle/(2*PI);
if (unit < 0) {
unit += 1;
}
mCenterPaint.setColor(interpColor(mColors, unit));
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (mTrackingCenter) {
if (inCenter) {
mListener.colorChanged(mCenterPaint.getColor());
}
mTrackingCenter = false; // so we draw w/o halo
invalidate();
}
break;
}
return true;
}
}
public ColorPickerDialog(Context context,
OnColorChangedListener listener,
int initialColor) {
super(context);
mListener = listener;
mInitialColor = initialColor;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnColorChangedListener l = new OnColorChangedListener() {
public void colorChanged(int color) {
mListener.colorChanged(color);
dismiss();
}
};
setContentView(new ColorPickerView(getContext(), l, mInitialColor));
setTitle("Pick a Color");
}
You have to choose the color and click the center circle to pick the color. Set the color to your paint object and use the same to draw.
Creating a resource file matching color name and color codes will solve the problem instead of using Color module like here
getResources().getStringArray and getResources().obtainTypedArray can be used to loop over and match the names & color codes.
Following: https://developer.android.com/training/gestures/movement.html
for handling movement in an onTouchEvent. My problem is though that it seems the touch is never registered, even when following the tutorial linked.
Code:
public class Sprite extends Activity {
private static final int BMP_ROWS = 4;
private static final int BMP_COL = 3;
private int x, y = 0;
private int speedx, speedy = 5;
private int currentFrame = 0;
private int width, height;
private float xTouch, yTouch;
private VelocityTracker mVelocityTracker = null;
private GameView gameView;
private Bitmap bmp;
int [] DIRECTION_TO_ANIMATE_MAP = {3, 1, 0, 2};
public Sprite(GameView gameView, Bitmap bmp) {
this.gameView = gameView;
this.bmp = bmp;
this.width = bmp.getWidth() / BMP_COL;
this.height = bmp.getHeight() / BMP_ROWS;
}
private void Update() {
if (x >= gameView.getWidth() - width - speedx|| x + speedx <= 0) {
}
if (y >= gameView.getHeight() - height - speedy || y + speedy <= 0) {
}
currentFrame = ++currentFrame % BMP_COL;
}
public boolean onTouchEvent(MotionEvent event) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
synchronized (gameView.getHolder()) {
if (this.isCollition(event.getX(), event.getY())) {
Log.d("", "Sprite touched!");
}
switch (action) {
case MotionEvent.ACTION_DOWN:
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
} else {
mVelocityTracker.clear();
}
xTouch = event.getX();
yTouch = event.getY();
Log.d("", "You clicked: " + Float.toString(xTouch) + "," + Float.toString(yTouch));
mVelocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
Log.d("", "X velocity: " + VelocityTrackerCompat.getXVelocity(mVelocityTracker, pointerId));
Log.d("", "Y velocity: " + VelocityTrackerCompat.getYVelocity(mVelocityTracker, pointerId));
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mVelocityTracker.recycle();
break;
}
}
boolean ret = super.onTouchEvent(event);
return ret;
}
public void onDraw(Canvas canvas) {
MotionEvent event = null;
Update();
int srcX = 1 * width;
int srcY = 0 * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
public boolean isCollition(float x2, float y2) {
return x2 > x && x2 < x + width && y2 > y && y2 < y + height;
}
}
I get a logcat message each time I touch the sprite but whenever i touch the screen or swipe I get nothing. I realise that the most possible reason is me not utilizing onTouchEvent properly but I've tried implementing some of the things suggested in other questions but without luck.
EDIT:
It was as suggested below my game logic that was wrong here. I had the onTouchEvent in a wrong class. When I changed it into the view class it works perfectly:
public class GameView extends SurfaceView {
private Bitmap bmp;
private SurfaceHolder holder;
private GameLoop gameLoop;
private Sprite sprite;
private int x = 0;
private long lastClick;
private VelocityTracker mVelocityTracker;
private float xTouch;
private float yTouch;
public GameView(Context context) {
super(context);
gameLoop = new GameLoop(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#SuppressLint("WrongCall")
#Override
public void surfaceCreated(SurfaceHolder holder) {
gameLoop.setRunning(true);
gameLoop.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
});
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.image);
sprite = new Sprite(this, bmp);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
sprite.onDraw(canvas);
}
public boolean onTouchEvent(MotionEvent event) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
synchronized (getHolder()) {
if (sprite.isCollition(event.getX(), event.getY())) {
Log.d("", "Sprite touched!");
}
switch (action) {
case MotionEvent.ACTION_DOWN:
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
} else {
mVelocityTracker.clear();
}
xTouch = event.getX();
yTouch = event.getY();
Log.d("", "You clicked: " + Float.toString(xTouch) + "," + Float.toString(yTouch));
mVelocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
Log.d("", "X velocity: " + VelocityTrackerCompat.getXVelocity(mVelocityTracker, pointerId));
Log.d("", "Y velocity: " + VelocityTrackerCompat.getYVelocity(mVelocityTracker, pointerId));
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mVelocityTracker.recycle();
break;
}
}
boolean ret = super.onTouchEvent(event);
return ret;
}
}
check your game logic again and handle return value manually, instead of super.onTouchEvent(event);
Here is the code for Drawing and Undoing but unable to join with Erasing.
It is either Drawing + Erasing or Drawing + Undoing but cannot three of these.
public class Drawing extends View {
private Paint mPaint, mBitmapPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private int color, size, state;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
private ArrayList<Integer> colors = new ArrayList<Integer>();
private ArrayList<Integer> sizes = new ArrayList<Integer>();
public Drawing(Context c) {
super(c);
}
public Drawing(Context c,int width, int height, int size, int color, int state) {
super(c);
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
// mBitmapPaint = new Paint(Paint.DITHER_FLAG);
// mBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
setColor(color);
setSize(size);
setState(state);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
// canvas.drawColor(Color.TRANSPARENT);
// canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
//
// if (state == 0)
// mBitmap.eraseColor(Color.TRANSPARENT);
for (int i = 0; i < paths.size(); i++) {
mPaint.setColor(colors.get(i));
mPaint.setStrokeWidth(sizes.get(i));
canvas.drawPath(paths.get(i), mPaint);
}
mPaint.setColor(color);
mPaint.setStrokeWidth(size);
canvas.drawPath(mPath, mPaint);
}
public void setColor(int color) {
this.color = color;
}
public void setSize(int size) {
this.size = size;
}
public void setState(int state) {
this.state = state;
// if (state == 0)
// mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
// else
// mPaint.setXfermode(null);
}
public void onClickUndo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
sizes.remove(sizes.size() - 1);
colors.remove(colors.size() - 1);
invalidate();
}
}
private void touch_start(float x, float y) {
undonePaths.clear();
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
colors.add(color);
sizes.add(size);
paths.add(mPath);
mPath = new Path();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
I tried to made color to transparent but it does not make sense because not changing the pixel but is create new path.
The below can be used to draw erase, emboss, save to gallery, blur. You can use the code to add undo and redo functionality. The below code works fine. You can slo check FingerPaint.java from the samples folder of your adk under api demos in the grapics folder.
Creating a spray effect on touch draw in android. This link will help you create spray effect by spraying dots.
public class FingerPaintActivity extends GraphicsActivity
implements ColorPickerDialog.OnColorChangedListener {
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
Button b;
Dialog dialog;
static MyView mv;
File f;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
mv= new MyView(this);
mv.setDrawingCacheEnabled(true);
ll.addView(mv);
b= (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
final CharSequence[] items = {"Pick Color", "Emboss", "Blur","Erase","SaveToGallery"};
AlertDialog.Builder builder = new AlertDialog.Builder(FingerPaintActivity.this);
builder.setTitle("Options");
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if(item==0)
{
new ColorPickerDialog(FingerPaintActivity.this, FingerPaintActivity.this, mPaint.getColor()).show();
}
if(item==1)
{
if (mPaint.getMaskFilter() != mEmboss) {
mPaint.setMaskFilter(mEmboss);
} else {
mPaint.setMaskFilter(null);
}
}
if(item==2)
{
if (mPaint.getMaskFilter() != mBlur) {
mPaint.setMaskFilter(mBlur);
} else {
mPaint.setMaskFilter(null);
}
}
if(item==3)
{
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
}
if(item==4)
{
saveImage();
}
}
});
builder.show();
}
});
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(20);
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },
0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}
public void colorChanged(int color) {
mPaint.setColor(color);
}
public class MyView extends View {
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context mcontext;
public MyView(Context c) {
super(c);
mcontext=c;
mPath = new Path();
mBitmapPaint = new Paint();
mBitmapPaint.setColor(Color.RED);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
Display display = ( (Activity) mcontext).getWindowManager().getDefaultDisplay();
float w = display.getWidth();
float h = display.getHeight();
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawLine(0, 0, w, 0,mBitmapPaint);
canvas.drawLine(0, 0, 0, h,mBitmapPaint);
canvas.drawLine(w,h,w,0,mBitmapPaint);
canvas.drawLine(w, h, 0,h , mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
public void saveImage()
{
AlertDialog.Builder editalert = new AlertDialog.Builder(FingerPaintActivity.this);
editalert.setTitle("Please Enter the name with which you want to Save");
final EditText input = new EditText(FingerPaintActivity.this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.FILL_PARENT);
input.setLayoutParams(lp);
editalert.setView(input);
editalert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
mv.setDrawingCacheEnabled(true);
String name= input.getText().toString();
Bitmap bitmap = mv.getDrawingCache();
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/MapleBearDraw");
myDir.mkdirs();
File file = new File (myDir, name+".jpg");
if (file.exists ()) file.delete ();
try
{
if(!file.exists())
{
file.createNewFile();
}
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 50, ostream);
ostream.flush();
ostream.close();
mv.invalidate();
}
catch (Exception e)
{
e.printStackTrace();
}finally
{
mv.setDrawingCacheEnabled(false);
}
}
});
editalert.show();
}
private static final int COLOR_MENU_ID = Menu.FIRST;
private static final int EMBOSS_MENU_ID = Menu.FIRST + 1;
private static final int BLUR_MENU_ID = Menu.FIRST + 2;
private static final int ERASE_MENU_ID = Menu.FIRST + 3;
private static final int SRCATOP_MENU_ID = Menu.FIRST + 4;
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, COLOR_MENU_ID, 0, "Color").setShortcut('3', 'c');
menu.add(0, EMBOSS_MENU_ID, 0, "Emboss").setShortcut('4', 's');
menu.add(0, BLUR_MENU_ID, 0, "Blur").setShortcut('5', 'z');
menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut('5', 'z');
menu.add(0, SRCATOP_MENU_ID, 0, "SrcATop").setShortcut('5', 'z');
/**** Is this the mechanism to extend with filter effects?
Intent intent = new Intent(null, getIntent().getData());
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
menu.addIntentOptions(
Menu.ALTERNATIVE, 0,
new ComponentName(this, NotesList.class),
null, intent, 0, null);
*****/
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
switch (item.getItemId()) {
case COLOR_MENU_ID:
new ColorPickerDialog(FingerPaintActivity.this, this, mPaint.getColor()).show();
return true;
case EMBOSS_MENU_ID:
if (mPaint.getMaskFilter() != mEmboss) {
mPaint.setMaskFilter(mEmboss);
} else {
mPaint.setMaskFilter(null);
}
return true;
case BLUR_MENU_ID:
if (mPaint.getMaskFilter() != mBlur) {
mPaint.setMaskFilter(mBlur);
} else {
mPaint.setMaskFilter(null);
}
return true;
case ERASE_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
return true;
case SRCATOP_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.SRC_ATOP));
mPaint.setAlpha(0x80);
return true;
}
return super.onOptionsItemSelected(item);
}
}