Simple free hand Paint with Color Changes using Color Picker

1.MAIN ACTIVITY 


import com.example.simplepaint.PickerDialog.OnColorChangedListener;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RelativeLayout;

public class MainActivity extends Activity {

private RelativeLayout relativelayout;

// Instance variables
private Paint mPaint, mBitmapPaint;
private MyView mView;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Button ClearPaint, Colorpaint;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

relativelayout = (RelativeLayout) findViewById(R.id.item);


DisplayMetrics metrics = getBaseContext().getResources().getDisplayMetrics();
int w = metrics.widthPixels;
int h = metrics.heightPixels;

System.out.println(" width " + w);
System.out.println(" height " + h);

mView = new MyView(this, w, h);
mView.setDrawingCacheEnabled(true);

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(5);

ClearPaint = (Button) findViewById(R.id.ClearPaint);
ClearPaint.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
mBitmap.eraseColor(Color.TRANSPARENT);
mPath.reset();
mView.invalidate();
}
});

Button Colorpaint = (Button) findViewById(R.id.color);
Colorpaint.setOnClickListener(new OnClickListener() {

public void onClick(View v) {

int _color = R.color.red;
new PickerDialog(v.getContext(),new OnColorChangedListener()  {

         public void colorChanged(int color) {
         mPaint.setColor(color);
         Log.i("TAG", "mpaint one" +mPaint);
          }
      }, mPaint.getColor(), _color).show();
     Log.i("TAG", "mpaint two" +mPaint);
}
});    
relativelayout.addView(mView);
}

/*/// color changed function, getting value from ColorPickerDialog ///
public void colorChanged(int color) {
mPaint.setColor(color);
} */

// //////////******************* Pinting view *******************///////////////////

public class MyView extends View {

public MyView(Context c, int w, int h) {
super(c);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
// Bitmap mBitmap =
// Bitmap.createScaledBitmap(originalBitmap,200,200,true);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint
.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
}

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

@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}

// //////************touching evants for painting**************///////
private float mX, mY;
private static final float TOUCH_TOLERANCE = 5;

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

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

private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
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;
} // end of touch events for image
}// end MyView
}

2.MAIN.XML


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:id="@+id/item"
        android:layout_below="@+id/linear"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:src="@drawable/cat" />

    </RelativeLayout>

    <LinearLayout
        android:id="@+id/linear"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/color"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="ChangeColor" />

        <Button
            android:id="@+id/ClearPaint"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="ClearPaint" />
    </LinearLayout>

</RelativeLayout>


 3. COLORPICKERVIEW ACTIVITY

import android.app.Dialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;

public class PickerDialog extends Dialog {

    public interface OnColorChangedListener {
        void colorChanged(int color);
    }

