I'm doing a simple drawing app, and so far I've managed to control the opacity and size of the brush.
Now I'm trying to set some kind of hardness, like in Photoshop, but I looked at the documentation and Paint doesn't seem to have something like that.
In case it's relevant, I'm following this
tutorial.
public class DrawingView extends View {
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
//brush sizes
private float brushSize, lastBrushSize;
//erase flag
private boolean erase=false;
public DrawingView(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
}
//setup drawing
private void setupDrawing(){
//prepare for drawing and setup paint stroke properties
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
//size assigned to view
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
//draw the view - will be called after touch event
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
//register user touches as drawing action
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
//respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
//redraw
invalidate();
return true;
}
//update color
public void setColor(String newColor){
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
//set brush size
public void setBrushSize(float newSize){
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize=pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
//get and set last brush size
public void setLastBrushSize(float lastSize){
lastBrushSize=lastSize;
}
public float getLastBrushSize(){
return lastBrushSize;
}
public void setErase(boolean isErase){
erase=isErase;
if(erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
else drawPaint.setXfermode(null);
}
//start new drawing
public void startNew(){
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
}
So, how can I set a Paint's hardness?
Thanks a lot!
Found it!
private Paint drawPaint= new Paint();
drawPaint.setMaskFilter(new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL));
Where the first parameter of BlurMaskFilter is the radius of the blur :)
Related
I have a custom ImageView where user can draw using some colors.
I load image from server then allow user to draw on top of it.
When i load the next image , i want the previously drawn colors to be gone before user can draw again.
I tried many thing from internet but not able to achieve the same.
below is code for custom ImageView:
public class DrawingView extends androidx.appcompat.widget.AppCompatImageView {
//drawing path
static Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
static int paintColor = 0xFFFFFFFF;
//stroke width
private float STROKE_WIDTH = 5f;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
//eraser mode
private boolean erase = false;
private boolean cc = false;
//constructor
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
setErase(erase);
}
private void setupDrawing() {
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(STROKE_WIDTH);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
//*************************************** View assigned size ****************************************************
#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);
}
public void setPaintColor(int paintColor) {
this.paintColor = paintColor;
setupDrawing();
}
public void setImageOnImageview(Bitmap canvasBitmap) {
this.canvasBitmap = canvasBitmap;
}
#Override
public void setImageResource(int resId) {
super.setImageResource(resId);
}
public void setErase(boolean isErase) {
erase = isErase;
drawPaint = new Paint();
if (erase) {
setupDrawing();
int srcColor = getResources().getColor(R.color.white);
PorterDuff.Mode mode = PorterDuff.Mode.CLEAR;
PorterDuffColorFilter porterDuffColorFilter = new PorterDuffColorFilter(srcColor, mode);
drawPaint.setColorFilter(porterDuffColorFilter);
drawPaint.setColor(srcColor);
drawPaint.setXfermode(new PorterDuffXfermode(mode));
} else {
setupDrawing();
}
}
//************************************ draw view *************************************************************
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (cc) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
cc = false;
} else {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
}
public void clearCanvas() {
setupDrawing();
setErase(false);
cc = true;
invalidate();
}
//*************************** respond to touch interaction **************************************************
#Override
public boolean onTouchEvent(MotionEvent event) {
canvasPaint.setColor(paintColor);
float touchX = event.getX();
float touchY = event.getY();
//respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
//redraw
invalidate();
return true;
}
//*********************************** return current alpha ***********************************************
public int getPaintAlpha() {
return Math.round((float) STROKE_WIDTH / 255 * 100);
}
//************************************** set alpha ******************************************************
public void setPaintAlpha(int newAlpha) {
STROKE_WIDTH = Math.round((float) newAlpha / 100 * 255);
drawPaint.setStrokeWidth(newAlpha);
}
}
I tried many solutions like clear path or clear paint.
Could any please help me with this ?
I assume you want to remove the drawn color on first image upon loading the new image
I think you can draw the color over canvas
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
or reset the path itself
Path.reset();
I made canvas view transparent and code is following;
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.OVERLAY);
}
The following code for eraser and its not working
if (this.mode == Mode.ERASER) {
// Eraser
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setARGB(0, 255, 0, 0);
paint.setColor(eraserColor);
paint.setStrokeWidth(DrawingActivity.eraserSize);
}
here is full code. Try it.
public class TryDraw extends View {
private Path drawPath;
private Paint drawPaint;
private Paint canvasPaint;
private Canvas drawCanvas;
public static Bitmap canvasBitmap;
private boolean erase=false;
float touchX;
float touchY;
float strokeWidth;
public TryDraw(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setupDrawing(){
strokeWidth=getResources().getDimension(R.dimen.medium_brush);
drawPath = new CustomPath();
drawPaint = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG);
drawPaint.setColor(Color.RED);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(strokeWidth);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
#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);
drawCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.OVERLAY);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(canvasBitmap,0,0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(event.getX(),event.getY());
touchX = event.getX();
touchY = event.getY();
drawPath.lineTo(touchX,touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(event.getX(), event.getY());
touchX = event.getX();
touchY = event.getY();
break;
case MotionEvent.ACTION_UP:
drawCanvas.drawPath(drawPath, drawPaint);
drawPath=new Path();
break;
default:
return false;
}
invalidate();
return true;
}
public void setColor(int newColor){
invalidate();
drawPaint.setColor(newColor);
}
public void setErase(boolean isErase){
if(!isErase) {
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
drawPaint.setStrokeWidth(45.0f);
erase=true;
}else {
drawPaint.setXfermode(null);
drawPaint.setStrokeWidth(strokeWidth);
erase=false;
}
}
public void startNew(){
mDrawingList.clear();
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
}
I have created my own custom edittext class so that i can draw in it and also add text...
Everything is working fine regarding the drawing part but when i type no text is visible,,,,,,
How can i fix this
my customview
public class MyCustomView extends View
{
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
private float brushSize ;
private boolean erase=false;
public MyCustomView(Context c, AttributeSet attr){
super(c,attr);
setupdraw();
}
public MyEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void setupdraw()
{
drawPath = new Path();
drawPaint = new Paint();
brushSize = 15;
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//view given size
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) {
//draw view
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//detect user touch
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;
}
public void setColor(String newColor){
//set color
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
public void setBrushSize(float newSize){
//update size
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize=pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
}
}
my main activity
public class MainActivity extends Activity
{
private MyCustomView myView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MyCustomView myView = (MyCustomView) findViewById(R.id.myCustomView);
}
}
main.xml
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="10dp"
android:background="#D06C65">
<com.mycompany.myapp.MyCustomView
android:id="#+id/myCustomView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#EAEAEA"/>
<Button
android:layout_height="wrap_content"
android:text="T"
android:layout_width="wrap_content"
android:layout_gravity="bottom|center"/>
</FrameLayout>
You should call super.onDraw(canvas) after drawing your background stuff. The TextView drawing methods will subsequently handle all the drawing text features (you don't want to recode that).
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
super.onDraw(canvas);
}
I'm a newbie for android development. I need some help with loading image from SDCard to a drawingView. What I'm trying to achieve here is after loading the image i want to modify the image and save.
So my primary task is to load the image to DrawingView.
Appreciate your help on this.
Thank you.
please use something like this ..this worked for me
YourDrawingView jpgView = (YourDrawingView)findViewById(R.id.imageView);
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/sample-1.jpg");
jpgView.setImageBitmap(bitmap);
setContentView(R.layout.main);
and here is my DrawingView
public class DrawingView extends ImageView {
private boolean erase = false;
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
private float brushSize, lastBrushSize;
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setUpDrawing();
}
public DrawingView(Context context) {
super(context);
}
private void setUpDrawing() {
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(20);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
drawPaint.setStrokeWidth(brushSize);
}
public void setErase(boolean isErase) {
//set erase true or false
erase = isErase;
if (erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
else drawPaint.setXfermode(null);
}
public void setBrushSize(float newSize) {
//update size
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize = pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
public void setLastBrushSize(float lastSize) {
lastBrushSize = lastSize;
}
public float getLastBrushSize() {
return lastBrushSize;
}
#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) {
super.onDraw(canvas);
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
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:
break;
}
invalidate();
return true;
}
public void setColor(String color) {
invalidate();
paintColor = Color.parseColor(color);
drawPaint.setColor(paintColor);
}
public void startNew() {
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
}
Not sure what is DrawingView, or do you mean ImageView?
File imageFile = new File("/sdcard/my_photo_1.jpg");
Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
imageView.setImageBitmap(bitmap);
You can use canvas to draw image, Below is code :
public class Keypaint extends View {
Paint p;
Bitmap bitmap = null;
public Keypaint(Context context) {
super(context);
File imageFile = new File("/sdcard/my_photo_1.jpg");
bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
p=new Paint();
p.setColor(Color.RED);
canvas.drawBitmap(bitmap, 0, 0, p);
}
}
I am trying to make undo,redo options in custom drawing view app. But it is not working as i want.
I am not good in english. Through picture, let me try to show the working of undo , redo functions. Hope so, this picture will explain my problem.
i want to remove first line on first undo click and second line on second undo click and so on... similarly on redo click draw last line on first click, second last on second click and so on..
Here is my custom view class.
public class DrawingView extends View{
ArrayList<Path> undoPath = new ArrayList<Path>();
ArrayList<Path> paths = new ArrayList<Path>();
private static int pathSize =0;
//draw path
private Path drawPath;
//drawing and canvas point
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor=0xFF660000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
private float brushSize, lastBrushSize;
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
public void setPattern(String newPattern){
invalidate();
int patternID = getResources().getIdentifier(newPattern, "drawable", "com.faisalahsan.paintingapp");
Bitmap patternBMP = BitmapFactory.decodeResource(getResources(), patternID);
BitmapShader patternBMPShader = new BitmapShader(patternBMP, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
drawPaint.setColor(0xFFFFFFFF);
drawPaint.setShader(patternBMPShader);
}
private void setupDrawing(){
//get drawing area setup for interaction
drawPath = new Path();
drawPaint= new Paint();
paths.add(drawPath);
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onDraw(Canvas canvas) {
for(Path p: paths){
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(p, drawPaint);
}
}
#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);
}
public void onClickUndo () {
if (paths.size()>0) {
undoPath.add(paths.remove(paths.size()-1));
invalidate();
}
}
public void onClickRedo (){
if (undoPath.size()>0) {
paths.add(undoPath.remove(undoPath.size()-1));
invalidate();
}
}
#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();
drawPath = new Path();
paths.add(drawPath);
break;
default:
return false;
}
invalidate();
return true;
}
}
You are not "redrawing" on the canvas when "undo" removes the action from the ArrayList "paths" - in other words, taking it out of the list does not change the image. You have to redraw what was on the canvas before it was drawn in order to "undo" the action.
Save the state of the canvas when "onDraw" starts and then redraw that canvas when undo is called. You need to keep a synchronized stack of canvas states in order to perform a series of "undo" and "redo" calls.