The goal is to be able to write / sketch / draw something on top of the resulting image, as well as erase without destroying the image, while the image remains intact, and when the image is saved, the image and the background image will be included in the final output.
I created an application that takes a photo, then sends it to a new action for preview and editing, where I should be able to draw the image as a circle or some lines. I was able to do this by creating a bitmap and passing it through the new Canvas () constructor.
The problem with this is that I can write on the image, but when I use the erase mode, the image is also erased, I would like to implement something that would allow me to erase without destroying the background image, and at the same time the image the background will still be turned on when I save the image permanently.
The code for my presentation is below.
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
public class DrawingView extends View {
private Path drawPath;
private Paint drawPaint, canvasPaint;
private int paintColor = 0xFF660000, paintAlpha = 255;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private float brushSize, lastBrushSize;
private boolean erase=false;
Bitmap bg;
public DrawingView(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
}
private void setupDrawing(){
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
Resources res = getResources();
Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.background);
bg = bitmap.copy(Bitmap.Config.ARGB_8888, true);
}
@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(bg);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bg, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
invalidate();
return true;
}
public void setColor(String newColor){
invalidate();
if(newColor.startsWith("#")){
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
drawPaint.setShader(null);
}
else{
int patternID = getResources().getIdentifier(
newColor, "drawable", "com.example.drawingfun");
Bitmap patternBMP = BitmapFactory.decodeResource(getResources(), patternID);
BitmapShader patternBMPshader = new BitmapShader(patternBMP,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
drawPaint.setColor(0xFFFFFFFF);
drawPaint.setShader(patternBMPshader);
}
}
public void setBrushSize(float newSize){
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize=pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
public void setLastBrushSize(float lastSize){
lastBrushSize=lastSize;
}
public float getLastBrushSize(){
return lastBrushSize;
}
public void setErase(boolean isErase){
erase=isErase;
drawPaint.setColor(Color.parseColor("#FFFFFF"));
if(erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
else drawPaint.setXfermode(null);
drawPaint.setColor(paintColor);
}
public void startNew(){
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
public int getPaintAlpha(){
return Math.round((float)paintAlpha/255*100);
}
public void setPaintAlpha(int newAlpha){
paintAlpha=Math.round((float)newAlpha/100*255);
drawPaint.setColor(paintColor);
drawPaint.setAlpha(paintAlpha);
}
}
MainActivity.java is
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import java.util.UUID;
public class MainActivity extends Activity implements OnClickListener {
private DrawingView drawView;
private ImageButton currPaint, drawBtn, eraseBtn, newBtn, saveBtn, opacityBtn;
private float smallBrush, mediumBrush, largeBrush;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawView = (DrawingView)findViewById(R.id.drawing);
LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors);
currPaint = (ImageButton)paintLayout.getChildAt(0);
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
smallBrush = getResources().getInteger(R.integer.small_size);
mediumBrush = getResources().getInteger(R.integer.medium_size);
largeBrush = getResources().getInteger(R.integer.large_size);
drawBtn = (ImageButton)findViewById(R.id.draw_btn);
drawBtn.setOnClickListener(this);
drawView.setBrushSize(smallBrush);
eraseBtn = (ImageButton)findViewById(R.id.erase_btn);
eraseBtn.setOnClickListener(this);
newBtn = (ImageButton)findViewById(R.id.new_btn);
newBtn.setOnClickListener(this);
saveBtn = (ImageButton)findViewById(R.id.save_btn);
saveBtn.setOnClickListener(this);
opacityBtn = (ImageButton)findViewById(R.id.opacity_btn);
opacityBtn.setOnClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
public void paintClicked(View view){
drawView.setErase(false);
drawView.setPaintAlpha(100);
drawView.setBrushSize(drawView.getLastBrushSize());
if(view!=currPaint){
ImageButton imgView = (ImageButton)view;
String color = view.getTag().toString();
drawView.setColor(color);
imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint));
currPaint=(ImageButton)view;
}
}
@Override
public void onClick(View view){
if(view.getId()==R.id.draw_btn){
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Brush size:");
brushDialog.setContentView(R.layout.brush_chooser);
ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
smallBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(false);
drawView.setBrushSize(smallBrush);
drawView.setLastBrushSize(smallBrush);
brushDialog.dismiss();
}
});
ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
mediumBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(false);
drawView.setBrushSize(mediumBrush);
drawView.setLastBrushSize(mediumBrush);
brushDialog.dismiss();
}
});
ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
largeBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(false);
drawView.setBrushSize(largeBrush);
drawView.setLastBrushSize(largeBrush);
brushDialog.dismiss();
}
});
brushDialog.show();
}
else if(view.getId()==R.id.erase_btn){
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Eraser size:");
brushDialog.setContentView(R.layout.brush_chooser);
ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
smallBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(true);
drawView.setBrushSize(smallBrush);
brushDialog.dismiss();
}
});
ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
mediumBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(true);
drawView.setBrushSize(mediumBrush);
brushDialog.dismiss();
}
});
ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
largeBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(true);
drawView.setBrushSize(largeBrush);
brushDialog.dismiss();
}
});
brushDialog.show();
}
else if(view.getId()==R.id.new_btn){
AlertDialog.Builder newDialog = new AlertDialog.Builder(this);
newDialog.setTitle("New drawing");
newDialog.setMessage("Start new drawing (you will lose the current drawing)?");
newDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
drawView.startNew();
dialog.dismiss();
}
});
newDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
dialog.cancel();
}
});
newDialog.show();
}
else if(view.getId()==R.id.save_btn){
AlertDialog.Builder saveDialog = new AlertDialog.Builder(this);
saveDialog.setTitle("Save drawing");
saveDialog.setMessage("Save drawing to device Gallery?");
saveDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
drawView.setDrawingCacheEnabled(true);
String imgSaved = MediaStore.Images.Media.insertImage(
getContentResolver(), drawView.getDrawingCache(),
UUID.randomUUID().toString()+".png", "drawing");
if(imgSaved!=null){
Toast savedToast = Toast.makeText(getApplicationContext(),
"Drawing saved to Gallery!", Toast.LENGTH_SHORT);
savedToast.show();
}
else{
Toast unsavedToast = Toast.makeText(getApplicationContext(),
"Oops! Image could not be saved.", Toast.LENGTH_SHORT);
unsavedToast.show();
}
drawView.destroyDrawingCache();
}
});
saveDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
dialog.cancel();
}
});
saveDialog.show();
}
else if(view.getId()==R.id.opacity_btn){
final Dialog seekDialog = new Dialog(this);
seekDialog.setTitle("Opacity level:");
seekDialog.setContentView(R.layout.opacity_chooser);
final TextView seekTxt = (TextView)seekDialog.findViewById(R.id.opq_txt);
final SeekBar seekOpq = (SeekBar)seekDialog.findViewById(R.id.opacity_seek);
seekOpq.setMax(100);
int currLevel = drawView.getPaintAlpha();
seekTxt.setText(currLevel+"%");
seekOpq.setProgress(currLevel);
seekOpq.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
seekTxt.setText(Integer.toString(progress)+"%");
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
Button opqBtn = (Button)seekDialog.findViewById(R.id.opq_ok);
opqBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setPaintAlpha(seekOpq.getProgress());
seekDialog.dismiss();
}
});
seekDialog.show();
}
}
}