    private OnColorChangedListener mListener;
    private int mInitialColor, mDefaultColor;
    //private String mKey;

private static class ColorPickerView extends View {

private Paint mPaint;
private float mCurrentHue = 0;
private int mCurrentX = 0, mCurrentY = 0;
private int mCurrentColor, mDefaultColor;
private final int[] mHueBarColors = new int[258];
private int[] mMainColors = new int[65536];
private OnColorChangedListener mListener;

ColorPickerView(Context c, OnColorChangedListener l, int color, int defaultColor)  {
super(c);
mListener = l;
mDefaultColor = defaultColor;

// Get the current hue from the current color and update the main color field
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
mCurrentHue = hsv[0];
updateMainColors();

mCurrentColor = color;

// Initialize the colors of the hue slider bar
int index = 0;
for (float i=0; i<256; i += 256/42) // Red (#f00) to pink (#f0f)
{
mHueBarColors[index] = Color.rgb(255, 0, (int) i);
index++;
}
for (float i=0; i<256; i += 256/42) // Pink (#f0f) to blue (#00f)
{
mHueBarColors[index] = Color.rgb(255-(int) i, 0, 255);
index++;
}
for (float i=0; i<256; i += 256/42) // Blue (#00f) to light blue (#0ff)
{
mHueBarColors[index] = Color.rgb(0, (int) i, 255);
index++;
}
for (float i=0; i<256; i += 256/42) // Light blue (#0ff) to green (#0f0)
{
mHueBarColors[index] = Color.rgb(0, 255, 255-(int) i);
index++;
}
for (float i=0; i<256; i += 256/42) // Green (#0f0) to yellow (#ff0)
{
mHueBarColors[index] = Color.rgb((int) i, 255, 0);
index++;
}
for (float i=0; i<256; i += 256/42) // Yellow (#ff0) to red (#f00)
{
mHueBarColors[index] = Color.rgb(255, 255-(int) i, 0);
index++;
}

// Initializes the Paint that will draw the View
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setTextSize(12);
}

// Get the current selected color from the hue bar
private int getCurrentMainColor()
{
int translatedHue = 255-(int)(mCurrentHue*255/360);
int index = 0;
for (float i=0; i<256; i += 256/42)
{
if (index == translatedHue)
return Color.rgb(255, 0, (int) i);
index++;
}
for (float i=0; i<256; i += 256/42)
{
if (index == translatedHue)
return Color.rgb(255-(int) i, 0, 255);
index++;
}
for (float i=0; i<256; i += 256/42)
{
if (index == translatedHue)
return Color.rgb(0, (int) i, 255);
index++;
}
for (float i=0; i<256; i += 256/42)
{
if (index == translatedHue)
return Color.rgb(0, 255, 255-(int) i);
index++;
}
for (float i=0; i<256; i += 256/42)
{
if (index == translatedHue)
return Color.rgb((int) i, 255, 0);
index++;
}
for (float i=0; i<256; i += 256/42)
{
if (index == translatedHue)
return Color.rgb(255, 255-(int) i, 0);
index++;
}
return Color.RED;
}

// Update the main field colors depending on the current selected hue
private void updateMainColors()
{
int mainColor = getCurrentMainColor();
int index = 0;
int[] topColors = new int[256];
for (int y=0; y<256; y++)
{
for (int x=0; x<256; x++)
{
if (y == 0)
{
mMainColors[index] = Color.rgb(255-(255-Color.red(mainColor))*x/255, 255-(255-Color.green(mainColor))*x/255, 255-(255-Color.blue(mainColor))*x/255);
topColors[x] = mMainColors[index];
}
else
mMainColors[index] = Color.rgb((255-y)*Color.red(topColors[x])/255, (255-y)*Color.green(topColors[x])/255, (255-y)*Color.blue(topColors[x])/255);
index++;
}
}
}

@Override
protected void onDraw(Canvas canvas) {
int translatedHue = 255-(int)(mCurrentHue*255/360);
// Display all the colors of the hue bar with lines
for (int x=0; x<256; x++)
{
// If this is not the current selected hue, display the actual color
if (translatedHue != x)
{
mPaint.setColor(mHueBarColors[x]);
mPaint.setStrokeWidth(1);
}
else // else display a slightly larger black line
{
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(3);
}
canvas.drawLine(x+10, 0, x+10, 40, mPaint);
}

// Display the main field colors using LinearGradient
for (int x=0; x<256; x++)
{
int[] colors = new int[2];
colors[0] = mMainColors[x];
colors[1] = Color.BLACK;
Shader shader = new LinearGradient(0, 50, 0, 306, colors, null, Shader.TileMode.REPEAT);
mPaint.setShader(shader);
canvas.drawLine(x+10, 50, x+10, 306, mPaint);
}
mPaint.setShader(null);

// Display the circle around the currently selected color in the main field
if (mCurrentX != 0 && mCurrentY != 0)
{
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLACK);
canvas.drawCircle(mCurrentX, mCurrentY, 10, mPaint);
}

// Draw a 'button' with the currently selected color
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mCurrentColor);
canvas.drawRect(10, 316, 138, 356, mPaint);

// Set the text color according to the brightness of the color
if (Color.red(mCurrentColor)+Color.green(mCurrentColor)+Color.blue(mCurrentColor) < 384)
mPaint.setColor(Color.WHITE);
else
mPaint.setColor(Color.BLACK);
//canvas.drawText(getResources().getString(R.string.hello), 74, 340, mPaint);

// Draw a 'button' with the default color
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mDefaultColor);
canvas.drawRect(138, 316, 266, 356, mPaint);

