Android Paint: how to get "airbrush" effect? - java

I am following the "FingerPaint" demo in the API Demos.
I would need to get an "airbrush" effect, in the sense that when I draw over the same spot it gets darker and darker.
Please see the image:
as you can see the center is darker because I passed with the paint on the same spot more than one time.
Please how do I get the same effect, of getting darker a spot if drawn over more than one time?
EDIT EDIT EDIT
the suggested
mPaint.setAlpha(0x80)
kind of work, but only if I release touch and then touch again, if I do not release and keep the finger on the screen the effect is not reached.
The point is that you do not reach the effect if you do not release your finger from the screen, if you keep on drawing without releasing the touch it doesn't get darker when paint over. If you release the touch and then draw again you get the effect
This is the result I get. And I do not want:
this would be the desired result:
this is is the code taken form the API Demos:
public class FingerPaint extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyView(this));
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0x44FF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
private Paint mPaint;
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;
public MyView(Context c) {
super(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);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
canvas.drawBitmap(mBitmap, 0, 0, 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);
// 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;
}
}
}

I made only few minor changes in your code.
mPaint.setColor(Color.BLACK);// changed color to balck
mPaint.setAlpha(0x80); // only change
Activity class
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyView(this));
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setAlpha(0x80); // only change
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
private Paint mPaint;
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;
public MyView(Context c) {
super(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);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
canvas.drawBitmap(mBitmap, 0, 0, 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);
// 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;
}
}
}
snap shot

This approach is more of a simulation the way something like Photoshop would do it: Integrate along the path and draw individual paint splashes with an adjustable spacing inbetween.
public class DrawView extends View {
public Paint mPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private int strokeRadius;
private ShapeDrawable mBrush;
private Paint mBitmapPaint;
private float mPreviousX, mPreviousY;
public DrawView(Context context, AttributeSet attrs) {
super( context, attrs);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
int strokeWidth = 20;
strokeRadius = strokeWidth/2;
Shape brushShape = new OvalShape();
mBrush = new ShapeDrawable(brushShape);
Paint paint = mBrush.getPaint();
// radial gradient shader with a transparency falloff, if you don't want this,
// just set a color on the paint and remove the setShader call
Shader shader = new RadialGradient(strokeRadius, strokeRadius, strokeRadius,
Color.argb(255, 0, 0, 0), Color.argb(0, 0, 0, 0), Shader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAlpha(0x10);
}
#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(0xFF00B8F5);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
}
private void touch_start(float x, float y) {
mPreviousX = x;
mPreviousY = y;
}
private void touch_move(MotionEvent event)
{
float x = event.getX();
float y = event.getY();
// get vector from previous to current position
float xdist = x - mPreviousX;
float ydist = y - mPreviousY;
// get the length
float segmentLength = (float) Math.sqrt(xdist * xdist + ydist * ydist);
// derive a suitable step size from stroke width
float stepSize = Math.max(strokeRadius / 10, 1f);
// calculate the number of steps we need to take
// NOTE: this draws a bunch of evenly spaced splashes from the start point
// to JUST BEFORE the end point. The end point will be drawn by the start point of the
// next stroke, or by the touch_up method. If we drew both the start and
// end point there it would be doubled up
int steps = Math.max(Math.round(segmentLength / stepSize), 2);
for(int i = 0; i < steps; ++i)
{
int currentX = (int) (mPreviousX + xdist * i / steps);
int currentY = (int) (mPreviousY + ydist * i / steps);
drawSplash(currentX, currentY);
}
// update the previous position
mPreviousX = x;
mPreviousY = y;
}
private void touch_up(MotionEvent event) {
drawSplash((int) event.getX(), (int)event.getY());
}
/**
* draws the brush to the canvas, centered around x and y
* #param x
* #param y
*/
private void drawSplash(int x, int y)
{
mBrush.setBounds(x - strokeRadius, y - strokeRadius, x + strokeRadius, y + strokeRadius);
mBrush.draw(mCanvas);
}
#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(event);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up(event);
invalidate();
break;
}
return true;
}
}
Edit: snap shot (Raghunandan). Result Testing with White Background and Black Color paint.

