What i have: Using the below code i am able to draw a pattern(Ex: Line) in the canvas.
What i am planning to do Or How to do this: I am trying to plot dots on that pattern in a uniform distance. (Hope i am clear)
ActDrawPaintImage.java
public class ActDrawPaintImage extends AppCompatActivity implements ColorPickerDialog.OnColorChangedListener {
MyView mv;
AlertDialog dialog;
#Bind(R.id.toolbar)
Toolbar mToolbar;
#Bind(R.id.btnNxtId)
Button btnNxtId;
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
LinearLayout canvasLayoutId;
boolean mDotToDraw=false;
private int BRUSHSIZE=20;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_draw_paint_image);
//Bind the views
ButterKnife.bind(this);
initToolbar();
onClickSet();
//ADD THE VIEW WHERE THE IMAGE IS DRAWN
setTheCanvasView();
//SET BRUSH PROPERTIES
setUpBrushProperties();
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}
private void onClickSet() {
btnNxtId.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mDotToDraw==false){
mDotToDraw=true;
}else{
mDotToDraw=false;
}
}
});
}
private void setTheCanvasView() {
mv= new MyView(this);
mv.setDrawingCacheEnabled(true);
canvasLayoutId=(LinearLayout) findViewById(R.id.canvasLayoutId);
canvasLayoutId.addView(mv);
}
private void setUpBrushProperties() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.pattern_color));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(BRUSHSIZE);
}
private void initToolbar() {
setSupportActionBar(mToolbar);
setTitle(getString(R.string.app_name));
mToolbar.setTitleTextColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.white));
}
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;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
Context context;
private int width;
private int height;
public MyView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width=w;
height=h;
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
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);
// kill this so we don't double draw
mPath.reset();
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
//mPaint.setMaskFilter(null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
//Create a pointer and log the output
Log.d("POINTS", x + "," + y);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(mDotToDraw==false){
touch_start(x, y);
}else{
touch_draw_circle(x, y);
}
invalidate();
break;
case MotionEvent.ACTION_MOVE:
if(mDotToDraw==false){
touch_move(x, y);
}else{
}
invalidate();
break;
case MotionEvent.ACTION_UP:
if(mDotToDraw==false){
touch_up();
}else{
}
invalidate();
break;
}
return true;
}
private void touch_draw_circle(float x, float y) {
/*int radius;
radius = 30;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
mCanvas.drawPaint(paint);
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor("#FF0000"));
mCanvas.drawCircle(x / 2, y / 2, radius, paint);*/
// mPath.quadTo(x, y, x + 0.1f, y);
/*Paint mPaint = new Paint();*/
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.white));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(BRUSHSIZE);
mPath.addCircle(x, y, mPaint.getStrokeWidth()/4f, Path.Direction.CW);
}
public void clear()
{
mBitmap = Bitmap.createBitmap(width,height , Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
invalidate();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
new MenuInflater(this).inflate(R.menu.draw_paint_image, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
switch (item.getItemId()) {
case R.id.COLOR_MENU_ID:
new ColorPickerDialog(this, this, mPaint.getColor()).show();
return true;
case R.id.EMBOSS_MENU_ID:
if (mPaint.getMaskFilter() != mEmboss) {
mPaint.setMaskFilter(mEmboss);
} else {
mPaint.setMaskFilter(null);
}
return true;
case R.id.BLUR_MENU_ID:
if (mPaint.getMaskFilter() != mBlur) {
mPaint.setMaskFilter(mBlur);
} else {
mPaint.setMaskFilter(null);
}
return true;
case R.id.ERASE_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mPaint.setAlpha(0x80);
return true;
case R.id.Clear:
mv.clear();
return true;
case R.id.Save:
AlertDialog.Builder editalert = new AlertDialog.Builder(ActDrawPaintImage.this);
editalert.setTitle("Please Enter the name with which you want to Save");
final EditText input = new EditText(ActDrawPaintImage.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) {
String name= input.getText().toString();
Bitmap bitmap = mv.getDrawingCache();
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
File file = new File("/sdcard/"+name+".png");
try
{
if(!file.exists())
{
file.createNewFile();
}
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 10, ostream);
ostream.close();
mv.invalidate();
}
catch (Exception e)
{
e.printStackTrace();
}finally
{
mv.setDrawingCacheEnabled(false);
}
}
});
editalert.show();
return true;
}
return super.onOptionsItemSelected(item);
}
}
EDIT
public class ActDrawPaintImage extends AppCompatActivity implements ColorPickerDialog.OnColorChangedListener {
MyView mv;
AlertDialog dialog;
#Bind(R.id.toolbar)
Toolbar mToolbar;
#Bind(R.id.btnNxtId)
Button btnNxtId;
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
LinearLayout canvasLayoutId;
boolean mDotToDraw=false;
private int BRUSHSIZE=20;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_draw_paint_image);
//Bind the views
ButterKnife.bind(this);
initToolbar();
onClickSet();
//ADD THE VIEW WHERE THE IMAGE IS DRAWN
setTheCanvasView();
//SET BRUSH PROPERTIES
setUpBrushProperties();
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}
private void onClickSet() {
btnNxtId.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mDotToDraw==false){
mDotToDraw=true;
}else{
mDotToDraw=false;
}
}
});
}
private void setTheCanvasView() {
mv= new MyView(this);
mv.setDrawingCacheEnabled(true);
canvasLayoutId=(LinearLayout) findViewById(R.id.canvasLayoutId);
canvasLayoutId.addView(mv);
}
private void setUpBrushProperties() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.pattern_color));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(BRUSHSIZE);
}
private void initToolbar() {
setSupportActionBar(mToolbar);
setTitle(getString(R.string.app_name));
mToolbar.setTitleTextColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.white));
}
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;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
Context context;
private int width;
private int height;
PathMeasure pathMeasure;
float[] position = new float[2];
float[] slope = new float[2]; // slope will give you the tangent of the position on the path. Not sure if you need this.
public MyView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
pathMeasure = new PathMeasure(mPath, false);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width=w;
height=h;
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
drawPlotPoints(canvas); // you should be able to implement this alone. It should draw a dot at a given x/y.
canvas.drawPath(mPath, mPaint);
}
private void drawPlotPoints(Canvas canvas) {
int amountOfPoints = (int)(pathMeasure.getLength() / 120f);
for (float distance = 0; distance <= 1; distance += 1f / amountOfPoints) {
pathMeasure.getPosTan(distance, position, slope);
touch_draw_circle(position[0], position[1]);
}
}
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;
}
//drawPlotPoints(x,y);
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
//mPaint.setMaskFilter(null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
//Create a pointer and log the output
//Log.d("POINTS", x + "," + y);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(mDotToDraw==false){
touch_start(x, y);
}else{
touch_draw_circle(x, y);
}
invalidate();
break;
case MotionEvent.ACTION_MOVE:
if(mDotToDraw==false){
touch_move(x, y);
}else{
}
invalidate();
break;
case MotionEvent.ACTION_UP:
if(mDotToDraw==false){
touch_up();
}else{
}
invalidate();
break;
}
return true;
}
private void touch_draw_circle(float x, float y) {
/*int radius;
radius = 30;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
mCanvas.drawPaint(paint);
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor("#FF0000"));
mCanvas.drawCircle(x / 2, y / 2, radius, paint);*/
// mPath.quadTo(x, y, x + 0.1f, y);
/*Paint mPaint = new Paint();*/
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.white));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(BRUSHSIZE);
mPath.addCircle(x, y, mPaint.getStrokeWidth()/4f, Path.Direction.CW);
}
public void clear()
{
mBitmap = Bitmap.createBitmap(width,height , Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
invalidate();
}
}
}
I am getting output as below:
I am trying to get output as like this:
If I understood you correctly, you're trying to discover certain positions on a given path, then draw dots on them where the distance between each dot should be the same.
You can achieve this using a PathMeasure object. Example:
boolean forceClose = false; //(set to true if you want to close the path or leave it open).
PathMeasure pathMeasure = new PathMeasure(path, forceClose);
float[] position = new float[2];
float[] slope = new float[2]; // slope will give you the tangent of the position on the path. Not sure if you need this.
for (float distance = 0; distance <= 1; distance += 1f / AMOUNT_OF_POINTS) {
pathMeasure.getPosTan(distance, position, slope);
drawDotAtPosition(position[0], position[1]); // you should be able to implement this alone. It should draw a dot at a given x/y.
}
The getPosTan method will give you the position on a given path after a certain ratio of the length has passed. This ratio is defined by AMOUNT_OF_POINTS which you can set to anything for a constant amount of points no matter what the length of the path is, or you could calculate it according to the length of the path:
// this will produce an amount of points equal to 1 point per 10 pixels along the whole path
int amountOfPoints = (int)(pathMeasure.getLength() / 10f);
Hope this helps.
I made this a while back, its not exactly my best work but it worked at the time. Maybe you can use it as a reference.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class line_graph extends View
{
private int padding = 0;
private int width = 0;//this is automatically
private int height = 0;
private Paint paint = new Paint();
private String[] labels;// labels for each column
private int[][] values;// values for each column
private String[] labelsHeadings;// headings for each segment of data
private float xInterval = 0;//space between x grid lines
private float yInterval = 0;//space between y grid lines
private int RowLineCount = 0; // amount of y grid lines
private float scale = 1; // this is automatically set according to the screen density
private int labelSpaceLeft = 0;// space on the left for labels
private int labelSpaceBottom = 0;// space on the bottom for labels
private int keySpace = 0;// space on the bottom for the key
private Path path = new Path();// bothe these paths are used for the shaded effect on the line graph
private Path path2 = new Path();
public line_graph(Context context)
{
this(context, null, 0);
}
public line_graph(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public line_graph(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
if(isInEditMode())
return;
scale = context.getResources().getDisplayMetrics().density;
labelSpaceLeft = (int)(40 * scale);
labelSpaceBottom = (int)(85 * scale);
keySpace = (int)(40 * scale);
}
public void setup(String[] labels, int[][] values, String[] labelsHeadings, int padding)
{
this.labels = labels;
this.values = values;
this.padding = padding;
this.labelsHeadings = labelsHeadings;
invalidate();
}
#Override
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld){
super.onSizeChanged(xNew, yNew, xOld, yOld);
width = xNew;
height = yNew;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode())
return;
try {
paint.reset();
paint.setAntiAlias(true);
paint.setTextSize(16);
paint.setTextAlign(Paint.Align.RIGHT);
int maxValue = 0;
for (int i = 0; i < values.length; i++) {
for (int j = 0; j < values[i].length; j++) {
maxValue = Math.max(maxValue, values[i][j]);
}
}
float innerWidth = width - padding * 2 - labelSpaceLeft;
float innerHeight = height - padding * 2 - labelSpaceBottom - keySpace;
float lx = padding;
paint.setTextAlign(Paint.Align.LEFT);
for (int i = 0; i < values.length; i++) {
paint.setColor(getNextColour(i));
//calculate space for circles
lx += 15 * scale;
//calculate space key label
if (labelsHeadings.length > i) {
lx += padding + paint.measureText(labelsHeadings[i]);
if (i < values.length - 1 && lx + paint.measureText(labelsHeadings[i + 1]) > width) {
lx = padding + labelSpaceLeft;
innerHeight += paint.ascent();
}
}
}
lx = padding + labelSpaceLeft;
float ly = innerHeight + padding*2 + labelSpaceBottom;
paint.setTextAlign(Paint.Align.LEFT);
for (int i = 0; i < values.length; i++) {
paint.setColor(getNextColour(i));
//draw circles
canvas.drawOval(new RectF(lx - 5 * scale, ly - 5 * scale, lx + 5 * scale, ly + 5 * scale), paint);
lx += 15 * scale;
//draw key label
canvas.drawText(labelsHeadings[i], lx, ly - paint.ascent() / 2, paint);
if (labelsHeadings.length > i) {
lx += padding + paint.measureText(labelsHeadings[i]);
if (i < values.length - 1 && lx + paint.measureText(labelsHeadings[i + 1]) > width) {
lx = padding + labelSpaceLeft;
ly -= paint.ascent();
innerHeight += paint.ascent();
}
}
}
xInterval = innerWidth / (labels.length-1);
RowLineCount = (int) Math.min(Math.max(innerHeight / Math.ceil(40 * scale), 2), maxValue/2);
yInterval = innerHeight / RowLineCount;
int currentValue = maxValue;
float y;
paint.setTextAlign(Paint.Align.RIGHT);
for (int i = 0; i < RowLineCount+1; i++) {
//draw left label
y = yInterval * i + padding;
paint.setColor(0xffaaaaaa);
canvas.drawText(String.valueOf(currentValue), labelSpaceLeft, y - paint.ascent()/2, paint);
currentValue = Math.max(currentValue - maxValue/RowLineCount,0);
//draw x grid line
paint.setColor(0xffeeeeee);
canvas.drawLine(padding + labelSpaceLeft, y, innerWidth + padding + labelSpaceLeft, y, paint);
}
float x;
for (int i = 0; i < labels.length; i++) {
//draw bottom label rotated
x = xInterval * i + padding + labelSpaceLeft;
if(i != labels.length) {
canvas.save();
canvas.rotate(300, x, innerHeight + padding*2 - paint.ascent()/2);
paint.setColor(0xffaaaaaa);
canvas.drawText(labels[i], x, innerHeight + padding*2 - paint.ascent()/2, paint);
canvas.restore();
}
//draw y grid line
paint.setColor(0xffeeeeee);
canvas.drawLine(x, padding, x, innerHeight + padding, paint);
}
paint.setStyle(Paint.Style.FILL);
for (int i = 0; i < values.length; i++) {
paint.setColor(getNextColour(i));
path.rewind();
path2.rewind();
for (int j = 0; j < values[i].length; j++)
{
x = xInterval * j + padding + labelSpaceLeft;
y = innerHeight + padding - (innerHeight * values[i][j] / maxValue);
//draw lines
if(j == 0) {
path2.moveTo(padding + labelSpaceLeft, innerHeight + padding);
path.moveTo(x, y);
}
else
path.lineTo(x,y);
path2.lineTo(x, y);
//canvas.drawLine(xOld,yOld,x,y,paint);
//draw circles
canvas.drawOval(new RectF(x - 5 * scale, y - 5 * scale, x + 5 * scale, y + 5 * scale), paint);
}
//draw line
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
canvas.drawPath(path, paint);
//draw shaded area
path2.lineTo(innerWidth + padding + labelSpaceLeft, innerHeight + padding);
paint.setARGB(20, Color.red(paint.getColor()), Color.green(paint.getColor()), Color.blue(paint.getColor()));
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path2, paint);
}
}
catch (Exception ignored){}
}
//used to get the next color in the series
public static int getNextColour(int index)
{
int[] colours = new int[]{0xFF4CAF50,
0xFF9C27B0,
0xFFF44336,
0xFF00BCD4,
0xFFE91E63,
0xFF03A9F4,
0xFFFF9800,
//0xFFFFEB3B,//removed bright yellow
0xFF9E9E9E,
0xFF795548,
0xFF8BC34A,
0xFF607D8B,
0xFF009688,
0xFFFFC107,
0xFF673AB7,
0xFF2196F3,
0xFFCDDC39,
0xFF3F51B5,
0xFFFF5722};
return colours[index % colours.length];
}
}
its used like this:
line_graph graph = (line_graph)findViewById(R.id.lineGraph);
graph.setup(
//labels
new String[]{"heading1","heading2","heading3","heading4","heading5","heading6","heading7"},
//Values
new int[][]{new int[]{1,4,8,2,5,9,12},new int[]{2,5,2,8,5,2,6},new int[]{8,2,9,23,7,1,11}},
//Series Headings
new String[]{"Series 1", "Series 2", "Series 3"},
//Padding
20);
xml:
<line_graph
android:id="#+id/lineGraph"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
it looks like this:
And yes i do realize this could be made better and that it had poor exception handling. But its just an example.
I am making an application I am unable to one issue last 3 days doing google as much possible.I make a circle on canvas and want to crop image that part and show that image in zoom mode.My first step is like in screen here:-
in this I am selecting area.here is my code used by me for this.
private float x, y;
private boolean zooming = false;
private Paint mPaint;
private Matrix mmatrix;
private Shader mShader;
private Bitmap mBitmap;
private List<Point> mpoints;
private List<MyPoints> mpointlist;
private Path mpath;
private Canvas mcanvas;
private Bitmap mresult_bitmap, resultingImage,finalbitmap;
private Context mcontext;
private boolean bfirstpoint = false;
private Point mfirstpoint = null;
private Point mlastpoint = null;
public CircularZoomView(Context context) {
super(context);
mcontext = context;
mpath = new Path();
mpoints = new ArrayList<Point>();
setBackgroundResource(R.drawable.testing);
mPaint = new Paint();
mresult_bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.testing);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setPathEffect(new DashPathEffect(new float[] { 10, 20 }, 0));
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.RED);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (zooming && resultingImage!=null) {
zooming = false;
ShowImage(resultingImage);
canvas.drawBitmap(resultingImage,mmatrix, null);
}
boolean first = true;
for (int i = 0; i < mpoints.size(); i += 2) {
Point point = mpoints.get(i);
if (first) {
first = false;
mpath.moveTo(point.x, point.y);
} else if (i < mpoints.size() - 1) {
Point next = mpoints.get(i + 1);
mpath.quadTo(point.x, point.y, next.x, next.y);
} else {
mlastpoint = mpoints.get(i);
mpath.lineTo(point.x, point.y);
}
}
canvas.drawPath(mpath, mPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
x = event.getX();
y = event.getY();
Point point = new Point();
point.x = (int) event.getX();
point.y = (int) event.getY();
if (bfirstpoint) {
if (comparepoint(mfirstpoint, point)) {
mpoints.add(mfirstpoint);
addCircleFromPath(mpath);
} else {
mpoints.add(point);
}
} else {
mpoints.add(point);
}
if (!(bfirstpoint)) {
mfirstpoint = point;
bfirstpoint = true;
}
invalidate();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
zooming = false;
this.invalidate();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
zooming = true;
mlastpoint = point;
if (mpoints.size() > 12) {
if (!comparepoint(mfirstpoint, mlastpoint)) {
mpoints.add(mfirstpoint);
addCircleFromPath(mpath);
}
}
this.invalidate();
break;
default:
break;
}
return true;
}
public Bitmap getCroppedBitmap(Bitmap bitmap) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
bitmap.getWidth() / 2, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
void ShowImage(Bitmap mbitmap) {
Display display = ((MainActivity) mcontext).getWindowManager().getDefaultDisplay();
int screenWidth = display.getWidth();
float imageWidth = (float)mbitmap.getWidth();
float imageHeight = (float)mbitmap.getHeight();
float newHeight = imageHeight / (imageWidth / screenWidth);
float newWidth = screenWidth;
float scaleWidth = screenWidth / imageWidth;
float scaleHeight = newHeight / imageHeight;
SetImageMatrix(mbitmap,scaleWidth,scaleHeight);
}
void SetImageMatrix(Bitmap image,float scaleWidth, float scaleHeight) {
mmatrix = new Matrix();
mmatrix.setTranslate(40,40);
mmatrix.postScale(scaleWidth/2, scaleHeight/2);
/*image.setImageMatrix(mmatrix);
image.setScaleType(ScaleType.MATRIX);
image.invalidate();*/
}
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 (mpoints.size() < 10) {
return false;
} else {
return true;
}
} else {
return false;
}
}
private void addCircleFromPath(Path path){
RectF bounds = new RectF();
path.computeBounds(bounds, true);
int width = (int) (bounds.right-bounds.left);
int height = (int) (bounds.bottom-bounds.top);
if(width<20 && height<20){
path.reset();
return;
}
int radius ;
if(width>=height)
radius = Math.round(((width/2)));
else radius = Math.round((int) ((height/2)));
/*CircleTagObject circle = new CircleTagObject((int)bounds.left+width/2, (int)bounds.top+height/2, radius, crossBitmap, tagBitmap,circleArray.size(),
ImageEditorView.this);
circleArray.add(circle);
tagBallID = circleArray.size() - 1;
dragEnable = true;*/
resultingImage = getCroppedBitmap(Bitmap.createBitmap(mresult_bitmap,0,0,200,200));
mcanvas = new Canvas(resultingImage);
path.reset();
resetView();
invalidate();
}
public void resetView() {
mpoints.clear();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setPathEffect(new DashPathEffect(new float[] { 10, 20 }, 0));
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.RED);
invalidate();
}
If I create hard coded bitmap like above its showing good but not crop bitmap of selected part.Like this image.
but when add exact coordinate of selected area Like as:-
resultingImage = getCroppedBitmap(Bitmap.createBitmap(mresult_bitmap,(int)bounds.left,(int)bounds.top,width,height));
Then exception occure:-
07-12 10:58:56.700: E/MessageQueue-JNI(12310): java.lang.IllegalArgumentException: y + height must be <= bitmap.height()
07-12 10:58:56.700: E/MessageQueue-JNI(12310): at android.graphics.Bitmap.createBitmap(Bitmap.java:565)
07-12 10:58:56.700: E/MessageQueue-JNI(12310): at android.graphics.Bitmap.createBitmap(Bitmap.java:530)
07-12 10:58:56.700: E/MessageQueue-JNI(12310): at com.intel.view.CircularZoomView.addCircleFromPath(CircularZoomView.java:237)
I know why This exception occurs but unable to find solution how crop image of selected part.Thanks in advance.
I know its too late for your solution but this may help to others Use of this code
help you to come out from this problem.
I'm making a custom slide control. Is like a Volume wheel, so some values augment or decrease depending on rotate direction.
I have two issues with this:
The performance is really low
The garbage collector is trigger, many many times.
Well, I'm sure that i'm doing something wrong, so please give me a Light.
Am working with Android graphics on 2.1 (eclaire) SDK.
This is the code of the view that am calling from my activity:
public class DrawingView extends View {
private Paint p;
Bitmap bitmap;
Context mContext;
Canvas canvas;
private float sweepAngle;
private int _height;
private int _width;
private float lastAngle;
private int percent;
public DrawingView(Context context) {
super(context);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
this.set_Width(display.getWidth());
this.set_Height(display.getHeight());
this.setSweepAngle(10);
mContext = context;
p = new Paint();
p.setAntiAlias(true);
}
protected int getAngleFromLocation(Point location){
int finalAngle = (int) (Math.atan2(location.y - 200, location.x - 200) * (180 / Math.PI));
return finalAngle;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(),Bitmap.Config.ARGB_8888);
this.canvas = new Canvas(bitmap);
RectF rectF = new RectF();
rectF.set(20, 20, this.get_Widtt() - this.get_Widtt()/10, this.get_Widtt() - this.get_Widtt()/10);
canvas.drawArc(rectF, 180, this.getSweepAngle(), true, p);
//invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
double increment = 3.6;
Point touchLocation = new Point();
touchLocation.x = (int)event.getX();
touchLocation.y = (int)event.getY();
canvas.drawBitmap(bitmap = Bitmap.createBitmap(canvas.getWidth(),canvas.getHeight(),Bitmap.Config.ARGB_8888),event.getX(), event.getY(),null );
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
lastAngle = this.getAngleFromLocation(touchLocation);
System.out.println("ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("ACTION_MOVE");
int currentAngle = this.getAngleFromLocation(touchLocation);
System.out.println("CURRENT ANGLE: " + currentAngle);
if (currentAngle > lastAngle || (currentAngle == 1 && lastAngle == 359)) {
percent += increment;
} else if (currentAngle < lastAngle) {
percent -= increment;
}
if (percent > 360) {
percent = 360;
} else if (percent < 0) {
percent = 0;
}
lastAngle = currentAngle;
this.setSweepAngle(percent);
//Write the label
//int realPercent = percent*100/360;
System.out.println("PERCENT: "+percent);
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
}
No need to create a new bitmap on every frame. In fact you should try to avoid allocationg any objects at all in onDraw().
Try this:
private RectF mRectF = new RectF();
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLACK);
mRectF.set(20, 20, this.get_Widtt() - this.get_Widtt() / 10, this.get_Widtt() - this.get_Widtt() / 10);
canvas.drawArc(rectF, 180, this.getSweepAngle(), true, p);
}
also remove the call to canvas.drawBitmap() in onTouchEvent.
It's most likely the bitmap/canvas creation that's taking so long and triggering the GC so much. You want to do as little object creation as possible during onDraw() in particular, and onTouchEvent() as well. Is there any reason you can't move that to a separate method that gets called once and reuse the same bitmap each frame? It looks like the values you're passing to createBitmap() are static, so it shouldn't be an issue.
I have a little drawing app and want to use "complex" shapes as brushes, i.e. a star.
Drawing with a simple brush already works with this code:
remotePath.reset();
remotePath.moveTo(start_x, start_y);
float dx = Math.abs(end_x - start_x);
float dy = Math.abs(end_y - start_y);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
remotePath.quadTo(start_x, start_y, (end_x + start_x) / 2, (end_y + start_y) / 2);
}
remotePath.lineTo(end_x, end_y);
// commit the path to our offscreen
mCanvas.drawPath(remotePath, remotePaint);
// kill this so we don't double draw
remotePath.reset();
invalidate();
I basically want the same functionality using this bitmap:
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.brush_star);
My solution currently is using a list of points (coordinates) to draw the bitmap. The problem with that solution is that it only draws bitmaps at the given points resulting in having gaps between each drawn bitmap. I rather would like to get a smooth line while drawing like with a simple brush without any gaps in between.
Current code for the bitmap drawing:
protected void onDraw(Canvas canvas) {
// Make canvas white
canvas.drawColor(Color.WHITE);
// Paintable area
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
for (Point point : points) {
canvas.drawBitmap(complexBrush, point.x, point.y, p);
}
}
What's the best way to do so?
Thanks for any help!
I use this
Point's class:
public class Point implements Serializable {
float x, y;
float dx, dy;
}
Paint object:
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
paint.setAntiAlias(true);
draw on canvas:
private void drawCanvas(Canvas canvas, List<Point> pts){
if (pts.size() > 1){
Path path = new Path();
final int SMOOTH_VAL = 6;
for(int i = pts.size() - 2; i < pts.size(); i++){
if(i >= 0){
Point point = pts.get(i);
if(i == 0){
Point next = pts.get(i + 1);
point.dx = ((next.x - point.x) / SMOOTH_VAL);
point.dy = ((next.y - point.y) / SMOOTH_VAL);
}
else if(i == pts.size() - 1){
Point prev = pts.get(i - 1);
point.dx = ((point.x - prev.x) / SMOOTH_VAL);
point.dy = ((point.y - prev.y) / SMOOTH_VAL);
}
else{
Point next = pts.get(i + 1);
Point prev = pts.get(i - 1);
point.dx = ((next.x - prev.x) / SMOOTH_VAL);
point.dy = ((next.y - prev.y) / SMOOTH_VAL);
}
}
}
boolean first = true;
for(int i = 0; i < pts.size(); i++){
Point point = pts.get(i);
if(first){
first = false;
path.moveTo(point.x, point.y);
}
else{
Point prev = pts.get(i - 1);
path.cubicTo(prev.x + prev.dx, prev.y + prev.dy, point.x - point.dx, point.y - point.dy, point.x, point.y);
}
}
canvas.drawPath(path, paint);
} else {
if (pts.size() == 1) {
Point point = pts.get(0);
canvas.drawCircle(point.x, point.y, 2, paint);
}
}
}
Draw on bitmap canvas:
private void drawBitmap(Bitmap bmp, List<Point> pts) {
Canvas c = new Canvas(bmp);
drawCanvas(c, pts);
}
I'm trying to figure out how to wite a simple drawing program in Android. I saw a sample program that stored each stroke in a array, then played back the array when the screen needed to be updated. To me this did not seem to proctical. I would like to draw in a bitmap, and the update would just draw the bitmap instad of every stroke. ( i could not figure out how to do this in android)
Any thoughts
?
Ted
Look at the Android samples: there are a couple of moderately complicated bits, but this is from the Sensors.java api demo in the Android SDK. It demonstrates the bitmap manipulation:
private class GraphView extends View implements SensorEventListener
{
private Bitmap mBitmap;
private Paint mPaint = new Paint();
private Canvas mCanvas = new Canvas();
private Path mPath = new Path();
private RectF mRect = new RectF();
private float mLastValues[] = new float[3*2];
private float mOrientationValues[] = new float[3];
private int mColors[] = new int[3*2];
private float mLastX;
private float mScale[] = new float[2];
private float mYOffset;
private float mMaxX;
private float mSpeed = 1.0f;
private float mWidth;
private float mHeight;
public GraphView(Context context) {
super(context);
mColors[0] = Color.argb(192, 255, 64, 64);
mColors[1] = Color.argb(192, 64, 128, 64);
mColors[2] = Color.argb(192, 64, 64, 255);
mColors[3] = Color.argb(192, 64, 255, 255);
mColors[4] = Color.argb(192, 128, 64, 128);
mColors[5] = Color.argb(192, 255, 255, 64);
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mRect.set(-0.5f, -0.5f, 0.5f, 0.5f);
mPath.arcTo(mRect, 0, 180);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
mCanvas.setBitmap(mBitmap);
mCanvas.drawColor(0xFFFFFFFF);
mYOffset = h * 0.5f;
mScale[0] = - (h * 0.5f * (1.0f / (SensorManager.STANDARD_GRAVITY * 2)));
mScale[1] = - (h * 0.5f * (1.0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
mWidth = w;
mHeight = h;
if (mWidth < mHeight) {
mMaxX = w;
} else {
mMaxX = w-50;
}
mLastX = mMaxX;
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
synchronized (this) {
if (mBitmap != null) {
final Paint paint = mPaint;
final Path path = mPath;
final int outer = 0xFFC0C0C0;
final int inner = 0xFFff7010;
if (mLastX >= mMaxX) {
mLastX = 0;
final Canvas cavas = mCanvas;
final float yoffset = mYOffset;
final float maxx = mMaxX;
final float oneG = SensorManager.STANDARD_GRAVITY * mScale[0];
paint.setColor(0xFFAAAAAA);
cavas.drawColor(0xFFFFFFFF);
cavas.drawLine(0, yoffset, maxx, yoffset, paint);
cavas.drawLine(0, yoffset+oneG, maxx, yoffset+oneG, paint);
cavas.drawLine(0, yoffset-oneG, maxx, yoffset-oneG, paint);
}
canvas.drawBitmap(mBitmap, 0, 0, null);
float[] values = mOrientationValues;
if (mWidth < mHeight) {
float w0 = mWidth * 0.333333f;
float w = w0 - 32;
float x = w0*0.5f;
for (int i=0 ; i<3 ; i++) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(x, w*0.5f + 4.0f);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
paint.setColor(outer);
canvas.scale(w, w);
canvas.drawOval(mRect, paint);
canvas.restore();
canvas.scale(w-5, w-5);
paint.setColor(inner);
canvas.rotate(-values[i]);
canvas.drawPath(path, paint);
canvas.restore();
x += w0;
}
} else {
float h0 = mHeight * 0.333333f;
float h = h0 - 32;
float y = h0*0.5f;
for (int i=0 ; i<3 ; i++) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(mWidth - (h*0.5f + 4.0f), y);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
paint.setColor(outer);
canvas.scale(h, h);
canvas.drawOval(mRect, paint);
canvas.restore();
canvas.scale(h-5, h-5);
paint.setColor(inner);
canvas.rotate(-values[i]);
canvas.drawPath(path, paint);
canvas.restore();
y += h0;
}
}
}
}
}
public void onSensorChanged(SensorEvent event) {
//Log.d(TAG, "sensor: " + sensor + ", x: " + values[0] + ", y: " + values[1] + ", z: " + values[2]);
synchronized (this) {
if (mBitmap != null) {
final Canvas canvas = mCanvas;
final Paint paint = mPaint;
if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
for (int i=0 ; i<3 ; i++) {
mOrientationValues[i] = event.values[i];
}
} else {
float deltaX = mSpeed;
float newX = mLastX + deltaX;
int j = (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) ? 1 : 0;
for (int i=0 ; i<3 ; i++) {
int k = i+j*3;
final float v = mYOffset + event.values[i] * mScale[j];
paint.setColor(mColors[k]);
canvas.drawLine(mLastX, mLastValues[k], newX, v, paint);
mLastValues[k] = v;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mLastX += mSpeed;
}
invalidate();
}
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}