I am trying to save custom view as image but this is not happening it only gives black image when i open it in android device gallery. The custom view is like this
public class page extends View
{
private static final String TAG = "DrawView";
private boolean clearflag = false;
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Context context;
private Paint mPaint = new Paint();
private int[] pencolor = { Color.BLUE, Color.GREEN, Color.MAGENTA,
Color.BLACK, Color.CYAN, Color.GRAY, Color.RED, Color.DKGRAY,
Color.LTGRAY, Color.YELLOW };
private Canvas mCanvas;
private Path mPath;
private ArrayList<Path> paths = new ArrayList<Path>();
public void ClearScreen()
{
clearflag = true;
invalidate();
}
public void resetPenColor()
{
Random random = new Random();
random.setSeed(System.currentTimeMillis());
int color_index = random.nextInt(pencolor.length);
// Toast.makeText(context, "Pen Color "+color_index, Toast.LENGTH_SHORT).show();
mPaint.setColor(pencolor[color_index]);
}
public void init(Context context) {
//super(context);
this.context = context;
setFocusable(true);
setFocusableInTouchMode(true);
//this.setOnTouchListener(this);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
mCanvas = new Canvas();
mPath = new Path();
paths.add(mPath);
}
public page(Context context, AttributeSet attrs)
{
super(context, attrs);
init(context);
this.context = context;
}
public page(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init(context);
this.context = context;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas)
{
if(clearflag)
{
canvas.drawColor(Color.WHITE);
clearflag = false;
paths.clear();
paths.add(mPath);
Log.v("Clear Screen", "---");
}
else
{
for (Path p : paths)
{
canvas.drawPath(p, mPaint);
Log.v("draw", "---line");
}
}
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y)
{
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
Log.v("Touch", "Start");
}
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;
}
Log.v("Touch", "Move");
}
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(mPath);
Log.v("Touch", "Move");
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
float x = event.getX();
float y = event.getY();
switch (event.getActionMasked())
{
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;
case MotionEvent.ACTION_POINTER_DOWN:
resetPenColor();
// Toast.makeText(context, "Multitouch", Toast.LENGTH_SHORT).show();
invalidate();
break;
}
return true;
}
}
and the main activity in which i am saving bitmap is like this
public class Book extends Activity
{
private ImageButton refresh;
private ImageButton save;
private page pg;
public void init()
{
refresh = (ImageButton) findViewById(R.id.refresh);
save = (ImageButton) findViewById(R.id.save);
pg = (page) findViewById(R.id.page);
}
public void onCreate(Bundle onsavestate)
{
super.onCreate(onsavestate);
setContentView(R.layout.book);
init();
addListeners();
}
public void addListeners()
{
refresh.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View arg0)
{
// TODO Auto-generated method stub
pg.ClearScreen();
}
});
save.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
// TODO Auto-generated method stub
saveautograph();
}
});
}
public void saveautograph()
{
Bitmap returnedbitmap = Bitmap.createBitmap(pg.getWidth(), pg.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedbitmap);
pg.draw(canvas);
/*Drawable bgDrawable = pg.getBackground();
if(bgDrawable != null)
{
bgDrawable.draw(canvas);
}*/
OutputStream stream = null;
try
{
stream = new FileOutputStream(Environment.getExternalStorageDirectory()+"/autograph.jpeg");
}
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
try
{
stream.flush();
stream.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
if(stream == null)
{
Log.v("Stream", "null");
}
if(returnedbitmap == null)
{
Log.v("bitmap", "null");
}
returnedbitmap.compress(CompressFormat.PNG, 90, stream);
}
}
and here is the xml file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rl"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<LinearLayout
android:id="#+id/buttonlayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#drawable/buttoncontainer"
android:gravity="bottom|center"
android:orientation="horizontal" >
<ImageButton
android:id="#+id/refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#color/white"
android:src="#drawable/refresh"
android:layout_marginLeft="4dp" />
<ImageButton
android:id="#+id/save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#color/white"
android:src="#drawable/save"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp" />
</LinearLayout>
<com.gsmappstabs.autographplease.page
android:id="#+id/page"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/buttonlayout" />
</RelativeLayout>
Help please
Update your saveautograph method as follows:
public void saveautograph()
{
pg.setDrawingCacheEnabled(true);
pg.buildDrawingCache();
Bitmap returnedBitmap = pg.getDrawingCache();
try {
FileOutputStream out = new FileOutputStream(Environment.getExternalStorageDirectory()+"/autograph.jpeg");
returnedBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
pg.setDrawingCacheEnabled(false);
}
Basically, you can get the view as bitmap using the getDrawingCache method. Then directly save the bitmap to file..
I believe you are trying to save the signatures captured on a view to an image. I have something ready which I re-use in my projects.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Environment;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.leelasofttech.android.pcm.R;
import com.leelasofttech.android.pcm.util.Constants;
public class DrawView extends View {
protected static final String TAG = "DrawView";
protected Bitmap mBitmap;
protected Canvas mCanvas;
protected Path mPath;
protected Paint mBitmapPaint;
protected Paint paint;
protected int bgColor;
public DrawView(Context context) {
super(context);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
bgColor = context.getResources().getColor(R.color.edit_box_normal);
setupPaint();
}
public DrawView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
bgColor = context.getResources().getColor(R.color.edit_box_normal);
setupPaint();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, getPaint());
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touchStart(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touchMove(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touchUp() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, getPaint());
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touchUp();
invalidate();
break;
}
return true;
}
protected void setupPaint() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
paint.setColor(bgColor);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(4);
}
public String toJPEGFile(String folderName, String fileName) {
File folder = new File(Environment.getExternalStorageDirectory() + File.separator + Constants.APP_FOLDER + File.separator + folderName + File.separator);
if (!folder.exists()) {
folder.mkdirs();
}
File file = null;
try {
this.setDrawingCacheEnabled(true);
file = new File(folder.getPath() + File.separator + fileName + Constants.FILE_TYPE_JPEG);
FileOutputStream fos = new FileOutputStream(file);
Bitmap bitmap = this.getDrawingCache();
bitmap.compress(CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
return file.getAbsolutePath();
}
catch (FileNotFoundException ex) {
Log.e(TAG, ex.getMessage(), ex);
}
catch (IOException ex) {
Log.e(TAG, ex.getMessage(), ex);
}
catch (Exception ex) {
Log.e(TAG, ex.getMessage(), ex);
}
return null;
}
public Paint getPaint() {
return paint;
}
public void setPaint(Paint paint) {
this.paint = paint;
}
public void changePaintStroke(float stroke) {
paint.setStrokeWidth(stroke);
}
public void changePaintColor(int newColor) {
paint.setColor(newColor);
}
}
// Signature view
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Path;
import android.util.AttributeSet;
public class SignatureView extends DrawView {
public SignatureView(Context context) {
super(context);
paint.setColor(Color.BLACK);
}
public SignatureView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
paint.setColor(Color.BLACK);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, getPaint());
}
public void resetSignatures() {
mPath = new Path();
invalidate();
}
}
Hope this helps.
Related
When I rotate a phone my DrawerView is clearing . When I rotate my phone in my class DrawerView is running onSizeChanged and after that my drawView is empty. I have added android:configChanges="keyboardHidden|orientation|screenSize" in my AndroidManifest but it doesn't work.
This is my drawer view :
public class DrawerView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private float mX, mY, sX, sY;
private boolean isSigned = false;
public DrawerView(Context c) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint.setColor(Color.WHITE);
}
public DrawerView(Context c, Bitmap bitmap) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint.setColor(Color.WHITE);
mBitmap = bitmap;
}
public void setIsSigned(boolean isSigned) {
this.isSigned = isSigned;
}
public boolean isSigned() {
return isSigned;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
mCanvas = new Canvas(mBitmap);
mCanvas.drawColor(Color.WHITE);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
public void clear() {
setDrawingCacheEnabled(true);
mCanvas.drawColor(Color.WHITE);
invalidate();
}
private void drawDot(float x, float y) {
mCanvas.drawCircle(x, y, 2.0f, mPaint);
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
sX = x;
sY = y;
}
private void touch_move(float x, float y) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
mCanvas.drawPath(mPath, mPaint);
}
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
this.isSigned = true;
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
break;
case MotionEvent.ACTION_UP:
if (x == sX && y == sY) {
drawDot(x, y);
}
touch_up();
break;
}
invalidate();
return true;
}
}
When I rotate a phone this is doing and
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
mCanvas = new Canvas(mBitmap);
mCanvas.drawColor(Color.WHITE);
}
and my drawer is clearing
this is my whole class :
public class SignatureActivity extends Activity implements Handler.Callback {
File mCurrentPhotoPath;
private FrameLayout drawerBox;
private Button save, clear;
private DrawerView mv;
private Paint mPaint;
private boolean existingSign;
private Intent intent;
private String signature;
private File imagesDir;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawer_act_lay);
existingSign = getIntent().hasExtra(getPackageName() + "_signaturePath");
initializeView();
setListeners();
Intent iin = getIntent();
Bundle b = iin.getExtras();
if (b != null) {
signature = (String) b.get("signaturePath");
}
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
public void onBackPressed() {
setResult(RESULT_CANCELED);
finish();
}
private void initializeView() {
drawerBox = this.findViewById(R.id.drawerContainer);
save = findViewById(R.id.saveBtn);
clear = findViewById(R.id.clearBtn);
if (existingSign) {
mv = new DrawerView(this, BitmapFactory.decodeFile(getIntent()
.getStringExtra(getPackageName() + "_signaturePath")));
} else {
mv = new DrawerView(this);
}
mv.setDrawingCacheEnabled(false);
mv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
drawerBox.addView(mv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(3);
mv.setDrawingCacheEnabled(true);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
mCurrentPhotoPath = (File) savedInstanceState.getSerializable(MY_CURRENT_PHOTO_PATH_KEY);
super.onRestoreInstanceState(savedInstanceState);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putSerializable(MY_CURRENT_PHOTO_PATH_KEY, mCurrentPhotoPath);
super.onSaveInstanceState(outState);
}
private void setListeners() {
save.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (!mv.isSigned()) {
Toast.makeText(SignatureActivity.this, R.string.empty_sign, Toast.LENGTH_SHORT).show();
} else {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
String currentDateandTime = sdf.format(new Date());
String name = "sign_" + currentDateandTime;
Bitmap bitmap = mv.getDrawingCache();
File imagesFolder = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
imagesFolder.mkdirs();
File file = new File(imagesFolder, name + ".jpg");
try {
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, ostream);
ostream.close();
mv.invalidate();
} catch (Exception e) {
e.printStackTrace();
} finally {
mv.setDrawingCacheEnabled(true);
}
Intent data = new Intent();
data.putExtra(getPackageName() + "_signaturePath", file.getPath());
setResult(RESULT_OK, data);
finishWithResult(file.getPath());
if (signature != null) {
File file1 = new File(signature);
file1.delete();
}
}
}
});
clear.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mv.clear();
mv.setIsSigned(false);
}
});
}
private void finishWithResult(String path) {
Intent intent = new Intent();
setResult(RESULT_OK, intent);
intent.putExtra("path", path);
finish();
}
#Override
public boolean handleMessage(Message msg) {
return false;
}
public class DrawerView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private float mX, mY, sX, sY;
private boolean isSigned = false;
public DrawerView(Context c) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint.setColor(Color.WHITE);
}
public DrawerView(Context c, Bitmap bitmap) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint.setColor(Color.WHITE);
mBitmap = bitmap;
}
public void setIsSigned(boolean isSigned) {
this.isSigned = isSigned;
}
public boolean isSigned() {
return isSigned;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
mCanvas = new Canvas(mBitmap);
mCanvas.drawColor(Color.WHITE);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
public void clear() {
setDrawingCacheEnabled(true);
mCanvas.drawColor(Color.WHITE);
invalidate();
}
private void drawDot(float x, float y) {
mCanvas.drawCircle(x, y, 2.0f, mPaint);
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
sX = x;
sY = y;
}
private void touch_move(float x, float y) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
mCanvas.drawPath(mPath, mPaint);
}
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
this.isSigned = true;
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
break;
case MotionEvent.ACTION_UP:
if (x == sX && y == sY) {
drawDot(x, y);
}
touch_up();
break;
}
invalidate();
return true;
}
}
}
You could save the touch events in some type of List and then recreate them after configuration changes. This is already explained in here.
Your class should look like this
public class DrawerView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private float mX, mY, sX, sY;
private boolean isSigned = false;
private static final String EXTRA_STATE = "exta_state";
private static final String EXTRA_EVENT_LIST = "exta_event_list";
private ArrayList<MotionEvent> motionEvents = new ArrayList<>();
private ArrayList<MotionEvent> auxMotionEvents = new ArrayList<>();
public DrawerView(Context c) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint.setColor(Color.WHITE);
setSaveEnabled(true);
}
public DrawerView(Context c, AttributeSet attributeSet) {
super(c, attributeSet);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint.setColor(Color.WHITE);
setSaveEnabled(true);
}
public DrawerView(Context c, Bitmap bitmap) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint.setColor(Color.WHITE);
mBitmap = bitmap;
setSaveEnabled(true);
}
#Override
public Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(EXTRA_STATE, super.onSaveInstanceState());
bundle.putParcelableArrayList(EXTRA_EVENT_LIST, motionEvents);
return bundle;
}
#Override
public void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
auxMotionEvents = new ArrayList<>();
motionEvents = new ArrayList<>();
Bundle bundle = (Bundle) state;
super.onRestoreInstanceState(bundle.getParcelable(EXTRA_STATE));
auxMotionEvents = bundle.getParcelableArrayList(EXTRA_EVENT_LIST);
if (auxMotionEvents == null) {
auxMotionEvents = new ArrayList<>();
}
return;
}
super.onRestoreInstanceState(state);
}
private void performTouch(MotionEvent event) {
this.isSigned = true;
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
break;
case MotionEvent.ACTION_UP:
if (x == sX && y == sY) {
drawDot(x, y);
}
touch_up();
break;
}
invalidate();
motionEvents.add(MotionEvent.obtain(event));
}
public void setIsSigned(boolean isSigned) {
this.isSigned = isSigned;
}
public boolean isSigned() {
return isSigned;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
mCanvas = new Canvas(mBitmap);
mCanvas.drawColor(Color.WHITE);
if (auxMotionEvents != null) {
for (MotionEvent motionEvent : auxMotionEvents) {
performTouch(motionEvent);
}
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mBitmapPaint);
}
public void clear() {
setDrawingCacheEnabled(true);
mCanvas.drawColor(Color.WHITE);
invalidate();
}
private void drawDot(float x, float y) {
mCanvas.drawCircle(x, y, 2.0f, mBitmapPaint);
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
sX = x;
sY = y;
}
private void touch_move(float x, float y) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
mCanvas.drawPath(mPath, mBitmapPaint);
}
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mBitmapPaint);
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
performTouch(event);
}
return true;
}
}
Remember to remove android:configChanges="keyboardHidden|orientation|screenSize" from your manisfest and to give the view an id so it can be recreated.
To set an id for your view use setId() after you instantiate DrawerView in your initializeView(). It should look something like this
private void initializeView() {
drawerBox = this.findViewById(R.id.drawerContainer);
save = findViewById(R.id.saveBtn);
clear = findViewById(R.id.clearBtn);
if (existingSign) {
mv = new DrawerView(this, BitmapFactory.decodeFile(getIntent()
.getStringExtra(getPackageName() + "_signaturePath")));
} else {
mv = new DrawerView(this);
}
mv.setId(View.generateViewId());
mv.setDrawingCacheEnabled(false);
mv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
drawerBox.addView(mv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(3);
mv.setDrawingCacheEnabled(true);
}
I try to make image editor application. in this application i try to put multiple sticker on image that sticker can move , zoom , rotate, and also selected sticker can erase . can anyone help me ? here is code that i done with sticker move,rotate,zoom but i cant erase selected sticker .
public class MainActivity extends AppCompatActivity {
Bitmap originalBitmap,originalBitmap1;
RelativeLayout rlImageViewContainer;
private ImageView ivRedo;
private ImageView ivUndo;
Button btn_erase;
private ArrayList<Path> paths;
private ArrayList<Path> redoPaths;
Paint destPaint = new Paint();
Path destPath = new Path();
Bitmap destBitmap;
Canvas destCanvas = new Canvas();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.a);
originalBitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.b);
initView();
}
private void initView() {
ivUndo = (ImageView) findViewById(R.id.iv_undo);
ivRedo = (ImageView) findViewById(R.id.iv_redo);
rlImageViewContainer = findViewById(R.id.rl_image_view_container);
final PhotoSortrView photoSortrView = new PhotoSortrView(this);
rlImageViewContainer.addView(photoSortrView,0);
photoSortrView.setBackgroundColor(getResources().getColor(R.color.tran));
photoSortrView.addImages(this, originalBitmap);
photoSortrView.addImages(this, originalBitmap1);
ivUndo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// undo();
}
});
ivRedo.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// redo();
}
});
btn_erase = (Button) findViewById(R.id.btn_erase);
btn_erase.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (photoSortrView.isErase) {
btn_erase.setBackgroundColor(Color.RED);
photoSortrView.isErase = false;
photoSortrView.isMove = true;
} else {
btn_erase.setBackgroundColor(Color.GREEN);
photoSortrView.isErase = true;
photoSortrView.isMove = false;
}
}
});
}
}
PhotoSortrView.java
public class PhotoSortrView extends View implements MultiTouchController.MultiTouchObjectCanvas<MultiTouchEntity> {
private static final String TAG = "PhotoSortr ####### ";
// private static final int[] IMAGES = { R.drawable.m74hubble };
private Path drawPath = new Path();
// drawing and canvas paint
private Paint drawPaint = new Paint(), canvasPaint = new Paint();
// initial color
private int paintColor = Color.TRANSPARENT;
// canvas
private Canvas drawCanvas = new Canvas();
// canvas bitmap
private Bitmap canvasBitmap;
private ArrayList<MultiTouchEntity> imageIDs = new ArrayList<MultiTouchEntity>();
// --
private MultiTouchController<MultiTouchEntity> multiTouchController = new MultiTouchController<MultiTouchEntity>(this);
// --
private MultiTouchController.PointInfo currTouchPoint = new MultiTouchController.PointInfo();
private static final int UI_MODE_ROTATE = 1, UI_MODE_ANISOTROPIC_SCALE = 2;
private int mUIMode = UI_MODE_ROTATE;
// --
private static final float SCREEN_MARGIN = 100;
private int displayWidth, displayHeight;
public boolean isErase = false;
public boolean isMove = true;
Paint destPaint = new Paint();
Path destPath = new Path();
Bitmap destBitmap;
Canvas destCanvas = new Canvas();
int height,width;
// ---------------------------------------------------------------------------------------------------
public PhotoSortrView(Context context) {
this(context, null);
setupPaint();
init(context);
}
private void setupPaint() {
destPaint.setAlpha(0);
destPaint.setAntiAlias(true);
destPaint.setStyle(Paint.Style.STROKE);
destPaint.setStrokeJoin(Paint.Join.ROUND);
destPaint.setStrokeCap(Paint.Cap.ROUND);
destPaint.setStrokeWidth(20);
destPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
}
public PhotoSortrView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
setupDrawing();
}
public PhotoSortrView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
Log.e(TAG, "init: " );
Resources res = context.getResources();
setBackgroundColor(Color.TRANSPARENT);
DisplayMetrics metrics = res.getDisplayMetrics();
this.displayWidth = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? Math
.max(metrics.widthPixels, metrics.heightPixels) : Math.min(
metrics.widthPixels, metrics.heightPixels);
this.displayHeight = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? Math
.min(metrics.widthPixels, metrics.heightPixels) : Math.max(
metrics.widthPixels, metrics.heightPixels);
}
public void addImages(Context context, Bitmap resourceId) {
Log.e(TAG, "addImages: " );
// setupDrawing();
Resources res = context.getResources();
imageIDs.add(new ImageEntity(resourceId, res));
float cx = SCREEN_MARGIN + (float)
(Math.random() * (displayWidth - 2 * SCREEN_MARGIN));
float cy = SCREEN_MARGIN + (float)
(Math.random() * (displayHeight - 2 * SCREEN_MARGIN));
imageIDs.get(imageIDs.size() - 1).load(context, cx, cy);
invalidate();
}
public void removeAllImages() {
imageIDs.removeAll(imageIDs);
invalidate();
}
public void removeImage() {
if (imageIDs.size() > 0) {
imageIDs.remove(imageIDs.size() - 1);
}
invalidate();
}
public int getCountImage() {
return imageIDs.size();
}
// ---------------------------------------------------------------------------------------------------
#Override
protected void onDraw(Canvas canvas) {
Log.e(TAG, "onDraw: " );
if (isErase){
Log.e(TAG, "onDraw: isErase" );
if (destBitmap != null){
destCanvas.drawPath(destPath,destPaint);
canvas.drawBitmap(destBitmap,0,0,null);
}
}
else if (isMove){
height = imageIDs.get(0).getHeight();
width = imageIDs.get(0).getWidth();
Log.e(TAG, "onDraw: isMove");
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath,drawPaint);
int n = imageIDs.size();
for (int i = 0; i < n; i++)
imageIDs.get(i).draw(canvas);
}
super.onDraw(canvas);
}
// ---------------------------------------------------------------------------------------------------
public void trackballClicked() {
mUIMode = (mUIMode + 1) % 3;
invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//collegeActivity.set
int action = event.getAction();
Log.e(TAG, "onTouchEvent: " );
float touchX = event.getX();
float touchY = event.getY();
// respond to down, move and up events
if (isErase){
Log.e(TAG, "onTouchEvent: isErase" );
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
destPath.moveTo(touchX,touchY);
break;
case MotionEvent.ACTION_MOVE:
destPath.lineTo(touchX,touchY);
break;
}
} else if (isMove) {
Log.e(TAG, "onTouchEvent: isMove" );
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;
}
return multiTouchController.onTouchEvent(event);
}
invalidate();
return true;
}
private void setupDrawing() {
Log.e(TAG, "setupDrawing: " );
// prepare for drawing and setup paint stroke properties
drawPath = new Path();
drawPaint.setAlpha(0);
drawPaint.setColor(0);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(10);
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) {
if (w > 0 && h > 0) {
Log.e(TAG, "onSizeChanged: " );
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
}
// update color
public void setColor(String newColor) {
Log.e(TAG, "setColor: " );
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
public MultiTouchEntity getDraggableObjectAtPoint(MultiTouchController.PointInfo pt) {
float x = pt.getX(), y = pt.getY();
int n = imageIDs.size();
for (int i = n - 1; i >= 0; i--) {
ImageEntity im = (ImageEntity) imageIDs.get(i);
if (im.containsPoint(x, y))
return im;
}
return null;
}
public void selectObject(MultiTouchEntity img, MultiTouchController.PointInfo touchPoint) {
currTouchPoint.set(touchPoint);
if (img != null) {
// Move image to the top of the stack when selected
drawPaint.setColor(Color.TRANSPARENT);
imageIDs.remove(img);
imageIDs.add(img);
destCanvas = new Canvas();
destBitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
destCanvas.setBitmap(destBitmap);
destCanvas.drawBitmap(img.getBitmap(),0,0,null);
} else {
// Called with img == null when drag stops.
}
invalidate();
}
public void getPositionAndScale(MultiTouchEntity img, MultiTouchController.PositionAndScale objPosAndScaleOut) {
// requires averaging the two scale factors)
objPosAndScaleOut.set(img.getCenterX(), img.getCenterY(),
(mUIMode & UI_MODE_ANISOTROPIC_SCALE) == 0,
(img.getScaleX() + img.getScaleY()) / 2,
(mUIMode & UI_MODE_ANISOTROPIC_SCALE) != 0, img.getScaleX(),
img.getScaleY(), (mUIMode & UI_MODE_ROTATE) != 0,
img.getAngle());
}
/**
* Set the position and scale of the dragged/stretched image.
*/
public boolean setPositionAndScale(MultiTouchEntity img,
MultiTouchController.PositionAndScale newImgPosAndScale, MultiTouchController.PointInfo touchPoint) {
currTouchPoint.set(touchPoint);
boolean ok = img.setPos(newImgPosAndScale);
if (ok)
invalidate();
return ok;
}
public boolean pointInObjectGrabArea(MultiTouchController.PointInfo pt, MultiTouchEntity img) {
return false;
}
}
I have a DrawingView class, which implements painting methods. It works perfectly when I paint something, but after, by the time I try to save what I've painted in a jpg file I get a black image. I've read many answers here in Stack Overflow, and blogs which explain how to do that, and don't understand why I still having the black image. Here is my code:
DrawingView:
public class DrawingView extends View {
private Path drawPath;
private Paint drawPaint;
private Paint canvasPaint;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
drawPath = new Path();
drawPaint = new Paint();
canvasPaint = new Paint(Paint.DITHER_FLAG);
drawPaint.setColor(Color.BLACK);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(5f);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
}
public DrawingView(Context context) {
super(context);
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(Color.BLACK);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(5f);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
}
#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);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFFFFF);
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
invalidate();
return true;
}
}
And I'm using here:
public void btFirma_FRAGMENT_CIERRE(View v) {
final DrawingView dv = new DrawingView(this);
LayoutParams params = CierreFragment.getdvFirma().getLayoutParams();
dv.setLayoutParams(params);
dv.setDrawingCacheEnabled(true);
dv.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
dv.layout(0, 0, v.getWidth(), v.getHeight());
dv.buildDrawingCache(true);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(dv);
builder.setPositiveButton("Aceptar", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Log.d("DialogFirma", "Se pulsa el botón aceptar del dialog");
// TODO Establecer el nombre que se quiere asignar a la firma.
imageName = "prueba.jpg";
// TODO Guardar imagen de la firma en la carpeta /FIRMAS/
saveImageSign(dv.getDrawingCache());
Drawable background = getImageSign(imageName);
if (background != null)
CierreFragment.setdvBackGround(background);
}
});
builder.setNegativeButton("Cancelar", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
Log.d("DialogFirma", "Se pulsa el botón cancelar del dialog");
}
});
builder.show();
}
private void saveImageSign(Bitmap finalBitmap) {
File file = new File(
((AISApplication) getApplicationContext())
.getLocalFolderFIRMAS() + imageName);
if (file.exists())
file.delete();
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private Drawable getImageSign(String imageName) {
FileInputStream in;
try {
in = new FileInputStream(new File(
((AISApplication) getApplication()).getLocalFolderFIRMAS()
+ imageName));
Bitmap bmp = BitmapFactory.decodeStream(in);
return new BitmapDrawable(getResources(), bmp);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
Can anyone tell me where's my fail?
I haven't looked too deeply into your code, but here's how I get the image I've just drawn:
private Bitmap getImage() {
tile = Bitmap.createBitmap(faces[0]); // create the bitmap (from existing or blank)
Canvas c = new Canvas(tile); // create a new canvas using that bitmap
c.drawBitmap(tile, 0, 0, null); // draw the bitmap onto the canvas
// do more drawing - here I add another image
c.drawBitmap(scoresBm[initScores[0]], vertex.get(0).x, vertex.get(0).y, null);
return tile; // just return the bitmap
}
Saving the image
// write the image back out (using compression in this one)
try {
FileOutputStream out = new FileOutputStream(imgFile);
_bitmapScaled.compress(Bitmap.CompressFormat.JPEG, 50, out);
out.flush();
out.close();
} catch (Exception e) {
I would like to include a color picker in my paint program. So anyone here has already done something like this please give me some tutorials or piece of code to get me started. I really need to get the whole idea of adding this. I already have set up the canvas for the drawing so I'd like to add the color picker to it. Any ideas are welcome. Thanks.
Your class should implement ColorPickerDialog.OnColorChangedListener
public class MainActivity implements ColorPickerDialog.OnColorChangedListener
{
private Paint mPaint;
mPaint = new Paint();
// on button click
new ColorPickerDialog(this, this, mPaint.getColor()).show();
}
ColorPicker Dialog
public class ColorPickerDialog extends Dialog {
public interface OnColorChangedListener {
void colorChanged(int color);
}
private OnColorChangedListener mListener;
private int mInitialColor;
private static class ColorPickerView extends View {
private Paint mPaint;
private Paint mCenterPaint;
private final int[] mColors;
private OnColorChangedListener mListener;
ColorPickerView(Context c, OnColorChangedListener l, int color) {
super(c);
mListener = l;
mColors = new int[] {
0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
0xFFFFFF00, 0xFFFF0000
};
Shader s = new SweepGradient(0, 0, mColors, null);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setShader(s);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(32);
mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCenterPaint.setColor(color);
mCenterPaint.setStrokeWidth(5);
}
private boolean mTrackingCenter;
private boolean mHighlightCenter;
#Override
protected void onDraw(Canvas canvas) {
float r = CENTER_X - mPaint.getStrokeWidth()*0.5f;
canvas.translate(CENTER_X, CENTER_X);
canvas.drawOval(new RectF(-r, -r, r, r), mPaint);
canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint);
if (mTrackingCenter) {
int c = mCenterPaint.getColor();
mCenterPaint.setStyle(Paint.Style.STROKE);
if (mHighlightCenter) {
mCenterPaint.setAlpha(0xFF);
} else {
mCenterPaint.setAlpha(0x80);
}
canvas.drawCircle(0, 0,
CENTER_RADIUS + mCenterPaint.getStrokeWidth(),
mCenterPaint);
mCenterPaint.setStyle(Paint.Style.FILL);
mCenterPaint.setColor(c);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(CENTER_X*2, CENTER_Y*2);
}
private static final int CENTER_X = 100;
private static final int CENTER_Y = 100;
private static final int CENTER_RADIUS = 32;
private int floatToByte(float x) {
int n = java.lang.Math.round(x);
return n;
}
private int pinToByte(int n) {
if (n < 0) {
n = 0;
} else if (n > 255) {
n = 255;
}
return n;
}
private int ave(int s, int d, float p) {
return s + java.lang.Math.round(p * (d - s));
}
private int interpColor(int colors[], float unit) {
if (unit <= 0) {
return colors[0];
}
if (unit >= 1) {
return colors[colors.length - 1];
}
float p = unit * (colors.length - 1);
int i = (int)p;
p -= i;
// now p is just the fractional part [0...1) and i is the index
int c0 = colors[i];
int c1 = colors[i+1];
int a = ave(Color.alpha(c0), Color.alpha(c1), p);
int r = ave(Color.red(c0), Color.red(c1), p);
int g = ave(Color.green(c0), Color.green(c1), p);
int b = ave(Color.blue(c0), Color.blue(c1), p);
return Color.argb(a, r, g, b);
}
private int rotateColor(int color, float rad) {
float deg = rad * 180 / 3.1415927f;
int r = Color.red(color);
int g = Color.green(color);
int b = Color.blue(color);
ColorMatrix cm = new ColorMatrix();
ColorMatrix tmp = new ColorMatrix();
cm.setRGB2YUV();
tmp.setRotate(0, deg);
cm.postConcat(tmp);
tmp.setYUV2RGB();
cm.postConcat(tmp);
final float[] a = cm.getArray();
int ir = floatToByte(a[0] * r + a[1] * g + a[2] * b);
int ig = floatToByte(a[5] * r + a[6] * g + a[7] * b);
int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b);
return Color.argb(Color.alpha(color), pinToByte(ir),
pinToByte(ig), pinToByte(ib));
}
private static final float PI = 3.1415926f;
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX() - CENTER_X;
float y = event.getY() - CENTER_Y;
boolean inCenter = java.lang.Math.sqrt(x*x + y*y) <= CENTER_RADIUS;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTrackingCenter = inCenter;
if (inCenter) {
mHighlightCenter = true;
invalidate();
break;
}
case MotionEvent.ACTION_MOVE:
if (mTrackingCenter) {
if (mHighlightCenter != inCenter) {
mHighlightCenter = inCenter;
invalidate();
}
} else {
float angle = (float)java.lang.Math.atan2(y, x);
// need to turn angle [-PI ... PI] into unit [0....1]
float unit = angle/(2*PI);
if (unit < 0) {
unit += 1;
}
mCenterPaint.setColor(interpColor(mColors, unit));
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (mTrackingCenter) {
if (inCenter) {
mListener.colorChanged(mCenterPaint.getColor());
}
mTrackingCenter = false; // so we draw w/o halo
invalidate();
}
break;
}
return true;
}
}
public ColorPickerDialog(Context context,
OnColorChangedListener listener,
int initialColor) {
super(context);
mListener = listener;
mInitialColor = initialColor;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnColorChangedListener l = new OnColorChangedListener() {
public void colorChanged(int color) {
mListener.colorChanged(color);
dismiss();
}
};
setContentView(new ColorPickerView(getContext(), l, mInitialColor));
setTitle("Pick a Color");
}
You have to choose the color and click the center circle to pick the color. Set the color to your paint object and use the same to draw.
Snap shot
Edit 2:
Source code can be found at https://code.google.com/p/android-color-picker/
Another ColorPickerDialog
public class ColorPickerDialog extends AlertDialog implements
ColorPickerView.OnColorChangedListener {
private ColorPickerView mColorPicker;
private ColorPanelView mOldColor;
private ColorPanelView mNewColor;
private OnColorChangedListener mListener;
public ColorPickerDialog(Context myDrawingMenuOptionEventsListener, int initialColor) {
super(myDrawingMenuOptionEventsListener);
init(initialColor);
}
private void init(int color) {
// To fight color branding.
getWindow().setFormat(PixelFormat.RGBA_8888);
setUp(color);
}
private void setUp(int color) {
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.dialog_color_picker, null);
layout.setBackgroundColor(Color.WHITE);
setView(layout);
setTitle("Choose a Color");
// setIcon(android.R.drawable.ic_dialog_info);
mColorPicker = (ColorPickerView) layout
.findViewById(R.id.color_picker_view);
mOldColor = (ColorPanelView) layout.findViewById(R.id.old_color_panel);
mNewColor = (ColorPanelView) layout.findViewById(R.id.new_color_panel);
((LinearLayout) mOldColor.getParent()).setPadding(Math
.round(mColorPicker.getDrawingOffset()), 0, Math
.round(mColorPicker.getDrawingOffset()), 0);
mColorPicker.setOnColorChangedListener(this);
mOldColor.setColor(color);
mColorPicker.setColor(color, true);
}
#Override
public void onColorChanged(int color) {
mNewColor.setColor(color);
if (mListener != null) {
mListener.onColorChanged(color);
}
}
public void setAlphaSliderVisible(boolean visible) {
mColorPicker.setAlphaSliderVisible(visible);
}
public int getColor() {
return mColorPicker.getColor();
}
}
Usage :
final ColorPickerDialog d= new ColorPickerDialog(ActivityName.this,0xffffffff);
d.setAlphaSliderVisible(true);
d.setButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
mPaint.setColor(d.getColor());
}
});
d.setButton2("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
d.show();
Snap shot:
In the above choose the color on the right bar. You also make a choice how dark or light the color choosen should be. Click ok to set the paint to your paint object and use the same to draw. Cancel will dismiss the color picker dialog.
Edit 3:
Only change instead of clear function i have added color picker on click of clear button.
public class MainActivity extends Activity implements ColorPickerDialog.OnColorChangedListener {
DrawingView dv ;
RelativeLayout rl;
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dv = new DrawingView(this);
setContentView(R.layout.activity_main);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
rl = (RelativeLayout) findViewById(R.id.rl);
rl.addView(dv);
Button b = (Button) findViewById(R.id.button1);
//b.setText(R.string.France);
Button b1 = (Button) findViewById(R.id.button2);
rl.setDrawingCacheEnabled(true);
b.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
// dv.clear();
new ColorPickerDialog(MainActivity.this, MainActivity.this, mPaint.getColor()).show();
}
});
b1.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
AlertDialog.Builder editalert = new AlertDialog.Builder(MainActivity.this);
editalert.setTitle("Please Enter the name with which you want to Save");
final EditText input = new EditText(MainActivity.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) {
rl.setDrawingCacheEnabled(true);
String name= input.getText().toString();
Bitmap bitmap =rl.getDrawingCache();
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/MyDraw");
myDir.mkdirs();
File file = new File (myDir, name+".png");
if (file.exists ()) file.delete ();
try
{
if(!file.exists())
{
file.createNewFile();
}
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(CompressFormat.PNG, 10, ostream);
// System.out.println("saving......................................................"+path);
ostream.close();
rl.invalidate();
}
catch (Exception e)
{
e.printStackTrace();
}finally
{
rl.setDrawingCacheEnabled(false);
}
}
});
editalert.show();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public class DrawingView extends View {
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
canvas.drawPath(circlePath, circlePaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
invalidate();
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
#Override
public void colorChanged(int color) {
// TODO Auto-generated method stub
mPaint.setColor(color);
}
}
you have a google code which can help you
http://code.google.com/p/android-color-picker/
I used this link for color picker http://code.google.com/p/android-color-picker/
steps:
I've added some extra file(like:"android-mvn-push.gradle" ) you can skip that file in step 3
and also remove this "apply from: '../android-mvn-push.gradle' " from your bulid.gradle(Module:liabrary) file if your skipping step 3.
Go to the above link and download project as zip file and extract the zip.
Inside Extracted folder you'll see library folder.
Copy that folder into your android Applications main folder where it contains all its gradle n all... and also copy "android-mvn-push.gradle" file to your main project folder.
open bulid.gradle(Module:app) inside that add dependencies like this,
"compile project(':library')"
update Settings.Gradle with include ':app', ':library'
go to Tools>Android>Sync with Gradles and then it will show some error like build gradle not matching bla bla....
Click on that open file error option.
In your bulid.gradle(Module:liabrary) change this,
apply plugin: 'com.android.library'
android {
compileSdkVersion propCompileSdkVersion
buildToolsVersion propBuildToolsVersion
defaultConfig {
minSdkVersion propMinSdkVersion
targetSdkVersion propTargetSdkVersion
versionCode propVersionCode
versionName propVersionName
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
apply from: '../android-mvn-push.gradle'
To>>>>>>>>>>>
apply plugin: 'com.android.library'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
minSdkVersion 14
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
apply from: '../android-mvn-push.gradle'
Finally Tools>Android > Sync with gradle...
and Bingo....It Works ....!!!
I'm trying to implement a personal way of undo/redo in a finger paint-like app.
I have in synthesis three objects: the Main class (named ScorePadActivity), the relative Main Layout (with buttons, menus, etc, as well as a View object where I create my drawings), and a third object named ArrayList where i'm writing the undo/redo code.
The problem is, when I press the undo button nothing happens, but if I draw anything again "one-time" and press undo, the screen is updated. If I draw many times, to see any changes happen on screen I have to press the undo button the same number of times I have drawn.
Seems like (as in title) when I add a bitmap to the array list the last element is duplicated in previous indexes, and for some strange reason, everytime I press the Undo Button, the system is ok for one time, but starts to duplicate until the next undo.
The index increase is verified with a series of System.out.println inserted in code.
Now when I draw something on screen, the array list is updated with the code inserted after the invocation of touchup(); method in motionEvent
touch_up(); }
this.arrayClass.incrementArray(mBitmap);
mPath.rewind();
invalidate();
and in ArrayList activity;
public void incrementArray(Bitmap mBitmap) {
this._mBitmap=mBitmap;
_size=undoArray.size();
undoArray.add(_size, _mBitmap);
}
(All Logs removed for clear reading)
The undo button in ScorePadActivity calls the undo method in View activity:
Button undobtn= (Button)findViewById(R.id.undo);
undobtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mView.undo();
}
});
in View activity:
public void undo() {
this.mBitmap= arrayClass.undo();
mCanvas = new Canvas(mBitmap);
mPath.rewind();
invalidate();
}
that calls the relative undo method in ArrayList activity:
public Bitmap undo() {
// TODO Auto-generated method stub
_size=undoArray.size();
if (_size>1) {
undoArray.remove(_size-1);
_size=undoArray.size();
_mBitmap = ((Bitmap) undoArray.get(_size-1)).copy(Bitmap.Config.ARGB_8888,true);
}
return _mBitmap;
}
return mBitmap and invalidate:
Due to my bad English I have made a scheme to make the problem more clear:
I have tried with HashMap, with a simple array, I have tried to change mPath.rewind(); with reset();, new Path(); etc but nothing.
Why?
Sorry for the complex answer, i want give you a great thanks in advance.
Best regards
Edit
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/buttonlayout"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >
some other layouts nested an buttons to form a upper toolbar
</LinearLayout>
<RelativeLayout
android:id="#+id/viewlayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/buttonlayout"
android:background="#drawable/desk_wood" >
<com.example.android.touchexample.MyView
android:id="#+id/viewout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
</RelativeLayout>
</RelativeLayout>
This the Main Activity ScorePadActivity
public class ScorePadActivity extends Activity {
MyView mView;
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mView = (MyView)findViewById(R.id.viewout);
Button undobtn= (Button)findViewById(R.id.undo);
undobtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mView.undo();
}
});
This is the View Activity:
public class MyView extends View {
MyView myView;
Context context;
final ArrayClass arrayClass= new ArrayClass();
private Bitmap mBitmap;
private Bitmap savedBmp;
private static Canvas mCanvas;
private static Path mPath;
private static Paint mPaint;
/*
* some other variables here
*/
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(color);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(bSize);
mPaint.setAlpha(255);
mPath = new Path();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap((int) bmWidth, (int) bmHeight,Bitmap. Config.ARGB_8888);}
/*
* here add a blank bitmap at the start of the array at index 0
*/
arrayClass.incrementArray(mBitmap);
mCanvas = new Canvas(mBitmap);
}
public void onDraw(Canvas canvas) {
canvas.save();
bx= (((width/mScaleFactor)-width)/2)+center;
by= ((height/mScaleFactor)-height)/2;
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
canvas.drawBitmap(penta, bx, by, null);
mCanvas.drawPath(mPath, mPaint);
canvas.drawBitmap(mBitmap, bx, by, null);
lastmPosX=mPosX;
lastmPosY=mPosY;
lastmScaleFactor=mScaleFactor;
canvas.restore();
}
private void touch_start(float x, float y) {
x=((x/mScaleFactor)-bx)-(mPosX/mScaleFactor);
y=((y/mScaleFactor)-by)-(mPosY/mScaleFactor);
mPath.rewind();
mPath.moveTo(x, y);
move=false;
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
x=((x/mScaleFactor)-bx)-(mPosX/mScaleFactor);
y=((y/mScaleFactor)-by)-(mPosY/mScaleFactor);
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;
move=true;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// mPath.rewind();
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
x = ev.getX();
y = ev.getY();
switch (ev.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();
// Here update the arraylist in the ArrayList activity
this.arrayClass.incrementArray(mBitmap);
mPath.rewind();
invalidate();
break;}
return true;
}
/*
* more methods here
*/ switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
public void undo() {
// Here recall the last mBitmap from Arraylist activity
this.mBitmap= arrayClass.undo();
mCanvas = new Canvas(mBitmap);
mPath.rewind();
invalidate();
}
}
and this is my ArrayList activity:
public class ArrayClass {
ArrayList<Bitmap> undoArray =new ArrayList<Bitmap>();
private int _size;
private Bitmap _mBitmap;
public void incrementArray(Bitmap mBitmap) {
this._mBitmap=mBitmap;
_size=undoArray.size();
// undoArray.add(_size, _mBitmap);
undoArray.add(_size, Bitmap.createBitmap(_mBitmap));
}
public Bitmap undo() {
// TODO Auto-generated method stub
_size=undoArray.size();
if (_size>1) {
undoArray.remove(_size-1);
_size=undoArray.size();
_mBitmap = ((Bitmap) undoArray.get(_size-1)).copy(Bitmap.Config.ARGB_8888,true);
}
return _mBitmap;
}
public Bitmap redo() {
// TODO
return null;
}
}
Thanks again
Here the solution, edit the ArrayClass in this way:
public class ArrayClass {
ArrayList<Bitmap> undoArray =new ArrayList<Bitmap>();
private int _size;
private Bitmap _mBitmap;
public void incrementArray(Bitmap mBitmap) {
this._mBitmap=mBitmap;
_size=undoArray.size();
// undoArray.add(_size, _mBitmap); replace with:
undoArray.add(_size, Bitmap.createBitmap(_mBitmap));
}
public Bitmap undo() {
// TODO Auto-generated method stub
_ size=undoArray.size();
if (_size>1) {
undoArray.remove(_size-1);
_size=undoArray.size();
_mBitmap = ((Bitmap) undoArray.get(_size-1)).copy(Bitmap.Config.ARGB_8888,true);
}
return _mBitmap;
}
public Bitmap redo() {
// TODO
return null;
}
}