Found the solution.
For those who might be interested:
public class DrawView extends View {
public Paint mPaint;
private Paint mPaint1;
private Paint mPaint2;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
public DrawView(Context context, AttributeSet attrs) {
super( context, attrs);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAlpha(0x80);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0x44000000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.BUTT);
mPaint.setStrokeWidth(5);
}
#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(0xFF00B8F5);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
}
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;
//mCanvas.drawPoint(x, y, mPaint);
}
private void touch_move(MotionEvent event) {
float x = event.getX();
float y = event.getY();
Path npath=new Path();
npath.moveTo(mX, mY);
npath.lineTo( x ,y );
mX=x;
mY=y;
mCanvas.drawPath(npath, mPaint);
npath.reset();
//Log.e("","sto disegando");
}
private void touch_up() {
}
#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(event);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
Edit: Attaching snap shot of my emulator (Raghunandan). I used your code no changes except increased the stroke width and it looks like below.
Does not look good when you draw slowly.
Screen shot stroke width 12 if you draw a striaght line no problem. But when you draw zig zag you can see it does not look good

Related

How to zoom canvas by two fingers and move?

I can draw by fingers in canvas, but I can not zoom it by two fingers without loss of scale drawn
and I want to do infinite my canvas size
I have this code:
public class MainActivity1 extends AppCompatActivity {
DrawingView dv ;
private Paint mPaint;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dv = new DrawingView(this);
setContentView(dv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(1000, 1000, 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);
canvas.drawPath( circlePath, circlePaint);
}
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;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// 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;
}
}
}
Please give me advice how to do it?
And I also want to do infinite my canvas size - its optional.
Main problem is zoom
My advice - you can use opengl. It's looks like you want to create some drawer, but canvas not perfect solution for this. Currently almost all devices support opengl es. It faster than canvas and you can made many another function(as scaling, image pasting, 3d objects etc.) much more easier. Here you can find a good tutorial.
Yoo should use ScaleGestureDetector to scale your canvas. This is my sample code:
private class MyScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener {
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
return true;
}
public boolean onScaleBegin(ScaleGestureDetector detector) {
Log.d("myZoomTag", "SCALE STARTED");
return true;
}
public void onScaleEnd(ScaleGestureDetector detector) {
Log.d("myZoomTag", "SCALE ENDED");
}
}
Here scaleFactor is global variable. In your onDraw method you should do something like this:
bitmapWidth *= scaleFactor;
bitmapHeight *= scaleFactor;

start paint from the circle android

I could program an application to draw but I have a problem
I want to start drawing from the circle,
my starting point will always be the circle, how could I do that?
Now I can draw from any point, I tried to find the middle of the screen but it did not work
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
path = new Path();
paint = new Paint();
paint.setColor(Color.RED);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(20f);
}
#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) {
super.onDraw(canvas);
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
int a = metrics.widthPixels; // to get width of the screen
int b = metrics.heightPixels;
canvas.drawCircle(a/2,((b/2)-160),50, paint);
if ((canDraw)) {
canvas.drawPath(path, paint);
}
}
private void startTouch (float x , float y){
if ((canDraw)) {
path.moveTo(x,y);
mX = x;
mY = y ;
}}
public void moveTouche (float x,float y ) {
if ((canDraw)) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if(dx >= Tolerance || dy >= Tolerance){
path.quadTo(mX,mY,(x+mX)/2,(y+mY)/2);
mX = x ;
mY = y;
}}
}
private void upTouch(){
if ((canDraw)) {
path.lineTo(mX,mY);
}}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
startTouch(x,y);
invalidate();
break ;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break ;
case MotionEvent.ACTION_MOVE:
moveTouche(x,y);
invalidate();
break;
}
return true ;
}
}
find the coordinates that delimit your central region from which touches must start, or create an element that identifies it
inside ouTouchEvent, write this:
case MotionEvent.ACTION_DOWN:
if (touchIsInsideCircle(x,y)) {
startTouch(x,y);
invalidate();
}
break ;
define a function that knows the center of the screen by using the coordinates predefined:
boolean touchIsInsideCircle(float x, float y) {
return (x < maxX && x > minX && y < maxY && y > minY);
}

java android - how to check drawing in canvas is finish or not?

i have one question,
I've made a project to draw an image. and it worked! but I am confused, I must add a button to check whether someone is really drawing all the parts of the image or not.
This is my code.
MainActivity.java
public class MainActivity extends Activity {
DrawingView dv;
private Paint mPaint;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dv = new DrawingView(this);
setContentView(dv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(5);
}
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context = c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#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);
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.asd) //-->here load your image
.copy(Bitmap.Config.ARGB_8888, true);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
canvas.drawPath(circlePath, circlePaint);
}
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;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// 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;
}
}
}
What from the code can be checked drawing?
and I do not know where to make checking function.
can you help me? thank you :)

How to implement undo/redo in my drawing app

