2

Here is the code for Drawing and Undoing but unable to join with Erasing.

It is either Drawing + Erasing or Drawing + Undoing but cannot three of these.

public class Drawing extends View {
private Paint mPaint, mBitmapPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;

private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;

private int color, size, state;

private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
private ArrayList<Integer> colors = new ArrayList<Integer>();
private ArrayList<Integer> sizes = new ArrayList<Integer>();

public Drawing(Context c) {
    super(c);
}

public Drawing(Context c,int width, int height, int size, int color, int state) {
    super(c);

    mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mBitmap);
    mPath = new Path();

    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);

//      mBitmapPaint = new Paint(Paint.DITHER_FLAG);
//      mBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));

    setColor(color);
    setSize(size);
    setState(state);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected void onDraw(Canvas canvas) {
//      canvas.drawColor(Color.TRANSPARENT);
//      canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
//
//      if (state == 0)
//          mBitmap.eraseColor(Color.TRANSPARENT);

    for (int i = 0; i < paths.size(); i++) {
        mPaint.setColor(colors.get(i));
        mPaint.setStrokeWidth(sizes.get(i));
        canvas.drawPath(paths.get(i), mPaint);
    }
    mPaint.setColor(color);
    mPaint.setStrokeWidth(size);
    canvas.drawPath(mPath, mPaint);

}

public void setColor(int color) {
    this.color = color;
}

public void setSize(int size) {
    this.size = size;
}

public void setState(int state) {
    this.state = state;
    // if (state == 0)
    // mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    // else
    // mPaint.setXfermode(null);
}

public void onClickUndo() {
    if (paths.size() > 0) {
        undonePaths.add(paths.remove(paths.size() - 1));
        sizes.remove(sizes.size() - 1);
        colors.remove(colors.size() - 1);
        invalidate();
    }
}

private void touch_start(float x, float y) {
    undonePaths.clear();
    mPath.reset();
    mPath.moveTo(x, y);
    mX = x;
    mY = y;
}

private void touch_move(float x, float y) {
    float dx = Math.abs(x - mX);
    float dy = Math.abs(y - mY);
    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
        mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
        mX = x;
        mY = y;
    }
}

private void touch_up() {
    mPath.lineTo(mX, mY);
    mCanvas.drawPath(mPath, mPaint);

    colors.add(color);
    sizes.add(size);
    paths.add(mPath);
    mPath = new Path();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        touch_start(x, y);
        invalidate();
        break;
    case MotionEvent.ACTION_MOVE:
        touch_move(x, y);
        invalidate();
        break;
    case MotionEvent.ACTION_UP:
        touch_up();
        invalidate();
        break;
    }
    return true;
}
}

I tried to made color to transparent but it does not make sense because not changing the pixel but is create new path.

Alan Lai
  • 1,296
  • 2
  • 12
  • 16
  • see this may be usefull not sure http://polamreddyn.blogspot.in/2012/10/free-hand-graw.html And this http://polamreddyn.blogspot.in/2013/02/paint-undo-and-redo-example.html – NagarjunaReddy Mar 19 '13 at 04:18
  • not suitable, cannot use erasecolor because my one is erase what it want instead whole bitmap – Alan Lai Mar 19 '13 at 06:39

1 Answers1

0

The below can be used to draw erase, emboss, save to gallery, blur. You can use the code to add undo and redo functionality. The below code works fine. You can slo check FingerPaint.java from the samples folder of your adk under api demos in the grapics folder.

Creating a spray effect on touch draw in android. This link will help you create spray effect by spraying dots.

