I am trying to implement an application to get an image from the device and add it to the canvas then start drawing on it using brush and eraser (like snapchat idea)
I used Drawing app as a base
http://code.tutsplus.com/series/create-a-drawing-app-on-android--cms-704
My problem for now is that when I draw on the bitmap it start drawing but when I finished and touch up the drawing disappear.
this is a video for the problem
https://vid.me/rgnF (try to mute the sound there is some noise :) )
any help would be appreciated. Thank you
public class DrawingView extends View {
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
public Bitmap canvasBitmap;
//brush sizes
private float brushSize, lastBrushSize;
//erase flag
private boolean erase=false;
public DrawingView(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
}
//setup drawing
private void setupDrawing(){
//prepare for drawing and setup paint stroke properties
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);
}
//size assigned to view
#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);
}
//draw the view - will be called after touch event
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
//respond to down, move and up events
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;
}
//redraw
invalidate();
return true;
}
//update color
public void setColor(String newColor){
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
//set brush size
public void setBrushSize(float newSize){
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize=pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
//get and set last brush size
public void setLastBrushSize(float lastSize){
lastBrushSize=lastSize;
}
public float getLastBrushSize(){
return lastBrushSize;
}
//set erase true or false
public void setErase(boolean isErase){
erase=isErase;
if(erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
else drawPaint.setXfermode(null);
}
//start new drawing
public void startNew(){
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
}
public class MainActivity extends Activity implements OnClickListener {
//custom drawing view
private DrawingView drawView;
//buttons
private ImageButton currPaint, drawBtn, eraseBtn, newBtn, saveBtn;
//sizes
private float smallBrush, mediumBrush, largeBrush;
Button mBtnPick;
int mWidth;
int mHeight;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWidth = mHeight = 0;
//get drawing view
drawView = (DrawingView)findViewById(R.id.drawing);
//get the palette and first color button
LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors);
currPaint = (ImageButton)paintLayout.getChildAt(0);
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
//sizes from dimensions
smallBrush = getResources().getInteger(R.integer.small_size);
mediumBrush = getResources().getInteger(R.integer.medium_size);
largeBrush = getResources().getInteger(R.integer.large_size);
//draw button
drawBtn = (ImageButton)findViewById(R.id.draw_btn);
drawBtn.setOnClickListener(this);
//set initial size
drawView.setBrushSize(mediumBrush);
//erase button
eraseBtn = (ImageButton)findViewById(R.id.erase_btn);
eraseBtn.setOnClickListener(this);
//new button
newBtn = (ImageButton)findViewById(R.id.new_btn);
newBtn.setOnClickListener(this);
//save button
saveBtn = (ImageButton)findViewById(R.id.save_btn);
saveBtn.setOnClickListener(this);
// Getting reference to Button "Pick an Image"
mBtnPick = (Button) findViewById(R.id.button);
// Setting OnClickListener for the button
mBtnPick.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent();
i.setType("image/*");
i.setAction(Intent.ACTION_GET_CONTENT);
Intent customChooserIntent = Intent.createChooser(i, "Pick an image");
startActivityForResult(customChooserIntent, 10);
}
});
if(savedInstanceState!=null){
mWidth = savedInstanceState.getInt("width");
mHeight = savedInstanceState.getInt("height");
Bitmap bitmap = savedInstanceState.getParcelable("bitmap");
if(bitmap!=null){
drawView.canvasBitmap=bitmap;
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
//user clicked paint
public void paintClicked(View view){
//use chosen color
//set erase false
drawView.setErase(false);
drawView.setBrushSize(drawView.getLastBrushSize());
if(view!=currPaint){
ImageButton imgView = (ImageButton)view;
String color = view.getTag().toString();
drawView.setColor(color);
//update ui
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){
//draw button clicked
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Brush size:");
brushDialog.setContentView(R.layout.brush_chooser);
//listen for clicks on size buttons
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();
}
});
//show and wait for user interaction
brushDialog.show();
}
else if(view.getId()==R.id.erase_btn){
//switch to erase - choose size
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Eraser size:");
brushDialog.setContentView(R.layout.brush_chooser);
//size buttons
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){
//new button
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){
//save drawing
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){
//save drawing
drawView.setDrawingCacheEnabled(true);
//attempt to save
String imgSaved = MediaStore.Images.Media.insertImage(
getContentResolver(), drawView.getDrawingCache(),
UUID.randomUUID().toString()+".png", "drawing");
//feedback
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();
}
}
// Courtesy : developer.android.com/training/displaying-bitmaps/load-bitmap.html
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
private Bitmap getBitmapFromUri(Uri data){
Bitmap bitmap = null;
// Starting fetch image from file
InputStream is=null;
try {
is = getContentResolver().openInputStream(data);
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// BitmapFactory.decodeFile(path, options);
BitmapFactory.decodeStream(is, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, mWidth, mHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
is = getContentResolver().openInputStream(data);
bitmap = BitmapFactory.decodeStream(is,null,options);
if(bitmap==null){
Toast.makeText(getBaseContext(), "Image is not Loaded",Toast.LENGTH_SHORT).show();
return null;
}
is.close();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch(NullPointerException e){
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == 10 && resultCode == RESULT_OK && null != intent) {
Uri data = intent.getData();
Bitmap bitmap = getBitmapFromUri(data);
if(bitmap!=null){
drawView.canvasBitmap=bitmap;
}
}
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
mWidth = drawView.getWidth();
mHeight = drawView.getHeight();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("width", mWidth);
outState.putInt("height", mHeight);
if(drawView.canvasBitmap!=null){
outState.putParcelable("bitmap", drawView.canvasBitmap);
}
super.onSaveInstanceState(outState);
}
}
What you are doing is getting canvas of image via drawCanvas object and drawing it on canvas and then drawing path on it.
Try another way, get canvas of image via drawCanvas object and draw path on it and then draw resultant image on canvas. See following code
// draw path on canvasBitmap
drawCanvas.drawPath(drawPath, drawPaint);
//Now draw canvasBitmap on canvas
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
//canvas.drawPath(drawPath, drawPaint); // No need for this line
What actually happening is that you draw path on canvas on ACTION_UP and reset path object, see following code of yours
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
According to Android what reset() do is as follows:
Clear any lines and curves from the path, making it empty.
After above code you call invalidate(); which clears canvas and redraw it with empty path object because you already have called drawPath.reset(). This is the main reason why lines are disappearing.
Finally I solved the problem by adding the following method to the DrawingView class
public void setPicture (Bitmap bitmap) {
setBackgroundDrawable(new BitmapDrawable(bitmap));
}
then I replaced every line contain drawView.canvasBitmap=bitmap; by drawView.setPicture(bitmap);
and every thing works fine :)
Related
There are few other questions,similar to mine, that I have followed and implemented their answers in every possible manner but that doesnt seem to work on my code. I'm close to the solution but seem to be missing on something. Kindly help and I request not to mark the question as duplicate.
here's the mainActivity:
public class MainActivity extends Activity implements View.OnClickListener {
// private ArrayList<Path> paths = new ArrayList<Path>();
// private ArrayList<Path> undonePaths = new ArrayList<Path>();
private Button btnUndo;
public DrawingView drawView;
//buttons
private ImageButton currPaint, drawBtn, eraseBtn, newBtn, saveBtn, opacityBtn;
//sizes
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);
//get the palette and first color button
LinearLayout paintLayout = (LinearLayout) findViewById(R.id.paint_colors);
currPaint = (ImageButton) paintLayout.getChildAt(0);
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
//sizes from dimensions
smallBrush = 10;
mediumBrush = 20;
largeBrush = 30;
//draw button
drawBtn = (ImageButton) findViewById(R.id.draw_btn);
drawBtn.setOnClickListener(this);
//set initial size
drawView.setBrushSize(mediumBrush);
//erase button
eraseBtn = (ImageButton) findViewById(R.id.erase_btn);
eraseBtn.setOnClickListener(this);
//new button
newBtn = (ImageButton) findViewById(R.id.new_btn);
newBtn.setOnClickListener(this);
//save button
saveBtn = (ImageButton) findViewById(R.id.save_btn);
saveBtn.setOnClickListener(this);
//opacity
opacityBtn = (ImageButton) findViewById(R.id.opacity_btn);
opacityBtn.setOnClickListener(this);
btnUndo = (Button) findViewById(R.id.btnUndo);
btnUndo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
drawView.undo();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
//user clicked paint
public void paintClicked(View view) {
//use chosen color
//set erase false
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);
//update ui
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) {
//draw button clicked
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Brush size:");
brushDialog.setContentView(R.layout.brush_chooser);
//listen for clicks on size buttons
ImageButton smallBtn = (ImageButton) brushDialog.findViewById(R.id.small_brush);
smallBtn.setOnClickListener(new View.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 View.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 View.OnClickListener() {
#Override
public void onClick(View v) {
drawView.setErase(false);
drawView.setBrushSize(largeBrush);
drawView.setLastBrushSize(largeBrush);
brushDialog.dismiss();
}
});
//show and wait for user interaction
brushDialog.show();
}
else if (view.getId() == R.id.erase_btn) {
//switch to erase - choose size
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Eraser size:");
brushDialog.setContentView(R.layout.brush_chooser);
//size buttons
ImageButton smallBtn = (ImageButton) brushDialog.findViewById(R.id.small_brush);
smallBtn.setOnClickListener(new View.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 View.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 View.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) {
//new button
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) {
//save drawing
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) {
//save drawing
drawView.setDrawingCacheEnabled(true);
//attempt to save
String imgSaved = MediaStore.Images.Media.insertImage(
getContentResolver(), drawView.getDrawingCache(),
UUID.randomUUID().toString() + ".png", "drawing");
//feedback
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.btnUndo) {
//undo drawing
{
//drawView.setErase(true);
drawView.undo();
/* if (paths.size() > 0) {
// drawView.setErase(true);
undonePaths.add(paths.remove(paths.size() - 1));
view.invalidate();
} else {
Toast.makeText(getBaseContext(), "undo isnt working", Toast.LENGTH_SHORT).show();
}*/
else if (view.getId() == R.id.opacity_btn) {
//launch opacity chooser
final Dialog seekDialog = new Dialog(this);
seekDialog.setTitle("Opacity level:");
seekDialog.setContentView(R.layout.opacity_chooser);
//get ui elements
final TextView seekTxt = (TextView) seekDialog.findViewById(R.id.opq_txt);
final SeekBar seekOpq = (SeekBar) seekDialog.findViewById(R.id.opacity_seek);
//set max
seekOpq.setMax(100);
//show current level
int currLevel = drawView.getPaintAlpha();
seekTxt.setText(currLevel + "%");
seekOpq.setProgress(currLevel);
//update as user interacts
seekOpq.setOnSeekBarChangeListener(new SeekBar.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) {
}
});
//listen for clicks on ok
Button opqBtn = (Button) seekDialog.findViewById(R.id.opq_ok);
opqBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
drawView.setPaintAlpha(seekOpq.getProgress());
seekDialog.dismiss();
}
});
//show dialog
seekDialog.show();
}
}
}
DrawingView.java:
(Undo function is at the bottom of this class)
public class DrawingView extends View{
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000, paintAlpha = 255;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
//brush sizes
private float brushSize, lastBrushSize;
//erase flag
private boolean erase = false;
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);
// paths.add(drawPath);
}
#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);
}
//draw the view - will be called after touch event
#Override
protected void onDraw(Canvas canvas) {
for (Path path : paths) {
canvas.drawPath(path, drawPaint);
}
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
//register user touches as drawing action
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
//respond to down, move and up events
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;
}
//redraw
invalidate();
return true;
}
//update color
public void setColor(String newColor) {
invalidate();
//check whether color value or pattern name
if (newColor.startsWith("#")) {
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
drawPaint.setShader(null);
} else {
//pattern
int patternID = getResources().getIdentifier(
newColor, "drawable", "com.example.drawingfun");
//decode
Bitmap patternBMP = BitmapFactory.decodeResource(getResources(), patternID);
//create shader
BitmapShader patternBMPshader = new BitmapShader(patternBMP,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
//color and shader
drawPaint.setColor(0xFFFFFFFF);
drawPaint.setShader(patternBMPshader);
}
}
//set brush size
public void setBrushSize(float newSize) {
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize = pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
//get and set last brush size
public void setLastBrushSize(float lastSize) {
lastBrushSize = lastSize;
}
public float getLastBrushSize() {
return lastBrushSize;
}
//set erase true or false
public void setErase(boolean isErase) {
erase = isErase;
if (erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
else drawPaint.setXfermode(null);
}
//start new drawing
public void startNew() {
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
//return current alpha
public int getPaintAlpha() {
return Math.round((float) paintAlpha / 255 * 100);
}
//set alpha
public void setPaintAlpha(int newAlpha) {
paintAlpha = Math.round((float) newAlpha / 100 * 255);
drawPaint.setColor(paintColor);
drawPaint.setAlpha(paintAlpha);
}
//define undo func
public void undo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
invalidate();
} else {
Toast.makeText(getContext(), "undo isnt working wth", Toast.LENGTH_SHORT).show();
}
}
}
I had a similar problem with this earlier today, This is a fairly old ticket so I am not sure if you are interested still... however someone else might be.
I think the issue is that you only ever use one instance of path - its kinda odd but the path isn't just point A-B
I think what you need to do is to make new paths prior to putting them into your collection - Selvin said this in his comment.
For example you could do something like this;
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
//respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//Make a new instance of DrawPath
drawPath = new Path();
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;
}
//redraw
invalidate();
return true;
}
when you do path rest I suspect it is clearing all the lines that are drawn - this is because they are all one path (despite the fact several on-touch events have made them).
if this doesnt work let me know what actually is the problem - is the line not appearing etc...
I am done creating different brush effect in for canvas. When i change the brush then previously drawn paint is change to that brush effect. So what i do for that? If any guidance then please provide me.
Below is my DrawingView class.
public class DrawingView extends View
{
private final Paint mPaintSrcIn = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);
private final Paint mPaintDstIn = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);
public Paint mPaintColor = new Paint(Paint.ANTI_ALIAS_FLAG);
public Paint mPaintColor1 = new Paint(Paint.ANTI_ALIAS_FLAG);
// public final Paint mPaintColor2 = new Paint(Paint.ANTI_ALIAS_FLAG);
// public final Paint mPaintColor3 = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mPaintEraser = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Matrix mMatrix = new Matrix();
private final Canvas mLayerCanvas = new Canvas();
private Bitmap mInnerShape;
private Bitmap mOuterShape;
private Bitmap mLayerBitmap;
private Color mInnerColor,mOuterColor;
PlayActivity playActivity = new PlayActivity();
private int mFlag;
private int paintAlpha = 255;
private int paintColor = 0xFFFF0000;
private ArrayList<DrawOp> mDrawOps = new ArrayList<DrawOp>();
private ArrayList<DrawOp> mDrawOps1 = new ArrayList<DrawOp>();
private DrawOp mCurrentOp = new DrawOp();
private DrawOp mPreviousOp = new DrawOp();
private ArrayList<DrawOp> mUndoneOps = new ArrayList<DrawOp>();
public DrawingView(Context context)
{
this(context, null, 0);
}
public DrawingView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public DrawingView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
mPaintSrcIn.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
mPaintDstIn.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaintColor.setStyle(Paint.Style.STROKE);
mPaintColor.setStrokeJoin(Paint.Join.ROUND);
mPaintColor.setStrokeCap(Paint.Cap.ROUND);
mPaintEraser.set(mPaintColor);
mPaintEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mPaintEraser.setMaskFilter(new BlurMaskFilter(getResources()
.getDisplayMetrics().density * 4, BlurMaskFilter.Blur.NORMAL));
}
public void setShape(int inner, int outer)
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ALPHA_8;
setShape(BitmapFactory.decodeResource(getResources(), inner, options),
BitmapFactory.decodeResource(getResources(), outer, options));
}
public void setShape(Bitmap inner, Bitmap outer)
{
mInnerShape = inner;
mOuterShape = outer;
requestLayout();
invalidate();
}
public void setDrawingColor(int color)
{
mCurrentOp.reset();
mCurrentOp.type = DrawOp.Type.PAINT;
mCurrentOp.color = color;
mPreviousOp.reset();
mPreviousOp.type = DrawOp.Type.PAINT;
mPreviousOp.color = color;
}
public void setDrawingStroke(int stroke)
{
mCurrentOp.reset();
mCurrentOp.type = DrawOp.Type.PAINT;
mCurrentOp.stroke = stroke;
}
public void enableEraser()
{
mCurrentOp.reset();
mCurrentOp.type = DrawOp.Type.ERASE;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
mLayerBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mLayerCanvas.setBitmap(mLayerBitmap);
if(mOuterShape != null){
int dx = (w - mOuterShape.getWidth()) / 2;
int dy = (h - mOuterShape.getHeight()) / 2;
mMatrix.setTranslate(dx, dy);
}
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if(isInEditMode()){
return;
}
// NOTE: Without extra bitmap or layer.. but HW Acceleration does not support setMaskFilter which means
// eraser has strong edges whilst drawing.
// #see http://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported
System.out.println("Flag before if "+mFlag);
if(mFlag==0){
System.out.println("Flag = 0 "+mFlag);
// Clear software canvas
// mPaintColor1 = mPaintColor;
mPaintColor.setStyle(Paint.Style.STROKE);
mPaintColor.setStrokeJoin(Paint.Join.ROUND);
mPaintColor.setStrokeCap(Paint.Cap.ROUND);
mPaintColor.setMaskFilter(null);
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
// Draw picture from ops
for (DrawOp op : mDrawOps) {
drawOp(mLayerCanvas, op);
}
drawOp(mLayerCanvas, mCurrentOp);
System.out.println("Drawing Flag : " + mFlag);
// Mask the drawing to the inner surface area of the shape
mLayerCanvas.drawBitmap(mInnerShape, mMatrix, mPaintDstIn);
// Draw orignal shape to view
canvas.drawBitmap(mOuterShape, mMatrix, null);
// Draw masked image to view
canvas.drawBitmap(mLayerBitmap, 0, 0, null);
}else if(mFlag==1){
mPaintColor.setStyle(Paint.Style.STROKE);
mPaintColor.setStrokeJoin(Paint.Join.ROUND);
mPaintColor.setStrokeCap(Paint.Cap.ROUND);
mPaintColor.setMaskFilter(null);
// Clear software canvas
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
// Draw picture from ops
for(DrawOp op : mDrawOps){
drawOp(mLayerCanvas, op);
}
drawOp(mLayerCanvas, mCurrentOp);
// Mask the drawing to the inner surface area of the shape
mLayerCanvas.drawBitmap(mInnerShape, mMatrix, mPaintDstIn);
// Draw orignal shape to view
canvas.drawBitmap(mOuterShape, mMatrix, null);
// Draw masked image to view
canvas.drawBitmap(mLayerBitmap, 0, 0, null);
canvas.save();
}
else if(mFlag==2){
System.out.println("Flag = 2 "+mFlag);
// mPaintColor1 = mPaintColor;
/* Blur Effect for creating more effect then change following properties
BlurMaskFilter.Blur.INNER,BlurMaskFilter.Blur.NORMAL,BlurMaskFilter.Blur.OUTER
BlurMaskFilter.Blur.SOLID*/
// Code Here
BlurMaskFilter mBlur = new BlurMaskFilter(15, BlurMaskFilter.Blur.NORMAL);
mPaintColor.setMaskFilter(mBlur);
// Clear software canvas
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
// Draw picture from ops
for (DrawOp op : mDrawOps) {
drawOp(mLayerCanvas, op);
}
drawOp(mLayerCanvas, mCurrentOp);
// Mask the drawing to the inner surface area of the shape
mLayerCanvas.drawBitmap(mInnerShape, mMatrix, mPaintDstIn); /*mPaintDstIn*/
// Draw orignal shape to view
canvas.drawBitmap(mOuterShape, mMatrix, null);
// Draw masked image to view
canvas.drawBitmap(mLayerBitmap, 0, 0, null);
canvas.save();
}
else if(mFlag==3){
mPaintColor.setStyle(Paint.Style.STROKE);
mPaintColor.setStrokeJoin(Paint.Join.ROUND);
mPaintColor.setStrokeCap(Paint.Cap.ROUND);
mPaintColor.setMaskFilter(null);
mPaintColor.setMaskFilter(new EmbossMaskFilter(new float[] { 1, 1, 1 },0.4f, 10, 8.2f));
// Clear software canvas
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
// Draw picture from ops
for (DrawOp op : mDrawOps) {
drawOp(mLayerCanvas, op);
}
drawOp(mLayerCanvas, mCurrentOp);
// Mask the drawing to the inner surface area of the shape
mLayerCanvas.drawBitmap(mInnerShape, mMatrix, mPaintDstIn);
// Draw orignal shape to view
canvas.drawBitmap(mOuterShape, mMatrix, null);
// Draw masked image to view
canvas.drawBitmap(mLayerBitmap, 0, 0, null);
canvas.save();
}
}
private void drawOp(Canvas canvas, DrawOp op)
{
if(op.path.isEmpty()){
return;
}
final Paint paint;
if(op.type == DrawOp.Type.PAINT){
paint = mPaintColor;
paint.setColor(op.color);
paint.setStrokeWidth(op.stroke);
}else{
paint = mPaintEraser;
paint.setStrokeWidth(op.stroke);
}
mLayerCanvas.drawPath(op.path, paint);
}
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouchEvent(MotionEvent event)
{
final float x = event.getX();
final float y = event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
mUndoneOps.clear();
mCurrentOp.path.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
for(int i = 0; i < event.getHistorySize(); i++){
mCurrentOp.path.lineTo(event.getHistoricalX(i), event.getHistoricalY(i));
}
mCurrentOp.path.lineTo(x, y);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mCurrentOp.path.lineTo(x, y);
mDrawOps.add(new DrawOp(mCurrentOp));
mCurrentOp.path.reset();
break;
}
invalidate();
return true;
}
private static class DrawOp
{
public final Path path = new Path();
public Type type;
public int color;
public int stroke;
public DrawOp()
{
//
}
public void reset()
{
this.path.reset();
}
public DrawOp(DrawOp op)
{
this.path.set(op.path);
this.type = op.type;
this.color = op.color;
this.stroke = op.stroke;
}
public static enum Type
{
PAINT, ERASE;
}
}
public void setFlag(int flag) {
System.out.println("Before Set mFlag " + mFlag);
this.mFlag = flag;
System.out.println("After Set mFlag " + mFlag);
}
}
This is my Activity Class for changing brush effect using button click
public class PlayActivity extends Activity{
private DrawingView mDrawingView;
private ViewGroup mBrushPanel;
private ViewGroup mBrushColors;
private SeekBar mBrushStroke;
private ViewGroup brush_panel_pencil;
private ViewGroup brush_colors_pencil;
private SeekBar brush_stroke_pencil;
String imagName ="";
private static String APP_ID = "788092211287311";
// Instance of Facebook Class
private Facebook facebook;
private AsyncFacebookRunner mAsyncRunner;
String FILENAME = "AndroidSSO_data";
private SharedPreferences mPrefs;
public boolean flag = false;
String name="";
File file = null;
FileOutputStream fOut = null;
// see:
// http://stackoverflow.com/questions/25758294/how-to-fill-different-color-on-same-area-of-imageview-color-over-another-color/
static int[] COLORS = { Color.rgb(255, 51, 255), // DARK PINK
Color.rgb(255, 230, 102), // LIGHT YELLOW
Color.rgb(148, 66, 50), // DARK MAROON
Color.rgb(186, 123, 68), // LIGHT MAROON
Color.rgb(252, 20, 20), // RED
Color.rgb(102, 255, 255), // LIGHT BLUE
Color.rgb(70, 78, 202), // DARK BLUE
Color.rgb(190, 255, 91), // LIGHT GREEN
Color.rgb(15, 230, 0), // DARK GREEN
Color.rgb(123, 0, 230), // JAMBLI
Color.rgb(255, 187, 50), // ORANGE
Color.rgb(7, 5, 0), // BLACK
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setBackgroundDrawable(
Utils.createCheckerBoard(getResources(), 16));
setContentView(R.layout.activity_play);
mDrawingView = (DrawingView) findViewById(R.id.drawing_view);
// mDrawingView.setShape(R.drawable.img_a_inner, R.drawable.img_a);
mDrawingView.setShape(R.drawable.inner, R.drawable.outer);
mDrawingView.setDrawingColor(getResources().getColor(R.color.ab_color));
mDrawingView.setFlag(0);
mBrushPanel = (ViewGroup) findViewById(R.id.brush_panel);
mBrushColors = (ViewGroup) findViewById(R.id.brush_colors);
mBrushStroke = (SeekBar) findViewById(R.id.brush_stroke);
mBrushStroke
.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
#Override
public void onProgressChanged(SeekBar seekBar,
int progress, boolean fromUser) {
mDrawingView.setDrawingStroke(progress);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
});
mBrushStroke.setProgress(30);
mBrushPanel.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
mBrushPanel.getViewTreeObserver()
.removeOnPreDrawListener(this);
mBrushPanel
.setTranslationY(isLandscape() ? -mBrushPanel
.getHeight() : mBrushPanel.getHeight());
return false;
}
});
createBrushPanelContent();
}
#SuppressWarnings("null")
private void createBrushPanelContent() {
TableRow tableRow = null;
final int rowLimit = isLandscape() ? 16 : 8;
for (int i = 0; i < COLORS.length; i++) {
if ((i % rowLimit) == 0) {
tableRow = new TableRow(this);
mBrushColors.addView(tableRow, new TableLayout.LayoutParams(
WRAP_CONTENT, WRAP_CONTENT));
}
tableRow.addView(createToolButton(tableRow,
R.drawable.ic_paint_splot, i));
}
/*tableRow.addView(createToolButton1(tableRow, R.drawable.ic_paint_splot,
1));*/
}
private void showBrushPanel() {
mBrushPanel.animate().translationY(0).start();
}
private void hideBrushPanel() {
mBrushPanel
.animate()
.translationY(
isLandscape() ? -mBrushPanel.getHeight() : mBrushPanel
.getHeight()).start();
}
private boolean isLandscape() {
return getResources().getBoolean(R.bool.is_landscape);
}
private ImageButton createToolButton(ViewGroup parent, int drawableResId,
int index) {
ImageButton button = (ImageButton) getLayoutInflater().inflate(
R.layout.button_paint_spot, parent, false);
button.setImageResource(drawableResId);
button.setOnClickListener(mButtonClick);
if (index != -1) {
button.setTag(Integer.valueOf(index));
button.setColorFilter(COLORS[index]);
}
return button;
}
/* private Button createToolButton1(ViewGroup parent, int drawableResId,
int index) {
Button buttonShare = (Button) getLayoutInflater().inflate(
R.layout.button, parent, false);
buttonShare.setOnClickListener(mButtonShare);
return buttonShare;
}
};*/
private View.OnClickListener mButtonClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
// code for set the shadow color
// mDrawingView.mPaintColor.setShadowLayer(10, 10, 5, Color.RED);
mDrawingView.setDrawingColor(COLORS[((Integer) v.getTag())
.intValue()]);
hideBrushPanel();
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_play, menu);
return super.onCreateOptionsMenu(menu) | true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_emboss:
mDrawingView.setFlag(3);
System.out.println("mClick Emboss");
mDrawingView.setDrawingStroke(30);
if (mBrushPanel.getTranslationY() == 0) {
hideBrushPanel();
} else {
showBrushPanel();
}
break;
case R.id.action_watermark:
mDrawingView.setFlag(2);
mDrawingView.setDrawingStroke(30);
BlurMaskFilter mBlur = new BlurMaskFilter(15, BlurMaskFilter.Blur.NORMAL);
mDrawingView.mPaintColor.setMaskFilter(mBlur);
if (mBrushPanel.getTranslationY() == 0) {
hideBrushPanel();
} else {
showBrushPanel();
}
break;
case R.id.action_pencil:
mDrawingView.setFlag(1);
mDrawingView.setDrawingStroke(4);
if (mBrushPanel.getTranslationY() == 0) {
hideBrushPanel();
} else {
showBrushPanel();
}
break;
case R.id.action_brush:
mDrawingView.setFlag(0);
mDrawingView.setDrawingStroke(30);
if (mBrushPanel.getTranslationY() == 0) {
hideBrushPanel();
} else {
showBrushPanel();
}
break;
case R.id.action_eraser:
mDrawingView.enableEraser();
break;
case R.id.action_undo:
mDrawingView.undoOperation();
break;
case R.id.action_redo:
mDrawingView.redoOperation();
break;
case R.id.action_save: {
mDrawingView
.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
mDrawingView.setDrawingCacheEnabled(true);
mDrawingView.buildDrawingCache();
Bitmap viewCache = mDrawingView.getDrawingCache();
Bitmap bitmap = viewCache.copy(viewCache.getConfig(), false);
mDrawingView.setDrawingCacheEnabled(false);
new SaveTask().execute(bitmap);
View view = findViewById(R.id.relative);
view.setDrawingCacheEnabled(true);
// Bitmap bitmap2 = view.getDrawingCache();
final Bitmap bitmap2 = bitmap.copy(Bitmap.Config.ARGB_8888,
true);
final BitmapDrawable bitmapDrawable = new BitmapDrawable(
bitmap2);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.horizon,
(ViewGroup) findViewById(R.id.main_relative_output));
RelativeLayout rl = (RelativeLayout) layout
.findViewById(R.id.main_relative_output);
/*AlertDialog builder = new AlertDialog.Builder(
PlayActivity.this).setView(layout).show();*/
//Convert to byte array
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap2.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
Intent i = new Intent(PlayActivity.this, SharingScreen.class);
i.putExtra("image",byteArray);
i.putExtra("name", name);
startActivity(i);
// rl.setBackgroundDrawable(bitmapDrawable);
}
break;
case R.id.action_cancel:
mDrawingView.clearDrawing();
// file.delete();
/*if(viewCache.isRecycled()){
viewCache.recycle();
bitmap.recycle();
}*/
break;
/*case R.id.action_share:
mDrawingView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
mDrawingView.setDrawingCacheEnabled(true);
mDrawingView.buildDrawingCache();
Bitmap viewCache = mDrawingView.getDrawingCache();
Bitmap bitmap = viewCache.copy(viewCache.getConfig(), false);
new SaveAndShare().execute(bitmap);
break;*/
default:
return super.onOptionsItemSelected(item);
}
return true;
}
}
I am trying to do Face swap kind of application using facedetection. Till now i get the faces detected in bitmap and draw oval on the faces detected. But now i need to use the faces inside the oval so that i can swap two faces. Is it possible. I need some suggestions regarding this.
My activity class as follows
public class FaceDetectionActivity extends Activity
{
public MyView faceview;
public ImageView gallery;
private Uri imageURI;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
setContentView(R.layout.main);
faceview = (MyView)findViewById(R.id.faceview);
gallery=(ImageView)findViewById(R.id.gallery);
gallery.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, 0 );
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if(requestCode==0){
imageURI = data.getData();
try {
Bitmap b = android.provider.MediaStore.Images.Media.getBitmap(getContentResolver(), imageURI);
faceview.myBitmap=b;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
faceview.invalidate();
}
faceview.invalidate();
} else {
System.exit(0);
Log.e("result", "BAD");
}
}
}
and my view class
public class MyView extends ImageViewTouchBase {
public RectF rectF;
public Bitmap myBitmap;
private int width, height;
private FaceDetector.Face[] detectedFaces;
private int NUMBER_OF_FACES=10;
private FaceDetector faceDetector;
private int NUMBER_OF_FACE_DETECTED;
private float eyeDistance;
Matrix mImageMatrix;
public MyView(Context context, AttributeSet attrs)
{
super(context, attrs);
BitmapFactory.Options bitmapFatoryOptions=new BitmapFactory.Options();
bitmapFatoryOptions.inPreferredConfig=Bitmap.Config.RGB_565;
myBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.familyportrait,bitmapFatoryOptions);
width=myBitmap.getWidth();
height=myBitmap.getHeight();
detectedFaces=new FaceDetector.Face[NUMBER_OF_FACES];
faceDetector=new FaceDetector(width,height,NUMBER_OF_FACES);
NUMBER_OF_FACE_DETECTED=faceDetector.findFaces(myBitmap, detectedFaces);
}
#Override
protected void onDraw(Canvas canvas)
{
if(myBitmap!=null)
{
canvas.drawBitmap(myBitmap, 0,0, null);
}
Paint myPaint = new Paint();
myPaint.setColor(Color.GREEN);
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(3);
for(int count=0;count<NUMBER_OF_FACE_DETECTED;count++)
{
Face face=detectedFaces[count];
PointF midPoint=new PointF();
face.getMidPoint(midPoint);
eyeDistance=face.eyesDistance();
float left = midPoint.x - (float)(1.4 * eyeDistance);
float right = midPoint.x + (float)(1.4 * eyeDistance);
float top = midPoint.y - (float)(1.8 * eyeDistance);
float bottom = midPoint.y + (float)(1.8 * eyeDistance);
Rect imageRect = new Rect(0, 0, width, height);
rectF = new RectF();
rectF.set(left,top,right,bottom);
canvas.drawOval(rectF, myPaint);
}
}
}
Now i want the content inside the oval to be selected. Please suggest me some ideas.
I just figured it out. I am creating another bitmap with the variables Left,Right,Top and Bottom from the above code. and then i get a square bitmap of the faces.I am extracting circular bitmap from the square bitmap faces. Thats it.
Try this code:
public class MainActivity extends ProgressA {
public static final String FACE_1 = "face_1";
public static final String FACE_2 = "face_2";
private ImageView mIvForDetect;
private ImageView mIvForDetect2;
private ImageView mIvForDetect3;
private ImageView mIvForDetect4;
//private Bitmap baseBTM;
private Bitmap face1BTM;
private Bitmap face2BTM;
boolean face1Done = false;
boolean face2Done = false;
private FirebaseVisionFaceDetector detector;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mIvForDetect = findViewById(R.id.iv_main_for_detect);
mIvForDetect2 = findViewById(R.id.iv_main_for_detect2);
mIvForDetect3 = findViewById(R.id.iv_main_for_detect3);
mIvForDetect4 = findViewById(R.id.iv_main_for_detect4);
//baseBTM = BitmapFactory.decodeResource(getResources(), R.drawable.paj);
mIvForDetect.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.jolie));
mIvForDetect2.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pitt));
detector = FirebaseVision.getInstance().getVisionFaceDetector(buildCloudVisionOptions());
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showProgressDialog();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
detectFace(mIvForDetect, FACE_1, null);
detectFace(mIvForDetect2,FACE_2, null);
}
});
thread.start();
}
});
}
private void checkFaces() {
if (face1Done && face2Done){
swapFaces();
}
}
private void swapFaces() {
detectFace(mIvForDetect, FACE_1, face2BTM);
detectFace(mIvForDetect2, FACE_2, face1BTM);
}
private void detectFace(final ImageView view, final String face, final Bitmap fakeFace) {
final Bitmap baseBTM = ((BitmapDrawable) view.getDrawable()).getBitmap();
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(baseBTM);
detector.detectInImage(image)
.addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionFace>>() {
#Override
public void onSuccess(List<FirebaseVisionFace> faces) {
if (fakeFace != null){
setFakeFace(view, faces.get(0), baseBTM, fakeFace);
hideProgressDialog();
}else {
switch (face){
case FACE_1:
face1BTM = createTrimmedBitmap(cutFaces(faces.get(0), baseBTM));
mIvForDetect3.setImageBitmap(face1BTM);
face1Done = true;
checkFaces();
break;
case FACE_2:
face2BTM = createTrimmedBitmap(cutFaces(faces.get(0), baseBTM));
mIvForDetect4.setImageBitmap(face2BTM);
face2Done = true;
checkFaces();
break;
}
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
hideProgressDialog();
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
public FirebaseVisionFaceDetectorOptions buildCloudVisionOptions() {
return new FirebaseVisionFaceDetectorOptions.Builder()
.setPerformanceMode(FirebaseVisionFaceDetectorOptions.ACCURATE)
.setLandmarkMode(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS)
.setClassificationMode(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS)
.setPerformanceMode(FirebaseVisionFaceDetectorOptions.FAST)
.build();
}
public static Bitmap createTrimmedBitmap(Bitmap bmp) {
int imgHeight = bmp.getHeight();
int imgWidth = bmp.getWidth();
int smallX = 0, largeX = imgWidth, smallY = 0, largeY = imgHeight;
int left = imgWidth, right = imgWidth, top = imgHeight, bottom = imgHeight;
for (int i = 0; i < imgWidth; i++) {
for (int j = 0; j < imgHeight; j++) {
if (bmp.getPixel(i, j) != Color.TRANSPARENT) {
if ((i - smallX) < left) {
left = (i - smallX);
}
if ((largeX - i) < right) {
right = (largeX - i);
}
if ((j - smallY) < top) {
top = (j - smallY);
}
if ((largeY - j) < bottom) {
bottom = (largeY - j);
}
}
}
}
bmp = Bitmap.createBitmap(bmp, left, top, imgWidth - left - right, imgHeight - top - bottom);
return bmp;
}
public Bitmap cutFaces(FirebaseVisionFace face, Bitmap baseBTM) {
Bitmap tempBitmap = Bitmap.createBitmap(baseBTM.getWidth(), baseBTM.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
tempCanvas.drawBitmap(baseBTM, 0, 0, null);
int top = face.getBoundingBox().top;
int left = Math.round(face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EAR).getPosition().getX());
int right = Math.round(face.getLandmark(FirebaseVisionFaceLandmark.RIGHT_EAR).getPosition().getX());
int bottom = face.getBoundingBox().bottom;
Bitmap output = Bitmap.createBitmap(tempBitmap.getWidth(), tempBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final Paint paint = new Paint();
canvas.drawOval(left, top, right, bottom, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(tempBitmap, new Matrix(), paint);
return output;
}
public void setFakeFace(ImageView view, FirebaseVisionFace face, Bitmap baseBTM, Bitmap fakeFace) {
Bitmap resultBitmap = Bitmap.createBitmap(baseBTM.getWidth(), baseBTM.getHeight(), baseBTM.getConfig());
Canvas canvas = new Canvas(resultBitmap);
final Paint paintSRC = new Paint();
final Paint paintDST = new Paint();
int top = face.getBoundingBox().top;
int left = Math.round(face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EAR).getPosition().getX());
int right = Math.round(face.getLandmark(FirebaseVisionFaceLandmark.RIGHT_EAR).getPosition().getX());
int bottom = face.getBoundingBox().bottom;
int weight = right - left;
int height = bottom - top;
canvas.drawOval(left, top, right, bottom, paintSRC);
paintSRC.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
paintDST.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
Matrix matrix = new Matrix();
matrix.postScale(face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EAR).getPosition().getX(), face.getBoundingBox().top);
canvas.drawBitmap(baseBTM, 0, 0, null);
canvas.drawBitmap(Bitmap.createScaledBitmap(fakeFace, weight, height, false), left, top, paintDST);
view.setImageBitmap(resultBitmap);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
} }
I am currently developing a coloring app for the kids. Created a canvas of an image for coloring. The image is a PNG and I am trying to color the image so the image does not get covered by the paint or color. I am very close in building the app but the problem is that I am not getting the tip of coloring the image in a way so that the image remains on the front and the color on the back
Here is my code
public class FingerPaint extends Activity {
LinearLayout mainContainer;
LinearLayout buttonContainer;
LinearLayout.LayoutParams ![enter image description here][1]btnParams;
Button btnText, btnSketch, btnColor, btnUndo, btnRedo, btnDone,btnClear;
// MyView drawView;
DrawingPanel drawView;
int lastColor = 0xFFFF0000;
public static final int SUCCESS = 200;
private final String TAG = getClass().getSimpleName();
private String textToDraw = null;
private boolean isTextModeOn = false;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint, mBitmapPaint;
private ArrayList<PathPoints> paths = new ArrayList<PathPoints>();
private ArrayList<PathPoints> undonePaths = new ArrayList<PathPoints>();
private Bitmap mBitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
generateViews();
}
public static void displayAlert(Context context, String msg) {
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setMessage(context.getString(R.string.app_name));
alert.setMessage(msg);
alert.setPositiveButton(context.getString(R.string.btn_ok),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
});
alert.show();
}
private void generateViews() {
btnDone = new Button(this);
btnDone.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
btnDone.setText(getString(R.string.btn_done));
btnText = new Button(this);
btnClear = new Button(this);
btnSketch = new Button(this);
btnColor = new Button(this);
btnUndo = new Button(this);
btnRedo = new Button(this);
mainContainer = new LinearLayout(this);
mainContainer.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
mainContainer.setOrientation(LinearLayout.VERTICAL);
buttonContainer = new LinearLayout(this);
buttonContainer.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
buttonContainer.setOrientation(LinearLayout.HORIZONTAL);
btnParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT, 1);
btnText.setText("Text");
btnText.setLayoutParams(btnParams);
btnClear.setText("Clear");
btnClear.setLayoutParams(btnParams);
btnSketch.setText("Sketch");
btnSketch.setLayoutParams(btnParams);
btnColor.setText("Color");
btnColor.setLayoutParams(btnParams);
btnUndo.setText("Undo");
btnUndo.setLayoutParams(btnParams);
btnRedo.setText("Redo");
btnRedo.setLayoutParams(btnParams);
buttonContainer.addView(btnText);
buttonContainer.addView(btnClear);
buttonContainer.addView(btnSketch);
buttonContainer.addView(btnColor);
buttonContainer.addView(btnUndo);
buttonContainer.addView(btnRedo);
drawView = new DrawingPanel(this, lastColor);
drawView.setDrawingCacheEnabled(true);
drawView.measure(
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
drawView.layout(0, 0, drawView.getMeasuredWidth(),
drawView.getMeasuredHeight());
drawView.buildDrawingCache(true);
drawView.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 1));
mainContainer.addView(btnDone);
mainContainer.addView(drawView);
mainContainer.addView(buttonContainer);
setContentView(mainContainer);
btnSketch.setSelected(true);
btnText.setOnClickListener(new OnClickListener() {
//text
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
resetButtons();
btnText.setSelected(true);
AlertDialog.Builder alert = new AlertDialog.Builder(
FingerPaint.this);
alert.setMessage(getString(R.string.msg_enter_text_to_draw));
final EditText edText = new EditText(FingerPaint.this);
alert.setView(edText);
alert.setPositiveButton(R.string.btn_ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
if (edText.getText().toString().length() > 0) {
textToDraw = edText.getText().toString();
isTextModeOn = true;
displayAlert(FingerPaint.this,
getString(R.string.msg_tap_image));
} else {
displayAlert(
FingerPaint.this,
getString(R.string.msg_enter_text_to_draw));
}
}
});
alert.setNegativeButton(R.string.btn_cancel,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
isTextModeOn = false;
}
});
alert.show();
}
});
/// clear
btnClear.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
//mBitmap.eraseColor(Color.TRANSPARENT);
mPath.reset();
paths.removeAll(paths);
undonePaths.removeAll(undonePaths);
drawView.invalidate();
}
});
////sketch
btnSketch.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
resetButtons();
btnSketch.setSelected(true);
isTextModeOn = false;
}
});
//color
/* btnColor.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
AmbilWarnaDialog dialog = new AmbilWarnaDialog(
FingerPaint.this, lastColor,
new OnAmbilWarnaListener() {
#Override
public void onOk(AmbilWarnaDialog dialog, int color) {
// color is the color selected by the user.
colorChanged(color);
}
#Override
public void onCancel(AmbilWarnaDialog dialog) {
// cancel was selected by the user
}
});
dialog.show();
}
});*/
//undo
btnUndo.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
drawView.onClickUndo();
}
});//redo
btnRedo.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
drawView.onClickRedo();
}
});
//done
btnDone.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
/*Log.v(TAG, "Here");
Bitmap editedImage = Bitmap.createBitmap(drawView
.getDrawingCache());
editedImage = Bitmap.createScaledBitmap(editedImage, 200, 300,
true);
if (editedImage != null) {
Intent intent = new Intent();
//intent.putExtra(ChooseActivity.BITMAP, editedImage);
// AddReportItemActivity.mPhoto =
// drawView.getDrawingCache();
setResult(SUCCESS, intent);
finish();
}
}*/
AlertDialog.Builder editalert = new AlertDialog.Builder(FingerPaint.this);
editalert.setTitle("Please Enter the name with which you want to Save");
final EditText input = new EditText(FingerPaint.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 = drawView.getDrawingCache();
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
File file = new File("mnt/sdcard/"+name+".png");
try
{
if(!file.exists())
{
file.createNewFile();
}
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(CompressFormat.PNG, 10, ostream);
ostream.close();
drawView.invalidate();
}
catch (Exception e)
{
e.printStackTrace();
}finally
{
drawView.setDrawingCacheEnabled(false);
}
}
});
editalert.show();
}
});
}
public void resetButtons() {
btnText.setSelected(false);
btnClear.setSelected(false);
btnSketch.setSelected(false);
btnColor.setSelected(false);
btnUndo.setSelected(false);
btnRedo.setSelected(false);
}
public class DrawingPanel extends View implements OnTouchListener {
private int color;
public int x, y;
public DrawingPanel(Context context, int color) {
super(context);
this.color = color;
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(color);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.MITER);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(15);
mPaint.setTextSize(30);
//mPaint.setStyle(Style s);
mPath = new Path();
paths.add(new PathPoints(mPath, color, false));
mCanvas = new Canvas();
}
public void colorChanged(int color) {
this.color = color;
mPaint.setColor(color);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// mBitmap = AddReportItemActivity.mPhoto;
//mBitmap = getIntent().getExtras().getParcelable(ChooseActivity.BITMAP);
mBitmap = BitmapFactory.decodeResource(
getApplicationContext().getResources(),
R.drawable.images);
// targetImage.setImageBitmap(srcBitmapLocal);
float xscale = (float) w / (float) mBitmap.getWidth();
float yscale = (float) h / (float) mBitmap.getHeight();
if (xscale > yscale) // make sure both dimensions fit (use the
// smaller scale)
xscale = yscale;
float newx = (float) w * xscale;
float newy = (float) h * xscale; // use the same scale for both
// dimensions
// if you want it centered on the display (black borders)
mBitmap = Bitmap.createScaledBitmap(mBitmap, this.getWidth(),
this.getHeight(), true);
// mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
for (PathPoints p : paths) {
mPaint.setColor(p.getColor());
Log.v("", "Color code : " + p.getColor());
if (p.isTextToDraw()) {
canvas.drawText(p.textToDraw, p.x, p.y, mPaint);
} else {
canvas.drawPath(p.getPath(), mPaint);
}
}
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 0;
Point p=new Point();
private void touch_start(float x, float y) {
p.x=(int)x;
p.y=(int)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;
int xx=Math.round(mX);
int yy=Math.round(mY);
}
}
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 = new Path();
paths.add(new PathPoints(mPath, color, false));
}
private void drawText(int x, int y) {
Log.v(TAG, "Here");
Log.v(TAG, "X " + x + " Y " + y);
this.x = x;
this.y = y;
paths.add(new PathPoints(color, textToDraw, true, x, y));
// mCanvas.drawText(textToDraw, x, y, mPaint);
}
#Override
public boolean onTouch(View arg0, MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!isTextModeOn) {
touch_start(x, y);
invalidate();
}
break;
case MotionEvent.ACTION_MOVE:
if (!isTextModeOn) {
touch_move(x, y);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (isTextModeOn) {
drawText((int) x, (int) y);
invalidate();
} else {
touch_up();
invalidate();
}
break;
}
return true;
}
public void onClickUndo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
invalidate();
} else {
}
// toast the user
}
public void onClickRedo() {
if (undonePaths.size() > 0) {
paths.add(undonePaths.remove(undonePaths.size() - 1));
invalidate();
} else {
}
// toast the user
}
}
public void colorChanged(int color) {
// TODO Auto-generated method stub
lastColor = color;
drawView.colorChanged(lastColor);
}
class PathPoints {
private Path path;
// private Paint mPaint;
private int color;
private String textToDraw;
private boolean isTextToDraw;
private int x, y;
public PathPoints(Path path, int color, boolean isTextToDraw) {
this.path = path;
this.color = color;
this.isTextToDraw = isTextToDraw;
}
public PathPoints(int color, String textToDraw, boolean isTextToDraw,
int x, int y) {
this.color = color;
this.textToDraw = textToDraw;
this.isTextToDraw = isTextToDraw;
this.x = x;
this.y = y;
}
public Path getPath() {
return path;
}
public void setPath(Path path) {
this.path = path;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public String getTextToDraw() {
return textToDraw;
}
public void setTextToDraw(String textToDraw) {
this.textToDraw = textToDraw;
}
public boolean isTextToDraw() {
return isTextToDraw;
}
public void setTextToDraw(boolean isTextToDraw) {
this.isTextToDraw = isTextToDraw;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
}
in your :
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
}
add these lines before canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.save();
canvas.drawColor(0xff000000);
hope it will help
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Bitmap recycle with largeHeap enabled
hi am doing one app here i am displying images using bitmaps,that images is displaying well,but becz this class i am getting out of memory exception in another class.pls see once my code and how to solve this issue any suhhest me...
public class DesignofatozActivity extends Activity {
BitmapDrawable sounddrawable,erasedrawable,backdrwable,fwddrwable,captiondrwable;
Bitmap soundbitmap,eraseBitmap,backbitmap,fwdbitmap,captionbitmap;
bitmapOrg,bitmapOrg1,bitmapOrg2,bitmapOrg3,bitmapOrg4,bitmapOrg5,bitmapOrg6;
MyView myview;
File f;
ImageView d1,d2,d3,d4,d5,d6;
public boolean action=false;
RelativeLayout relativeLayout,layout,relativeLayout2;
Button c1,c2,c3,c4,c5,c6,c7,c8;
MediaPlayer player;
MediaPlayer mediay2;
ImageView horn;
float screenHeight,screenWidth,screendensity;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setNoTitle();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
screenHeight = displaymetrics.heightPixels;
screenWidth = displaymetrics.widthPixels;
screendensity = displaymetrics.densityDpi;
Log.i("screenHeight",""+screenHeight);
Log.i("screenWidth",""+screenWidth);
Log.i("screendensity",""+screendensity);
setContentView(R.layout.line);
relativeLayout=(RelativeLayout)findViewById(R.id.relative);
relativeLayout.setBackgroundColor(Color.WHITE);
relativeLayout2=(RelativeLayout)findViewById(R.id.relative2);
RelativeLayout.LayoutParams layoutrel2= (RelativeLayout.LayoutParams) relativeLayout2.getLayoutParams();
layoutrel2.height=(int)(25*(screenHeight/600));
int toplay=(int)(90*(screenHeight/600));
layout=new RelativeLayout(this);
RelativeLayout.LayoutParams lp=new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.setMargins(0, toplay, 0,0);
layout.setLayoutParams(lp);
relativeLayout.addView(layout,lp);
int topmyvi=(int)(45*(screenHeight/600));
myview = new MyView(this);
myview.setId(004);
RelativeLayout.LayoutParams lp6 = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
myview.setLayoutParams(lp6);
lp6.setMargins(0, topmyvi, 0,0);
relativeLayout.addView(myview,lp6);
ImageView I2=new ImageView(this);
if(captiondrwable!= null) {
captionbitmap.recycle();
captiondrwable= null;
}
captionbitmap=BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.caption22_1));
captiondrwable = new BitmapDrawable(captionbitmap);
I2.setBackgroundDrawable(captiondrwable);
int left2=(int)(15*(screenWidth/1024));
int widthhh2=(int)(100*(screenWidth/1024));
int hifhtttt2=(int)(50*(screenHeight/600));
RelativeLayout.LayoutParams rlp2=new RelativeLayout.LayoutParams(widthhh2,hifhtttt2);
rlp2.setMargins(left2, topmyvi, 0, 0);
relativeLayout.addView(I2,rlp2);
ImageView b1=new ImageView(this);
if(erasedrawable!= null) {
eraseBitmap.recycle();
erasedrawable= null;
}
eraseBitmap=BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.eraser_501));
erasedrawable = new BitmapDrawable(eraseBitmap);
b1.setBackgroundDrawable(erasedrawable);
int leftb1=(int)(650*(screenWidth/1024));
int topb1=(int)(10*(screenHeight/600));
int widtb1=(int)(100*(screenWidth/1024));
int hightb1=(int)(100*(screenHeight/600));
RelativeLayout.LayoutParams rlp3=new RelativeLayout.LayoutParams(widtb1,hightb1);
rlp3.setMargins(leftb1, topb1, 0, 0);
relativeLayout.addView(b1,rlp3);
b1.setOnClickListener(new OnClickListener() {
// #Override
public void onClick(View v) {
// TODO Auto-generated method stub
try{
mBitmap.eraseColor(android.graphics.Color.TRANSPARENT);
Canvas Canvas=new Canvas(mBitmap);
action=true;
myview.onDraw(Canvas);
}catch(IllegalStateException ie){
ie.printStackTrace();
}
}
});
int lefth1=(int)(830*(screenWidth/1024));
int toph1=(int)(35*(screenHeight/600));
int width1=(int)(60*(screenWidth/1024));
int highth1=(int)(60*(screenHeight/600));
horn=new ImageView(this);
if(sounddrawable!= null) {
soundbitmap.recycle();
sounddrawable= null;
}
soundbitmap=BitmapFactory.decodeStream(getResources().openRawResource( R.drawable.horn));
sounddrawable = new BitmapDrawable(soundbitmap);
horn.setBackgroundDrawable(sounddrawable);
RelativeLayout.LayoutParams hn=new RelativeLayout.LayoutParams(width1,highth1);
hn.setMargins(lefth1,toph1,0,0);
relativeLayout.addView(horn,hn);
horn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
if(mediay2==null)
{
mediay2 = MediaPlayer.create(DesignofatozActivity.this, R.raw.hwprepsheets);
}
mediay2.start();
if(mediay2!=null)
{
}
}
});
ImageView next=(ImageView)findViewById(R.id.imv1a);
if(fwddrwable!= null) {
fwdbitmap.recycle();
fwddrwable= null;
}
fwdbitmap=BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.next_50));
fwddrwable = new BitmapDrawable(fwdbitmap);
next.setBackgroundDrawable(fwddrwable);
RelativeLayout.LayoutParams layoutnxt= (RelativeLayout.LayoutParams) next.getLayoutParams();
layoutnxt.height=(int)(30*(screenHeight/600));
layoutnxt.width=(int)(50*(screenWidth/1024));
next.setOnClickListener(new OnClickListener() {
// #Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Log.i("next","next");
Intent i =new Intent(DesignofatozActivity.this,Dots.class);
startActivity(i);
}
});
ImageView back=(ImageView)findViewById(R.id.back);
if(backdrwable!= null) {
backbitmap.recycle();
backdrwable= null;
}
backbitmap=BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.back1_50));
backdrwable = new BitmapDrawable(backbitmap);
back.setBackgroundDrawable(backdrwable);
RelativeLayout.LayoutParams layoutbak= (RelativeLayout.LayoutParams) back.getLayoutParams();
layoutbak.height=(int)(30*(screenHeight/600));
layoutbak.width=(int)(50*(screenWidth/1024));
back.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent i =new Intent(DesignofatozActivity.this,Slantlines.class);
startActivity(i);
}
});
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
//mPaint.setColor(0xFFFF0000);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
}
private void setNoTitle() {
// TODO Auto-generated method stub
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
private Paint mPaint;
private Bitmap mBitmap;
public void colorChanged(int color) {
mPaint.setColor(color);
}
public class MyView extends View
{
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
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);
if (mBitmap != null) {
mBitmap.recycle();
mBitmap=null;
}
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mCanvas.setBitmap(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
if(action)
{
invalidate();
}
Paint painto = new Paint();
painto.setAntiAlias(true);
painto.setStrokeWidth(3);
painto.setStyle(Paint.Style.FILL);
int leftx1=(int)(15*(screenWidth/1024));
int leftx2=(int)(1010*(screenWidth/1024));
int topy1=(int)(60*(screenHeight/600));
int topy2=(int)(530*(screenHeight/600));
canvas.drawLine(leftx1, topy1, leftx2, topy1, painto);
canvas.drawLine(leftx1, topy1, leftx1, topy2, painto);
canvas.drawLine(15, topy2, leftx2, topy2, painto);
canvas.drawLine(leftx2, topy1, leftx2, topy2, painto);
bitmapOrg = BitmapFactory.decodeResource(getResources(),
R.drawable.circles1_4);
int leftorg=(int)(150*(screenWidth/1024));
int toporg=(int)(110*(screenHeight/600));
canvas.drawBitmap(bitmapOrg, leftorg, toporg, painto);
bitmapOrg.recycle();
bitmapOrg=null;
bitmapOrg1 = BitmapFactory.decodeResource(getResources(),
R.drawable.circles1_5);
int leftorg1=(int)(430*(screenWidth/1024));
int toporg1=(int)(130*(screenHeight/600));
canvas.drawBitmap(bitmapOrg1, leftorg1,toporg1, painto);
bitmapOrg1.recycle();
bitmapOrg1=null;
bitmapOrg2 = BitmapFactory.decodeResource(getResources(),
R.drawable.circles1_6);
int leftorg2=(int)(650*(screenWidth/1024));
canvas.drawBitmap(bitmapOrg2, leftorg2,toporg, painto);
bitmapOrg2.recycle();
bitmapOrg2=null;
bitmapOrg3 = BitmapFactory.decodeResource(getResources(),
R.drawable.circles1_1);
int leftorg3=(int)(170*(screenWidth/1024));
int toporg3=(int)(350*(screenHeight/600));
canvas.drawBitmap(bitmapOrg3, leftorg3,toporg3, painto);
bitmapOrg3.recycle();
bitmapOrg3=null;
bitmapOrg4 = BitmapFactory.decodeResource(getResources(),
R.drawable.circles1_3);
int leftorg4=(int)(680*(screenWidth/1024));
canvas.drawBitmap(bitmapOrg4, leftorg4,toporg3, painto);
bitmapOrg4.recycle();
bitmapOrg4=null;
bitmapOrg5 = BitmapFactory.decodeResource(getResources(),
R.drawable.circles1_2);
int leftorg5=(int)(400*(screenWidth/1024));
int toporg5=(int)(300*(screenHeight/600));
canvas.drawBitmap(bitmapOrg5, leftorg5,toporg5, painto);
bitmapOrg5.recycle();
bitmapOrg5=null;
Paint paint1 = new Paint();
paint1.setAntiAlias(true);
paint1.setColor(Color.BLACK);
paint1.setStrokeWidth(3);
paint1.setStyle(Paint.Style.FILL);
paint1.setTextSize(13);
canvas.drawText("Get ready to write place your pen on the dot and follow direction ", 120, 20, paint1);
canvas.drawText("indicated by the arrow . ", 120, 38, paint1);
Paint p = new Paint();
p.setAntiAlias(true);
p.setTextSize(120);
p.setColor(Color.LTGRAY);
Typeface font = Typeface.createFromAsset(getAssets(), "font/KINDTRG.TTF");
p.setTypeface(font);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
} private float mX, mY;
private final float TOUCH_TOLERANCE = 2;
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();
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 clearAllResources() {
// Set related variables null
System.gc();
Runtime.getRuntime().gc();
}
#Override
protected void onPause() {
if (mediay2 != null){
mediay2.stop();
mediay2.release();
mediay2=null;
}
clearAllResources();
super.onPause();
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
System.gc();
Runtime.getRuntime().gc();
unbindDrawables(findViewById(R.id.relative));
}
private void unbindDrawables(View view) {
// TODO Auto-generated method stub
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
}
}
You use memory heap more than gcc allowed size. You must use slaced bitmaps
or
+3.0 in manifest add application
android:largeHeap="true" to allocate more heap size.
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoTitleBar.Fullscreen"
android:largeHeap="true">...
Try This
After you get bitmap then recycle bitmap after use this will solve some issue.
Bitmap finalImage;
finalImage.recycle();
Or try in onResume()
System.gc();
I suggest you have a look at this thread: Strange out of memory issue while loading an image to a Bitmap object
This was answer on the thread:
public Bitmap readAssetsBitmap(String filename) throws IOException {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeStream(assets.open(filename), null, options);
if(bitmap == null) {
throw new IOException("File cannot be opened: It's value is null");
}
else {
return bitmap;
}
} catch (IOException e) {
throw new IOException("File cannot be opened: " + e.getMessage());
}
}
Remember to recycle bitmaps and set them to null once they have been used to ensure the get GCed.
Note: You shouldn't call System.gc();
I hope this helps.