I'm working an app which is can draw on a custom view. I want to save the drawing with a button. I tried the other solution on the other threads but nothing. please give me an example with my method below. actually, it's not my method. it's from https://github.com/msiuts/FingerPaint
Custom View
DrawView.java
public class DrawView extends View implements OnTouchListener {
private static final String TAG = "DrawView";
private final Random random = new Random();
private final int[] colors = new int[] {Color.BLACK, Color.BLACK, Color.BLACK, Color.BLACK, Color.BLACK,
Color.BLACK, Color.BLACK, Color.BLACK, Color.BLACK, Color.BLACK};
private final Paint paint = new Paint();
private Path path = new Path();
private Canvas canvas;
private Bitmap bitmap;
// deletes the screen by painting it black when the Menu Button is pressed
// this is a good method but how about save the drawing?
private OnKeyListener clearingOnKeyListener = new OnKeyListener() {
public boolean onKey(View view, int i, KeyEvent keyEvent) {
if (KeyEvent.KEYCODE_MENU == keyEvent.getKeyCode() && KeyEvent.ACTION_DOWN == keyEvent.getAction()) {
bitmap.eraseColor(Color.BLACK);
invalidate();
return true;
}
return false;
}
};
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
this.setOnKeyListener(clearingOnKeyListener);
paint.setColor(randomColor());
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3f);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (bitmap != null) {
if (bitmap.getHeight() == w && bitmap.getWidth() == h) {
Log.d(TAG, "rotating bitmap by 90 degree");
Matrix mtx = new Matrix();
mtx.postRotate(90, h/2, w/2);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, h, w, mtx, false);
canvas = new Canvas();
canvas.setBitmap(bitmap);
return;
} else {
bitmap.recycle();
}
}
canvas = new Canvas();
bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
canvas.setBitmap(bitmap);
}
#Override
public void onDraw(Canvas c) {
// draw to the screen
c.drawBitmap(bitmap, null, new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()), null);
}
public boolean onTouch(View view, MotionEvent event) {
// draw the new Points to our internal canvas / bitmap
if (event.getAction() == MotionEvent.ACTION_DOWN) {
paint.setColor(randomColor());
path = new Path();
path.moveTo(event.getX(), event.getY());
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
int historySize = event.getHistorySize();
for (int i=0; i < historySize; i++) {
path.lineTo(event.getHistoricalX(i), event.getHistoricalY(i));
}
path.lineTo(event.getX(), event.getY());
canvas.drawPath(path, paint);
} else {
return super.onTouchEvent(event);
}
invalidate();
return true;
}
public Bitmap getBitmap() {
return bitmap;
}
public void initBitmap(Bitmap bmap) {
bitmap = bmap;
}
/**
* Chooses a random color.
* #return the chosen color
*/
private int randomColor() {
return colors[random.nextInt(colors.length)];
}
}
Activity
Drawing Activity.java
public class DrawingActivity extends Activity {
private static final String TAG = "FingerPaint";
private DrawView drawView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw);
// restore view
drawView = (DrawView) findViewById(R.id.drawView);
Log.d(TAG, "DrawView from R is null? " + (drawView == null));
Bitmap lastDrawing = (Bitmap) getLastNonConfigurationInstance();
if (lastDrawing != null) {
Log.d(TAG, "lastDrawing is not null");
drawView.initBitmap(lastDrawing);
}
}
#Override
public Object onRetainNonConfigurationInstance() {
Bitmap bmap = null;
if (drawView != null) {
bmap = drawView.getBitmap();
Log.d(TAG, "onRetainNonConfigurationInstance returning a bitmap: " + (bmap != null));
}
return bmap;
}
#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;
}
#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();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
On the assumption you want to save the file to the devices storage, here is the solution i use...
Add permission to manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Here is how I am doing it:
// Variables i needed
private String mFileName;
private Bitmap mBitmap;
// apply this listener to your button
private final View.OnClickListener ButtonListener = new View.OnCickListener(){
#Override
public void onClick(View v){
new SaveFile().execute();
}
}
private class SaveFile extends AsyncTask<Void, Void, File>{
#Override
protected File doInBackground(Void... params) {
View rootView = findViewById(R.id.drawView);
File newBackgroundBitmap = saveFileToStorage(rootView);
return newBackgroundBitmap;
}
#Override
protected void onPostExecute(File bitmapFile) {
super.onPostExecute(bitmapFile);
if(bitmapFile != null){
Toast.makeText(getBaseContext(), "Saved drawView to storage", Toast.LENGTH_SHORT).show();
}
}
}
Then here is the method doing all the work:
/**
* Saves the Bitmap File to Storage and returns the new File
* #param rootView - the View we want to capture
* #return returns the new FileName of the image.
*/
private File saveFileToStorage(View rootView){
rootView.setDrawingCacheEnabled(true);
mBitmap = rootView.getDrawingCache();
File fileDirectory = new File(Environment.getExternalStorageDirectory() + "FOLDER_NAME_YOU_WANT_TO_USE");
fileDirectory.mkdirs();
// Filename to store, Probably want to add some time stamp to make this unique
mFileName = "YOUR_FILE_NAME"+ ".png";
final File newBackgroundBitmap = new File(fileDirectory, mFileName);
try{
newBackgroundBitmap.createNewFile();
FileOutputStream outputStream = new FileOutputStream(newBackgroundBitmap);
mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
outputStream.close();
Log.d(TAG, "File saved..." + " " + mFileName);
}catch(Exception e){
e.printStackTrace();
}
return newBackgroundBitmap;
}
Related
I draw using my finger some signatures using this fragment, it works fine but when I try to save the bitmap, I try this function Bitmap bitmap = view.getDrawingCache(); but it's always Null , so my question is how to get the real file bitmap to use it after !
this is my code :
public class FingerDrawFragment extends DialogFragment
{
private RelativeLayout relativeLayout;
private Paint paint;
private View view;
private Path path2;
private Bitmap bitmap;
private Canvas canvas;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.draw_fragment, container, false);
Bundle b = getArguments();
if(b != null)
{
int id = b.getInt("id");
Boolean isInfraction = b.getBoolean("infraction");
if(isInfraction)
infraction = realm.where(Infraction.class).equalTo("id",id).findFirst();
}
view = new SketchSheetView(getActivity());
paint = new Paint();
path2 = new Path();
paint.setDither(true);
paint.setColor(getResources().getColor(R.color.TealDark));
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(2);
((RelativeLayout) v.findViewById(R.id.body)).addView(view );
((TextView)v.findViewById(R.id.topBarTitle)).setText("Signature");
v.findViewById(R.id.delete_draw).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
path2.reset();
}
});
v.findViewById(R.id.save_draw).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder editalert = new AlertDialog.Builder(getActivity());
editalert.setTitle("Please Enter the name with which you want to Save");
final EditText input = new EditText(getActivity());
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 = view.getDrawingCache();
String root = Utils.getFirstWritableDirectory().toString();
File file = new File(root + "/.SMS_Images/"+name+".png");
try
{
if(!file.exists())
{
file.createNewFile();
}
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 10, ostream);
ostream.close();
view.invalidate();
}
catch (Exception e)
{
e.printStackTrace();
}finally
{
view.setDrawingCacheEnabled(false);
}
}
});
editalert.show();
}
});
return v;
}
class SketchSheetView extends View {
public SketchSheetView(Context context) {
super(context);
bitmap = Bitmap.createBitmap(820, 480, Bitmap.Config.ARGB_4444);
canvas = new Canvas(bitmap);
this.setBackgroundColor(Color.WHITE);
}
private ArrayList<DrawingClass> DrawingClassArrayList = new ArrayList<DrawingClass>();
#Override
public boolean onTouchEvent(MotionEvent event) {
DrawingClass pathWithPaint = new DrawingClass();
canvas.drawPath(path2, paint);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
path2.moveTo(event.getX(), event.getY());
path2.lineTo(event.getX(), event.getY());
}
else if (event.getAction() == MotionEvent.ACTION_MOVE) {
path2.lineTo(event.getX(), event.getY());
pathWithPaint.setPath(path2);
pathWithPaint.setPaint(paint);
DrawingClassArrayList.add(pathWithPaint);
}
invalidate();
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (DrawingClassArrayList.size() > 0) {
canvas.drawPath(
DrawingClassArrayList.get(DrawingClassArrayList.size() - 1).getPath(),
DrawingClassArrayList.get(DrawingClassArrayList.size() - 1).getPaint());
}
}
}
public class DrawingClass {
Path DrawingClassPath;
Paint DrawingClassPaint;
public Path getPath() {
return DrawingClassPath;
}
public void setPath(Path path) {
this.DrawingClassPath = path;
}
public Paint getPaint() {
return DrawingClassPaint;
}
public void setPaint(Paint paint) {
this.DrawingClassPaint = paint;
}
}
}
add
view.setDrawingCacheEnabled(true);
before
Bitmap bitmap = view.getDrawingCache();
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 want to create a window where the user can go out of the borders of the image but the path continues.
I have this code for my Activity
public class PaintActivity extends Activity {
PaintView maskView;
ImageView imagen;
Bitmap bitmap;
Bitmap mask;
int bitmapWidth, bitmapHeight;
public int[] getBitmapMinCoords() {
float[] minCoordF = {0, 0};
Matrix matriz = imagen.getImageMatrix();
matriz.mapPoints(minCoordF);
int[] minCoords = new int[2];
minCoords[0] = Math.round(minCoordF[0]);
minCoords[1] = Math.round(minCoordF[1]);
return minCoords;
}
public int[] getBitmapMaxCoords() {
float[] maxCoordF = {bitmapWidth, bitmapHeight};
Matrix matriz = imagen.getImageMatrix();
matriz.mapPoints(maxCoordF);
int[] maxCoords = new int[2];
maxCoords[0] = Math.round(maxCoordF[0]);
maxCoords[1] = Math.round(maxCoordF[1]);
return maxCoords;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.paint);
imagen = (ImageView) findViewById(R.id.image_paint);
maskView = (PaintView) findViewById(R.id.mask_paint);
String imagePath = "/sdcard/images/NewOrleans.gif";
bitmap = BitmapFactory.decodeFile(imagePath);
imagen.setImageBitmap(bitmap);
bitmapWidth = bitmap.getWidth();
bitmapHeight = bitmap.getHeight();
ViewTreeObserver vto = imagen.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
Matrix matrizTransformacion = imagen.getImageMatrix();
float[] values = new float[9];
if (matrizTransformacion != null) {
matrizTransformacion.getValues(values);
Log.i(PaintActivity.class.toString() + ".globalListener()", "La matriz tiene valores: " + matrizTransformacion.toString() );
}
int[] minC = getBitmapMinCoords();
int[] maxC = getBitmapMaxCoords();
Log.i("Listener MinCOORDS (0,0)", minC[0] + ", " + minC[1]);
Log.i("Listener MaxCOORDS (" + bitmapWidth + "," + bitmapHeight + ")", maxC[0] + ", " + maxC[1]);
Bitmap mapaBits = Bitmap.createBitmap( bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mapaBits);
maskView.layout(minC[0], minC[1], maxC[0], maxC[1]);
maskView.draw(canvas);
maskView.refreshDrawableState();
imagen.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}
Bitmap getMaskBitmap(View view) {
Matrix matrizTransformacion = imagen.getImageMatrix();
float[] values = new float[9];
if (matrizTransformacion != null) {
matrizTransformacion.getValues(values);
Log.i(PaintActivity.class.toString() + ".onStart()", "La matriz tiene valores: " + matrizTransformacion.toString() );
}
Bitmap mapaBits = Bitmap.createBitmap( Math.round(bitmapWidth*values[0]), Math.round(bitmapHeight*values[4]), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mapaBits);
int[] minCoords = getBitmapMinCoords();
int[] maxCoords = getBitmapMaxCoords();
view.layout(minCoords[0], minCoords[1], maxCoords[0], maxCoords[1]);
view.draw(canvas);
return mapaBits;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.inpainting_color_selection_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.inpainting_color_accept_opt:
ProgressDialog pd = ProgressDialog.show(this, "", "Guardando imagen");
Bitmap mascara = getMaskBitmap(maskView);
// GUARDANDO BITMAP EN HDD
try {
String filename = "/sdcard/PhotoRestore/mask.png";
File file = new File(filename);
FileOutputStream out = new FileOutputStream(file);
mascara.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (Exception e) {
e.printStackTrace();
}
pd.dismiss();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
This is the code for my PaintView
public class PaintView extends View {
float previousX = -1;
float previousY = -1;
float currentX = -1;
float currentY = -1;
PaintActivity activity;
Path path;
Paint paintLine = new Paint();
public PaintView(Context context) {
super(context);
init();
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PaintView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
path = new Path();
activity = (PaintActivity) getContext();
paintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
paintLine.setStyle(Paint.Style.STROKE);
paintLine.setStrokeWidth(10);
paintLine.setColor(Color.GREEN);
paintLine.setAlpha(150);
}
public void onDraw(Canvas canvas) {
canvas.drawPath(path, paintLine);
}
#Override
public boolean onTouchEvent(final MotionEvent event) {
currentX = event.getX();
currentY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(currentX, currentY);
break;
case MotionEvent.ACTION_MOVE:
path.quadTo(previousX, previousY, currentX, currentY);
break;
case MotionEvent.ACTION_UP:
path.quadTo(previousX, previousY, currentX, currentY);
break;
}
previousX = currentX;
previousY = currentY;
postInvalidate();
return true;
}
}
And this is my XML view
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/image_paint"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="#string/hola" />
<com.paint.PaintView
android:id="#+id/mask_paint"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
When I push the button I added in the menu I save the image inside memory and the screen continues being there but now i've got a border. Far away this border the paths continues drawing but it's occluded under a black surface and paths are not cutted, that's I want to occur at the beginning of the activity.
I tried to do the same in the 'onCreate()' method of the activity (inside the global layout listener) but it don't runs.
Someone could help me?
First of all, lost of thanks!
I found the way to solve my problem.
Where I need to put the view.layout() is inside the onDraw() method of the view that I want to be layout resized.
I have a problem with the flickering.
Here is my code.
public class Tutorial2D3 extends Activity {
Panel panel;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
panel = new Panel(this);
setContentView(panel);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(1, 1, 1, "Clean Canvas");
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
panel.cleanCanvas();
return true;
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
TutorialThread thread;
Bitmap icon;
int iconWidth;
int iconHeight;
int touchX;
int touchY;
int mCount = 0;
public Panel(Context context) {
super(context);
icon = BitmapFactory
.decodeResource(getResources(), R.drawable.icon);
iconWidth = icon.getWidth();
iconHeight = icon.getHeight();
getHolder().addCallback(this);
thread = new TutorialThread(getHolder(), this);
setFocusable(true);
}
#Override
protected void onDraw(Canvas canvas) {
int x = touchX - (iconWidth / 2);
int y = touchY - (iconHeight / 2);
if(mCount>0) {
canvas.drawColor(Color.BLACK);
mCount--;
}
canvas.drawBitmap(icon, (x > 0 ? x : 0), (y > 0 ? y : 0), null);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.setRunning(false);
do {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (retry);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchX = (int) event.getX();
touchY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
touchX = (int) event.getX();
touchY = (int) event.getY();
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return true;
}
private void cleanCanvas() {
mCount = 2;
}
}
class TutorialThread extends Thread {
private SurfaceHolder _surfaceHolder;
private Panel _panel;
private boolean _run = false;
public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
#Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.onDraw(c);
}
} finally {
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
The drawn image flickers.
It looks like the bitmap that is drawn at one point is drawn on one surface and not the other so it looks like flickering, the bitmap that is drawn when we touch action_up is done, that is a solid image and does not flickers. Could someone please help me with this one.
Thanks
When you are drawing in the Canvas of a SurfaceView, you must always draw every pixel of the surface.
Here you are not always clearing the Canvas in onDraw(), hence the flickering.
One thing you could do to mitigate that (and to kinda contradict Guillaume :)) is to use surfaceholder.lockCanvas(rectangle), where it is only the specified rectangle part of the canvas which is then drawn (but you must draw every pixel of that rect). Here it is, ripped from the LunarLandar sample:
#Override
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(Rectangle);
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING) updatePhysics();
doDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
I didn't read through all of your code, but I think this article will help.
The essence of the article is that flickering is due to double buffering and can be eliminated by drawing not to the argument Canvas but to a bitmap used as the canvas and then drawing that bitmap to the arg Canvas:
int myCanvas_w, myCanvas_h;
Bitmap myCanvasBitmap = null;
Canvas myCanvas = null;
Matrix identityMatrix;
#Override
public void surfaceCreated(SurfaceHolder holder) {
myCanvas_w = getWidth();
myCanvas_h = getHeight();
myCanvasBitmap = Bitmap.createBitmap(myCanvas_w, myCanvas_h, Bitmap.Config.ARGB_8888);
myCanvas = new Canvas();
myCanvas.setBitmap(myCanvasBitmap);
identityMatrix = new Matrix();
}
#Override
protected void onDraw(Canvas canvas) {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
//int w = myCanvas.getWidth();
//int h = myCanvas.getHeight();
int x = random.nextInt(myCanvas_w-1);
int y = random.nextInt(myCanvas_h-1);
int r = random.nextInt(255);
int g = random.nextInt(255);
int b = random.nextInt(255);
paint.setColor(0xff000000 + (r << 16) + (g << 8) + b);
myCanvas.drawPoint(x, y, paint); // <--------- Here's where you draw on your bitmap
canvas.drawBitmap(myCanvasBitmap, identityMatrix, null);
// ^---------- And here's where you draw that bitmap to the canvas
}