public class FingerPaintActivity extends GraphicsActivity
    implements ColorPickerDialog.OnColorChangedListener {

    private Paint       mPaint;
    private MaskFilter  mEmboss;
    private MaskFilter  mBlur;
    Button b;
    Dialog dialog;
    static MyView mv;
    File f;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
    mv= new MyView(this);
    mv.setDrawingCacheEnabled(true);
    ll.addView(mv);
    b= (Button) findViewById(R.id.button1);
    b.setOnClickListener(new OnClickListener()
    {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            final CharSequence[] items = {"Pick Color", "Emboss", "Blur","Erase","SaveToGallery"};

            AlertDialog.Builder builder = new AlertDialog.Builder(FingerPaintActivity.this);
            builder.setTitle("Options");
            builder.setItems(items, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int item) {

                       if(item==0)
                       {
                           new ColorPickerDialog(FingerPaintActivity.this, FingerPaintActivity.this, mPaint.getColor()).show();
                       }
                       if(item==1)
                       {
                           if (mPaint.getMaskFilter() != mEmboss) {
                                mPaint.setMaskFilter(mEmboss);
                            } else {
                                mPaint.setMaskFilter(null);
                            }

                       }
                       if(item==2)
                       {
                           if (mPaint.getMaskFilter() != mBlur) {
                                mPaint.setMaskFilter(mBlur);
                            } else {
                                mPaint.setMaskFilter(null);
                            }
                       }
                       if(item==3)
                       {
                           mPaint.setXfermode(new PorterDuffXfermode(
                                   PorterDuff.Mode.CLEAR));
                       }
                       if(item==4)
                       {

                          saveImage();
                       }
                   }
               });


            builder.show();
        }


    });
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(0xFFFF0000);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(20);

    mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },
                                   0.4f, 6, 3.5f);

    mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}


public void colorChanged(int color) {
    mPaint.setColor(color);
}


public class MyView extends View {

    private static final float MINP = 0.25f;
    private static final float MAXP = 0.75f;

    private Bitmap  mBitmap;
    private Canvas  mCanvas;
    private Path    mPath;
    private Paint   mBitmapPaint;
    Context mcontext;

    public MyView(Context c) {
        super(c);
        mcontext=c;
        mPath = new Path();
        mBitmapPaint = new Paint();
        mBitmapPaint.setColor(Color.RED);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(0xFFAAAAAA);
        Display display = ( (Activity) mcontext).getWindowManager().getDefaultDisplay();  
        float w = display.getWidth(); 
        float h = display.getHeight();
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        canvas.drawLine(0, 0, w, 0,mBitmapPaint);
        canvas.drawLine(0, 0, 0, h,mBitmapPaint);
        canvas.drawLine(w,h,w,0,mBitmapPaint);
        canvas.drawLine(w, h, 0,h , mBitmapPaint);
        canvas.drawPath(mPath, mPaint);
    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }
    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
            mX = x;
            mY = y;
        }
    }
    private void touch_up() {
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
        // kill this so we don't double draw
        mPath.reset();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
        }
        return true;
    }
}
    public void saveImage()
    {
    AlertDialog.Builder editalert = new AlertDialog.Builder(FingerPaintActivity.this);
    editalert.setTitle("Please Enter the name with which you want to Save");
    final EditText input = new EditText(FingerPaintActivity.this);
    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.FILL_PARENT,
            LinearLayout.LayoutParams.FILL_PARENT);
    input.setLayoutParams(lp);
    editalert.setView(input);
    editalert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
        mv.setDrawingCacheEnabled(true);
        String name= input.getText().toString();
        Bitmap bitmap = mv.getDrawingCache();
     String root = Environment.getExternalStorageDirectory().toString();
        File myDir = new File(root + "/MapleBearDraw");    
        myDir.mkdirs();
        File file = new File (myDir, name+".jpg");
        if (file.exists ()) file.delete ();         
        try 
        {
            if(!file.exists())
        {
            file.createNewFile();
        }
            FileOutputStream ostream = new FileOutputStream(file);
            bitmap.compress(CompressFormat.JPEG, 50, ostream);
            ostream.flush();
            ostream.close();  
            mv.invalidate();                            
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }finally
        {

            mv.setDrawingCacheEnabled(false);                           
        }
        }
    });

    editalert.show();   
 }
