Related
I'm just trying to draw a basic triangle in Android Studio but nothing is showing up when I run the program. This is my first Android program so I don't really know what I'm doing. What is wrong with it?
public class CustomDrawableView extends View {
private ShapeDrawable mDrawable;
public CustomDrawableView(Context context, Display display) {
super(context);
Point size = new Point();
display.getSize(size);
int screenWidth = size.x;
int screenHeight = size.y;
int pathWidth = screenWidth / 6;
int startWidth = screenWidth / 10;
Path path = new Path();
path.moveTo(startWidth, 0);
path.moveTo(startWidth, screenHeight / 5);
path.moveTo(screenWidth / 5, screenHeight / 5);
path.close();
mDrawable = new ShapeDrawable(new PathShape(path, screenWidth, screenHeight));
mDrawable.setDither(true);
int color = Color.parseColor("#ff74AC23");
mDrawable.getPaint().setColor(color);
mDrawable.setBounds(0, 0 , screenWidth, screenHeight);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}
public class MainActivity extends AppCompatActivity {
CustomDrawableView mCustomDrawableView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Display display = getWindowManager().getDefaultDisplay();
mCustomDrawableView = new CustomDrawableView(this, display);
setContentView(mCustomDrawableView);
}
}
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
Hi I currently have a SurfaceView Runnable public class mapsLayout extends SurfaceView implements Runnable { which draws lines based on current geolocation. My previous solution involved having a main activity which contains the Android location manager - using a FusedLocationProviderClient as recommended by the tutorials provided by Google - and then calling the SurfaceView.
mainActivity with Android location manager -> 'SurfaceView'
However this means that the SurfaceView resets every time the location changes which happens every 10000 ticks.
Is there a way for the SurfaceView to contain the Android location manager.
If it helps I have my SurfaceView Runnable code below
public class mapsActivityLayout extends SurfaceView implements Runnable {
MyThread draw = null;
boolean canDraw = false;
Bitmap map;
SurfaceHolder surfaceHolder;
Context mContext;
Paint paint;
ArrayList<String> endNodes = new ArrayList<String>();
int bitmapX;
int bitmapY;
int viewWidth;
int viewHeight;
Paint red_paintbrush_fill, blue_paintbrush_fill, green_paintbrush_fill;
Paint red_paintbrush_stroke, blue_paintbrush_stroke, green_paintbrush_stroke;
Path line;
Path circle;
public mapsActivityLayout(Context context, ArrayList<String> endNodes) {
super(context);
this.endNodes = endNodes
mContext = context;
surfaceHolder = getHolder();
paint = new Paint();
paint.setColor(Color.DKGRAY);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
viewWidth = w;
viewHeight = h;
draw = new MyThread(viewWidth, viewHeight);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = true;
options.inMutable = true;
map = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.mapimage, options);
setUpBitmap();
}
#Override
public void run() {
Canvas canvas;
prepPaintBrushes();
while (canDraw) {
//draw stuff
if (surfaceHolder.getSurface().isValid()) {
int x = draw.getX();
int y = draw.getY();
//int radius = draw.getRadius();
canvas = surfaceHolder.lockCanvas();
canvas.save();
canvas.drawBitmap(map, bitmapX, bitmapY, paint);
ArrayList<Double> currentLocation = convertGeoToPixel(currentLat, currentLon);
ArrayList<Double> destination = convertGeoToPixel(destinationLat, destinationLat);
int width = 2699;
int height = 2699;
canvas.drawCircle(currentX, currentY, 20, red_paintbrush_fill);
canvas.drawCircle(destX, destY, 20, green_paintbrush_fill);
path.rewind();
canvas.restore();
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
private void updateFrame(int newX, int newY) {
draw.update(newX, newY);
}
/**
* Calculates a randomized location for the bitmap
* and the winning bounding rectangle.
*/
private void setUpBitmap() {
bitmapX = (int) Math.floor(
Math.random() * (viewWidth - backGround.getWidth()));
bitmapY = (int) Math.floor(
Math.random() * (viewHeight - backGround.getHeight()));
}
public void pause() {
canDraw = false;
while (true) {
try {
thread.join();
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void resume() {
canDraw = true;
thread = new Thread(this);
thread.start();
}
private void prepPaintBrushes() {
red_paintbrush_fill = new Paint();
red_paintbrush_fill.setColor(Color.RED);
red_paintbrush_fill.setStyle(Paint.Style.FILL);
green_paintbrush_stroke = new Paint();
green_paintbrush_stroke.setColor(Color.GREEN);
green_paintbrush_stroke.setStyle(Paint.Style.STROKE);
green_paintbrush_stroke.setStrokeWidth(10);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setUpBitmap();
updateFrame((int) x, (int) y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
updateFrame((int) x, (int) y);
invalidate();
break;
default:
}
return true;
}
}
thread code
public class MyThread extends Thread {
private int mX;
private int mY;
public MyThread(int viewWidth, int viewHeight) {
//super()
mX = viewWidth / 2;
mY = viewHeight / 2;
}
/**
* Update the coordinates of the map.
*
* #param newX Changed value for x coordinate.
* #param newY Changed value for y coordinate.
*/
public void update(int newX, int newY) {
mX = newX;
mY = newY;
}
public int getX() {
return mX;
}
public int getY() {
return mY;
}
}
FaceView.java
package com.example.richelle.neeuro;
public class FaceView extends View {
private float radius;
NormalFace normalFace;
HappyFace happyFace;
public FaceView(Context context, AttributeSet attrs) {
super(context, attrs);
// get radius value
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.FaceView,
0, 0
);
try {
radius = a.getDimension(R.styleable.FaceView_radius, 20.0f);
} finally {
a.recycle();
}
// initiate HappyFace class
normalFace = new NormalFace(radius);
happyFace = new HappyFace(radius);
}
Handler setDelay;
Runnable startDelay;
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
normalFace.draw(canvas);
//delay timer
setDelay = new Handler();
startDelay = new Runnable() {
#Override
public void run() {
happyFace.draw(canvas);
}
};
setDelay.postDelayed(startDelay,5000);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int desiredWidth = (int) radius*2+(int) Math.ceil((radius/1.70));
int desiredHeight = (int) radius*2+(int)Math.ceil((radius/1.70));
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
Log.d("Width AT_MOST", "width: "+width);
} else {
//Be whatever you want
width = desiredWidth;
Log.d("Width ELSE", "width: "+width);
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
}
NormalFace.java
public class NormalFace {
//Paint object
Paint facePaint;
Paint mePaint;
float radius;
float adjust;
float mouthLeftX, mouthRightX, mouthTopY, mouthBottomY;
RectF mouthRectF;
Path mouthPath;
float eyeLeftX, eyeRightx, eyeTopY, eyeBottomY;
RectF eyeLeftRectF, eyeRightRectF;
public NormalFace(float radius){
this.radius= radius;
facePaint = new Paint();
facePaint.setColor(0xfffed325); // face color - yellow
facePaint.setDither(true);
facePaint.setStrokeJoin(Paint.Join.ROUND);
facePaint.setStrokeCap(Paint.Cap.ROUND);
facePaint.setPathEffect(new CornerPathEffect(10) );
facePaint.setAntiAlias(true);
facePaint.setShadowLayer(4, 2, 2, 0x80000000);
mePaint = new Paint();
mePaint.setColor(0xff2a2a2a); //black
mePaint.setDither(true);
mePaint.setStyle(Paint.Style.STROKE);
mePaint.setStrokeJoin(Paint.Join.ROUND);
mePaint.setStrokeCap(Paint.Cap.ROUND);
mePaint.setPathEffect(new CornerPathEffect(10) );
mePaint.setAntiAlias(true);
mePaint.setStrokeWidth(radius / 14.0f);
adjust = radius / 3.2f;
// Left Eye
eyeLeftX = radius-(radius*0.43f);
eyeRightx = eyeLeftX + (radius*0.3f);
eyeTopY = radius-(radius*0.5f);
eyeBottomY = eyeTopY + (radius*0.4f);
eyeLeftRectF = new RectF(eyeLeftX+adjust,eyeTopY+adjust,eyeRightx+adjust,eyeBottomY+adjust);
// Right Eye
eyeLeftX = eyeRightx + (radius*0.3f);
eyeRightx = eyeLeftX + (radius*0.3f);
eyeRightRectF = new RectF(eyeLeftX+adjust,eyeTopY+adjust,eyeRightx+adjust,eyeBottomY+adjust);
// Mouth
mouthLeftX = radius-(radius/2.0f);
mouthRightX = mouthLeftX+ radius;
// mouthTopY = 125 - (125*0.01f);
// mouthBottomY = mouthTopY + (125*0.01f);
mouthTopY = radius - (radius*(-0.2f));
mouthBottomY = mouthTopY + (radius*0.01f);
mouthRectF = new RectF(mouthLeftX+adjust,mouthTopY+adjust,mouthRightX+adjust,mouthBottomY+adjust);
//mouthRectF = new RectF(mouthLeftX+adjust,mouthTopY+70,mouthRightX+adjust,mouthBottomY+20); //a line
mouthPath = new Path();
mouthPath.arcTo(mouthRectF, 30, 120, true);
// mouthPath.arcTo(mouthRectF, 15, 135, true);
}
public void draw(Canvas canvas) {
// 1. draw face
canvas.drawCircle(radius+adjust, radius+adjust, radius, facePaint);
// 2. draw mouth
mePaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mouthPath, mePaint);
//canvas.drawLine(90, 155, 176, 155, mePaint);
// 3. draw eyes
mePaint.setStyle(Paint.Style.FILL);
canvas.drawArc(eyeLeftRectF, 0, 360, true, mePaint);
canvas.drawArc(eyeRightRectF, 0, 360, true, mePaint);
}
}
HappyFace.java
public class HappyFace {
//Paint object
Paint facePaint;
Paint mePaint;
float radius;
float adjust;
float mouthLeftX, mouthRightX, mouthTopY, mouthBottomY;
RectF mouthRectF;
Path mouthPath;
float eyeLeftX, eyeRightx, eyeTopY, eyeBottomY;
RectF eyeLeftRectF, eyeRightRectF;
public HappyFace(float radius){
this.radius= radius;
facePaint = new Paint();
facePaint.setColor(0xfffed325); // face color - yellow
facePaint.setDither(true);
facePaint.setStrokeJoin(Paint.Join.ROUND);
facePaint.setStrokeCap(Paint.Cap.ROUND);
facePaint.setPathEffect(new CornerPathEffect(10) );
facePaint.setAntiAlias(true);
facePaint.setShadowLayer(4, 2, 2, 0x80000000);
mePaint = new Paint();
mePaint.setColor(0xff2a2a2a); //black
mePaint.setDither(true);
mePaint.setStyle(Paint.Style.STROKE);
mePaint.setStrokeJoin(Paint.Join.ROUND);
mePaint.setStrokeCap(Paint.Cap.ROUND);
mePaint.setPathEffect(new CornerPathEffect(10) );
mePaint.setAntiAlias(true);
mePaint.setStrokeWidth(radius / 14.0f);
adjust = radius / 3.2f;
// Left Eye
eyeLeftX = radius-(radius*0.43f);
eyeRightx = eyeLeftX + (radius*0.3f);
eyeTopY = radius-(radius*0.5f);
eyeBottomY = eyeTopY + (radius*0.4f);
eyeLeftRectF = new RectF(eyeLeftX+adjust,eyeTopY+adjust,eyeRightx+adjust,eyeBottomY+adjust);
// Right Eye
eyeLeftX = eyeRightx + (radius*0.3f);
eyeRightx = eyeLeftX + (radius*0.3f);
eyeRightRectF = new RectF(eyeLeftX+adjust,eyeTopY+adjust,eyeRightx+adjust,eyeBottomY+adjust);
// Smiley Mouth
mouthLeftX = radius-(radius/2.0f);
mouthRightX = mouthLeftX+ radius;
mouthTopY = radius - (radius*0.2f);
mouthBottomY = mouthTopY + (radius*0.5f);
mouthRectF = new RectF(mouthLeftX+adjust,mouthTopY+adjust,mouthRightX+adjust,mouthBottomY+adjust);
mouthPath = new Path();
mouthPath.arcTo(mouthRectF, 30, 120, true);
}
public void draw(Canvas canvas) {
// 1. draw face
canvas.drawCircle(radius+adjust, radius+adjust, radius, facePaint);
// 2. draw mouth
mePaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mouthPath, mePaint);
// 3. draw eyes
mePaint.setStyle(Paint.Style.FILL);
canvas.drawArc(eyeLeftRectF, 0, 360, true, mePaint);
canvas.drawArc(eyeRightRectF, 0, 360, true, mePaint);
}
}
FaceView.java is to display the different facial expressions in the canvas. The NormalFace.java and HappyFace.java are the UI of the different facial expressions. I want to add a delay timer in FaceView.java so that the display of the normal face can be change to a happy face after the timer had finished counting down.
Use this: ms is delay in millisecond
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
You can use Handler class for this in android.Handler has a method postDelayed(),you can use this method for the delay,read about handler from here
Runnable happy = new Runnable() {
public void run() {
happyFace(); //suppose this is the method for happy face
}
};
and then call this method like this after 5 sec
handler.postDelayed(happy,5000);
It will post your code to be run after 5 sec
You can use Handler to delay your next task
import android.os.Handler;
Handler handler=new Handler();
Runnable r=new Runnable() {
public void run() {
// Your next task
}
};
handler.postDelayed(r, 30000);
30000 is the value of delay in milli seconds which makes it 30 secs
I was trying to animate a sprite for an android app and i've encounter a small problem. I'm drawing on a surfaceView that i add on top of already existing layouts. On this surfaceView, i wanted to animate few sprites so they would walk along a path.
So this is the result i'm facing right now :
The walking sprite is leaving a trail. So i decided to google this problem and apparently i had to clear the canvas first before drawing on it.
This was my onDraw method before :
public void onDraw(Canvas canvas) {
update();
int srcX = currentFrame * width;
int srcY = directionX * 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);
}
And this was my onDraw method after
public void onDraw(Canvas canvas) {
canvas.drawRGB(0, 0, 0);
update();
int srcX = currentFrame * width;
int srcY = directionX * 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);
}
So i now have this as a result
which is great because it leaves no more trail BUT i cant see the layouts underneath. Is there anyway i can get the best of both world ? I thought clearing the canvas would work but it obviously doesnt not work as expected.
I'll post my code below
SurfaceView :
public class MonsterView extends SurfaceView {
private Bitmap monsterImg;
private SurfaceHolder holder;
private MonsterThread mainThread;
private Sprite monsterSprite;
private int x;
private int xSpeed = 1;
public MonsterView(Context context) {
super(context);
this.mainThread = new MonsterThread(this);
this.x = 0;
holder = getHolder();
holder.setFormat(PixelFormat.TRANSPARENT);
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
mainThread.setRunning(true);
mainThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mainThread.setRunning(false);
while (retry) {
try {
mainThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
});
setZOrderOnTop(true);
monsterImg = BitmapFactory.decodeResource(getResources(), R.drawable.fire);
monsterSprite = new Sprite(this,monsterImg);
}
#Override
public void onDraw(Canvas canvas) {
if (x == getWidth() - monsterImg.getWidth()) {
xSpeed = -1;
}
if (x == 0) {
xSpeed = 1;
}
x = x + xSpeed;
monsterSprite.onDraw(canvas);
}
Thread :
public class MonsterThread extends Thread {
private MonsterView monsterSurface;
private boolean running;
static final long FPS = 35;
public MonsterThread(MonsterView monsterSurface){
this.monsterSurface = monsterSurface;
this.running = false;
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while(running){
Canvas c = null;
startTime = System.currentTimeMillis();
try{
c = monsterSurface.getHolder().lockCanvas();
synchronized (monsterSurface.getHolder()){
monsterSurface.onDraw(c);
}
} finally {
if( c!= null){
monsterSurface.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if(sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e){}
}
}
public MonsterView getMonsterSurface() {
return monsterSurface;
}
public void setMonsterSurface(MonsterView monsterSurface) {
this.monsterSurface = monsterSurface;
}
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
Sprite :
public class Sprite {
private static final int BMP_ROWS = 4;
private static final int BMP_COLUMNS = 3;
private int x = 0;
private int y = 0;
private int xSpeed = 5;
private MonsterView monsterView;
private Bitmap bmp;
private int currentFrame = 0;
private int width;
private int height;
private int directionX;
public Sprite(MonsterView monsterView, Bitmap bmp) {
this.monsterView = monsterView;
this.bmp=bmp;
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
this.directionX = 2;
}
private void update() {
if (x > monsterView.getWidth() - width - xSpeed) {
xSpeed = -5;
directionX = 1;
}
if (x + xSpeed < 0) {
xSpeed = 5;
directionX = 2;
}
x = x + xSpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
Log.d("test", ""+currentFrame);
}
public void onDraw(Canvas canvas) {
update();
int srcX = currentFrame * width;
int srcY = directionX * 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);
}
You're using setZOrderOnTop(), which is putting the Surface part of the SurfaceView on a layer above everything else. (By default, it's a separate layer below everything else.) When you clear it with canvas.drawRGB(0, 0, 0) you're setting the entire layer to opaque black, which is going to obscure the View layer beneath it.
If instead you clear it to transparent black, with canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR), you should get the results you want.
FWIW, you shouldn't override onDraw() if you're only drawing on the Surface. The onDraw() method is called by the View hierarchy to draw on the View part of the SurfaceView. If something manages to invalidate the SurfaceView's View, your onDraw() will be called, and you'll end up with a character sprite on the View layer. (Depending on your layout this may not be visible.) Just give the method a different name.
There are a number of ways to handle this, but generally, the way to do this is by maintaining a background layer (which is just another image), and sprite layers. Instead of clearing, at each frame you blit (copy) your background onto the surface (which erases everything), then you blit your sprites.
So you're going to have to draw the background bitmap onto the surface first before drawing your sprite. Right now you're drawing black which is covering your background layouts.
Alternatively you might be able to do canvas.drawRect with a Paint with paint.setColor to Color.Transparent.