// Set the text color according to the brightness of the color
if (Color.red(mDefaultColor)+Color.green(mDefaultColor)+Color.blue(mDefaultColor) < 384)
mPaint.setColor(Color.WHITE);
else
mPaint.setColor(Color.BLACK);
   //canvas.drawText(getResources().getString(R.string.hello), 202, 340, mPaint);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(276, 366);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN) return true;
float x = event.getX();
float y = event.getY();

// If the touch event is located in the hue bar
if (x > 10 && x < 266 && y > 0 && y < 40)
{
// Update the main field colors
mCurrentHue = (255-x)*360/255;
updateMainColors();

// Update the current selected color
int transX = mCurrentX-10;
int transY = mCurrentY-60;
int index = 256*(transY-1)+transX;
if (index > 0 && index < mMainColors.length)
mCurrentColor = mMainColors[256*(transY-1)+transX];

// Force the redraw of the dialog
invalidate();
}
// If the touch event is located in the main field
if (x > 10 && x < 266 && y > 50 && y < 306)
{
mCurrentX = (int) x;
mCurrentY = (int) y;
int transX = mCurrentX-10;
int transY = mCurrentY-60;
int index = 256*(transY-1)+transX;
if (index > 0 && index < mMainColors.length)
{
// Update the current color
mCurrentColor = mMainColors[index];
// Force the redraw of the dialog
invalidate();
}
}
// If the touch event is located in the left button, notify the listener with the current color
if (x > 10 && x < 138 && y > 316 && y < 356)
mListener.colorChanged( mCurrentColor);

// If the touch event is located in the right button, notify the listener with the default color
if (x > 138 && x < 266 && y > 316 && y < 356)
mListener.colorChanged( mDefaultColor);

return true;
}
}

    public PickerDialog(Context context, OnColorChangedListener listener, int initialColor, int defaultColor) {
        super(context);

        mListener = listener;
      //  mKey = key;
        mInitialColor = initialColor;
        mDefaultColor = defaultColor;
    }
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     
        OnColorChangedListener _ChangedListener = new OnColorChangedListener() {
            public void colorChanged( int color) {
                mListener.colorChanged(color);
                dismiss();
            }
        };

        setContentView(new ColorPickerView(getContext(), _ChangedListener, mInitialColor, mDefaultColor));
        setTitle("Color Picker");
    }
}

//Add this xml to  res/values 

4. COLOR.XML


<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="red">#ffff0000</color>
</resources>


1). we want choose any color use ing color picker  





10 comments:

Anonymous said...

Hello dude

I go through your drawing code and its awesome, But in your code what i realize is that user can draw with one finger only, if he try to use multiple finger to draw it don't allow the user to draw on it. I try implementing multiple touch event on ur code but not succeeded. If u know about this issue can u please write a code for us.

Unknown said...

hello buddy..
thanks for your wonderful example.
but there is a question that while multiple no. of drawings last one still stays on the screen until the screen is touched again .
can you please tell me why..
and really thanx for the code

Unknown said...

hey thanx for the wonderful example..

Anonymous said...

hey thanx buddy for the wonderful code..

Unknown said...

I go through your drawing code and its awesome
thanx a lot buddy

Anonymous said...

I go through your drawing code and its awesome
thanx a lot buddy

NagarjunaReddy said...

Thank for complement........

Unknown said...

Hey, its a very nice example and useful to me,
but i want to add some functionality to it,
what i wanted is after drawing something i wanted it to save as image in drawable folder, it will be very useful for me if you help me for this, and if you have any ready made source code for this then please send it to me on : suthar.rajesh2687@gmail.com

Thank you

Unknown said...

Hey, its a very nice example and useful to me,
but i want to add some functionality to it,
what i wanted is after drawing something i wanted it to save as image in drawable folder, it will be very useful for me if you help me for this, and if you have any ready made source code for this then please send it to me on : suthar.rajesh2687@gmail.com

Thank you

amarnath said...

Hey, its a very nice example and useful to me,but its not copatable for all versions.above version 4.x imageview showing black space.please help me. thank you

Select DateRange UsingRangePicker.

  /* * This Method is for select range from picker. * */ private fun selectDateRangeUsingRangePicker () { pageNumber = 1 val displ...