I created an app to draw and wanted to implement the functions undo / redo, I tried various methods found surfing but none of them work, can someone help me?
Here is my code:
Variables
'public class MainDrawingView extends View {
public MainDrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
float TOUCH_TOLERANCE = 4;
float mX, mY;
//drawing path
private Path drawPath, drawX, drawY;
//drawing and canvas paint
private Paint drawPaint;
private Paint canvasPaint;
private View canvasback;
private Paint bccanvas;
//initial color
private int paintColor = 0xFF000000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap, trans;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();'
SetupDrawing
'private void setupDrawing() {
drawPath = new Path();
drawPaint = new Paint();
bccanvas = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(20);
drawPaint.setStyle(Paint.Style.FILL_AND_STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}'
onSizeChanged
'#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}'
Touch Event
'private void touch_start(float x, float y) {
undonePaths.clear();
drawPath.reset();
drawPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx, dy;
dx = Math.abs(x - mX);
dy = Math.abs(y - mY);
if ((dx >= TOUCH_TOLERANCE) || (dy >= TOUCH_TOLERANCE)) {
drawPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
drawPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
drawPath.lineTo(mX, mY);
// commit the path to our offscreen
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
drawPath.moveTo(mX, mY);
mX = x;
mY = y;
}
}
private void touch_up() {
drawPath.reset();
}'
onTouchEvent
'public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
drawPath.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
drawPath.lineTo(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
drawPath.reset();
touch_up();
invalidate();
break;
}
return true;
}'
onDraw
'#SuppressLint("NewApi")
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(p, drawPaint);
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
}'
onClickUndo
'public void onClickUndo () {
if (paths.size()>0){
undonePaths.add(paths.remove(paths.size()-1));
invalidate();
undonePaths.clear();
}
else
{
}
//toast the user
}'
onClickRedo
'public void onClickRedo (){
if (undonePaths.size()>0)
{
paths.add(undonePaths.remove(undonePaths.size()-1));
invalidate();
}
else
{
}
//toast the user
}'
TL;DR.
I created a similar application in Java Swing a couple of months ago. The way I implemented the 2 methods was I had created a Stack of shapes which was added to as the user was adding shapes to the whiteboard and then push/popped from this to undo/redo (storing the shape which was removed in a temp variable)
protected Shape removed; //shape object of an undo-ed object
protected Stack<Shape> shapes = new Stack<Shape>(); //stack to store the shapes
public void undo()
{
if (!shapes.empty()) //only undo if there's shapes on the board
{
removed = shapes.pop(); //pop removes a shape and returns it into 'removed' object
repaint();
}
}
public void redo()
{
if (removed != null) //only redo if something has been undone
{
shapes.push(removed); //push adds the object back onto the stack
removed = null;
repaint();
}
}
I hope this helps!
A good approach is to create an interface called something like "Undoable". It has at least 3 overrrides: do(), undo() and redo(). Then do all your work in classes that implement Undoable, and keep a stack of these around = the undo history.

How to make black background and red color for drawing?

I have been developing the application for drawing. I have following code for main activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
Display display = getWindow().getWindowManager().getDefaultDisplay();
mMainView = new MyView(this, display.getWidth(), display.getHeight());
setContentView(mMainView);
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(12);
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}
And code for my custom view for drawing:
public class MyView extends View {
private static final float TOUCH_TOLERANCE = 4;
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;
public MyView(Context context, int width, int height) {
super(context);
this.setDrawingCacheEnabled(true);
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
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);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFF000000);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
public void clearView() {
mBitmap.eraseColor(Color.TRANSPARENT);
}
public Bitmap getState() {
return mBitmap;
}
private void touchStart(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touchMove(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 touchUp() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// 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:
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touchUp();
invalidate();
break;
}
return true;
}
}
So, because if I try to save resulted bitmap as jpeg file using bitmap compress then all is good, but if I try to save as png file I will get file with transparent background (white) and red picture. I need that I can save using JPEG/PNG with black background and red picture. Code for saving is good, don't worry. Thank you.
you can draw a black rectangle on the bitmap, like so:
Bitmap myBitmap = Bitmap.createBitmap(width, height, ...);
Canvas mCanvas = new Canvas(myBitmap);
// create a black rectangle
final int color = 0xffffffff;
final Paint p1 = new Paint();
final Rect rect = new Rect(0, 0, width, height);
final RectF rectF = new RectF(rect);
// draw it to the canvas
mCanvas.drawARGB(0, 0, 0, 0);
p1.setColor(color);
mCanvas.drawRect(rectF, p1);
That should force a black background, and you can overlay additional bitmaps on the canvas, and finally use myBitmap to export as png.
I think the black background you have now is a jpeg default, since it does not have transparency.

Categories