private static final int COLOR_MENU_ID = Menu.FIRST;
private static final int EMBOSS_MENU_ID = Menu.FIRST + 1;
private static final int BLUR_MENU_ID = Menu.FIRST + 2;
private static final int ERASE_MENU_ID = Menu.FIRST + 3;
private static final int SRCATOP_MENU_ID = Menu.FIRST + 4;


public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);

    menu.add(0, COLOR_MENU_ID, 0, "Color").setShortcut('3', 'c');
    menu.add(0, EMBOSS_MENU_ID, 0, "Emboss").setShortcut('4', 's');
    menu.add(0, BLUR_MENU_ID, 0, "Blur").setShortcut('5', 'z');
    menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut('5', 'z');
    menu.add(0, SRCATOP_MENU_ID, 0, "SrcATop").setShortcut('5', 'z');

    /****   Is this the mechanism to extend with filter effects?
    Intent intent = new Intent(null, getIntent().getData());
    intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
    menu.addIntentOptions(
                          Menu.ALTERNATIVE, 0,
                          new ComponentName(this, NotesList.class),
                          null, intent, 0, null);
    *****/
    return true;
}

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    mPaint.setXfermode(null);
    mPaint.setAlpha(0xFF);

    switch (item.getItemId()) {
        case COLOR_MENU_ID:
            new ColorPickerDialog(FingerPaintActivity.this, this, mPaint.getColor()).show();
            return true;
        case EMBOSS_MENU_ID:
            if (mPaint.getMaskFilter() != mEmboss) {
                mPaint.setMaskFilter(mEmboss);
            } else {
                mPaint.setMaskFilter(null);
            }
            return true;
        case BLUR_MENU_ID:
            if (mPaint.getMaskFilter() != mBlur) {
                mPaint.setMaskFilter(mBlur);
            } else {
                mPaint.setMaskFilter(null);
            }
            return true;
        case ERASE_MENU_ID:
            mPaint.setXfermode(new PorterDuffXfermode(
                                                    PorterDuff.Mode.CLEAR));
            return true;
        case SRCATOP_MENU_ID:
            mPaint.setXfermode(new PorterDuffXfermode(
                                                PorterDuff.Mode.SRC_ATOP));
            mPaint.setAlpha(0x80);
            return true;
    }
    return super.onOptionsItemSelected(item);
}

}
Community
  • 1
  • 1
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • I updated my code, if I command out the drawitmap, Undo work fine but uncommand will not working. I saw your code almost similar with my code. – Alan Lai Mar 19 '13 at 07:08
  • If I use mBitmapPaint to drawbitmap, then undo cannot work. What I want is draw path on bitmap so that I can change the path pixel dynamically. I think this is more clear – Alan Lai Mar 19 '13 at 07:16
  • I got brush size on eraser so user can choose how large the size, I just tried by added `mPaint.setXfermode(new PorterDuffXfermode( PorterDuff.Mode.CLEAR));` it was disappear whole path and the path still keep in there, when I switch back to paint, the path will be draw again – Alan Lai Mar 19 '13 at 07:20
  • mPaint.setXfermode(new PorterDuffXfermode( PorterDuff.Mode.CLEAR)); clears the draw. For undo you need to remember the points of draw (store it arraylist) and remove the paths 1 at a time and redraw on canvas. Create a menu option and choose different options. You can change the brush size. – Raghunandan Mar 19 '13 at 07:39
  • the above code has an option to choose color, erase and draw. Add the undo feature to the same. – Raghunandan Mar 19 '13 at 07:43
  • mPaint.setXfermode(new PorterDuffXfermode( PorterDuff.Mode.CLEAR)); is for erasing. To the clear you have to reset the canvas. Reset every option of your draw. – Raghunandan Mar 19 '13 at 07:48
  • If remove entire path then no problem, I want to erase only a part only a path, this is the problem, I remembered all the paths before erase, after erase I remembered the path also and call again, It was the same that before I erase. – Alan Lai Mar 19 '13 at 07:56
  • For example, I draw straight line, I removed middle part, So the path only left front 1/3 and end 1/3 part of the path. – Alan Lai Mar 19 '13 at 07:57