Drawing on Canvas

Illya Rodin

 

Use cases:

  • Custom views
  • Custom drawables
  • Drawing (as feature)
  • 2D Games
  • e.t.c

View

class CustomView extends View {

    public CustomView (Context context) {
      super(context);
      //TODO Initializing painters, constants and support elements
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
      //TODO drawing something
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     //TODO Get measures
    }

    //----- AND/OR ----//

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    //TODO Initialize objects in according to size
    }
    
  }

Drawable

class CustomDrawable extends Drawable{

    public CustomDrawable () {
      //TODO Initializing painters, constants and support elements
    }
    
    @Override
    public void draw (Canvas canvas)
      //TODO drawing something
    }


    @Override
     protected void onBoundsChange(Rect bounds) {
       //TODO Initialize objects in according to bounds
    }
    
  }

Bitmap

  Bitmap bitmap= Bitmap.createBitmap(...); //or copy
  Canvas canvas = new Canvas(bitmap);
  //TODO Drawing something

Surface/TextureView

void drawMethod(){
   
   while (mRunning && !Thread.interrupted()) {
      final Canvas canvas = mTextureView.lockCanvas(null);
      //TODO Drawing something
      mTextureView.unlockCanvasAndPost(canvas);
   }

}

Paint

"The Paint class holds the style and color information about how to draw geometries, text and bitmaps."

        private Paint mPaint;
        private RectF mRectForOval;
        private Rect mRect;
        private float[] mPoints;

        public DrawView(Context context) {
            super(context);
            mPaint = new Paint();
            mPaint.setColor(Color.CYAN);
            mPaint.setStrokeWidth(10.0f);
            mRectForOval = new RectF(200,300,400,450);
            mPoints = new float[]{300,500,600,800,300,4800,500, 650};
            mRect = new Rect(200, 150, 400, 200);

       
        }

        @Override
        protected void onDraw(Canvas canvas) {

            canvas.drawColor(Color.WHITE);

            canvas.drawPoint(50, 50, mPaint);

            canvas.drawLine(100, 100, 500, 50, mPaint);

            canvas.drawCircle(100, 200, 50, mPaint);

            canvas.drawRect(mRect, mPaint);

            canvas.drawArc(mRectForOval, 0, 270, true, mPaint);

            canvas.drawLines(mPoints, mPaint);

            mRect.offset(250, 0);
            mPaint.setStyle(Paint.Style.STROKE);
            canvas.drawRect(mRect, mPaint);


            mRect.offset(0, 200);
            mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            canvas.drawRect(mRect, mPaint);
        }
        private Paint mPaint;
        private RectF mRectForOval;
        private Path mPath;
        private Point mPointA;
        private Point mPointB;
        private Point mPointC;

        public DrawView(Context context) {
            super(context);
            mPaint = new Paint();
            mPaint.setColor(Color.CYAN);
            mPaint.setStrokeWidth(10.0f);
            mPaint.setStyle(Paint.Style.STROKE);
            mRectForOval = new RectF(200,300,400,450);
            mPointA = new Point(50,500);
            mPointB = new Point(150,900);
            mPointC = new Point(250,300);
            mPath = new Path();

        }



        @Override
        protected void onDraw(Canvas canvas) {

            canvas.drawColor(Color.WHITE);

            mPath.reset();

            mPath.moveTo(100, 100);
            mPath.lineTo(150, 200);
            mPath.lineTo(50, 200);

            mPath.moveTo(250, 100);
            mPath.rLineTo(100, 50);
            mPath.rLineTo(-100, 0);

            mPath.close();

            mPath.addRect(mRectForOval, Path.Direction.CW);
            mPath.addCircle(450, 150, 25, Path.Direction.CW);

            canvas.drawPath(mPath, mPaint);

            mPath.reset();
            mPath.moveTo(100, 500);
            mPath.quadTo(mPointA.x, mPointB.y, 600, 300);
            canvas.drawPath(mPath, mPaint);

            mPath.reset();
            mPath.moveTo(100, 800);
            mPath.cubicTo(mPointB.x, mPointB.y ,mPointC.x, mPointC.y,600, 1000);
            canvas.drawPath(mPath, mPaint);
        }

    }


        @Override
        protected void onDraw(Canvas canvas) {

            canvas.drawColor(Color.WHITE);

            mPath.reset();

            mPath.addRect(50, 50, 200, 100, Path.Direction.CW);
            mPath.addRect(100, 0, 150, 150, Path.Direction.CW);
            mPaint.setColor(Color.CYAN);
            canvas.drawPath(mPath, mPaint);
            mMatrix.reset();

            mMatrix.setTranslate(200, 0);

            mPath.transform(mMatrix);

            mPaint.setColor(Color.RED);
            canvas.drawPath(mPath, mPaint);

            mMatrix.reset();

            mMatrix.setScale(1.2f, 1.2f);

            mMatrix.preTranslate(150, 0);

            mPath.transform(mMatrix);
            mPaint.setColor(Color.GREEN);
            canvas.drawPath(mPath, mPaint);

            mMatrix.reset();

            mMatrix.setRotate(45.0f);

           mMatrix.postTranslate(0, -200);

            mPath.transform(mMatrix);
            mPaint.setColor(Color.BLACK);
            canvas.drawPath(mPath, mPaint);
        }

 
 {
        super.onDraw(canvas);
        mDial.draw(canvas);

        canvas.save();
        canvas.rotate(mHourAng, x, y);
        mHourHand.draw(canvas);
        canvas.restore();

        canvas.save();
        canvas.rotate(mMinutesAng, x, y);
        mMinuteHand.draw(canvas);
        canvas.restore();

        canvas.save();
        canvas.rotate(mSecondAng, x, y);
        mSecondHand.draw(canvas);
        canvas.restore();
}
@Override
 protected void onDraw(Canvas canvas) {

   canvas.drawColor(Color.WHITE);

   canvas.drawRect(mRect, mPaint);

   canvas.translate(250, 0);


   canvas.clipRect(mRect);
   canvas.translate(100, 100);
   canvas.clipRect(mRect, Region.Op.UNION);
   canvas.translate(-50, -50);
   canvas.drawRect(mRect, mPaint);
   //canvas.quickReject(350,100,400,150, Canvas.EdgeType.AA);


   canvas.restore();
   mRect.offsetTo(250,50);
   mPaint.setColor(Color.RED);
   mPaint.setStyle(Paint.Style.STROKE);
   canvas.drawRect(mRect, mPaint);
 }

Text



        private TextPaint mTextPaint;
        private StaticLayout mStaticTextLayout;
        private Rect mTextBounds;

        public DrawView(Context context) {
            super(context);
            mTextPaint = new TextPaint();
            mTextPaint.setColor(Color.BLACK);
            mTextPaint.setTextSize(36);
            mTextBounds = new Rect();
            mTextPaint.getTextBounds(TEXT, 0, TEXT.length(), 
                  mTextBounds);
            mStaticTextLayout = new StaticLayout(TEXT, mTextPaint, 
                  720,
                    Layout.Alignment.ALIGN_CENTER, 1, 1, true);

        }



        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawColor(Color.WHITE);
            canvas.save();
            int numberOfTextLines = mStaticTextLayout.getLineCount();
            float textYCoordinate = mTextBounds.exactCenterY() +
                    ((numberOfTextLines * mTextBounds.height()) / 2);
            float textXCoordinate = mTextBounds.left;
            canvas.translate(textXCoordinate, textYCoordinate);
            mStaticTextLayout.draw(canvas);
            canvas.restore();
        }
        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawColor(Color.WHITE);
            mPath.reset();
            mPath.addCircle(200, 200, 100, Path.Direction.CW);
            mTextPaint.setColor(Color.BLACK);
            canvas.drawTextOnPath(TEXT, mPath, 0, 0, mTextPaint);

            mPath.reset();
            mPath.addCircle(500, 200, 100, Path.Direction.CCW);


            mTextPaint.setStyle(Paint.Style.FILL);
            mTextPaint.setColor(Color.BLUE);
            canvas.drawTextOnPath(TEXT, mPath, 0, 0, mTextPaint);
            mTextPaint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(mPath, mTextPaint);


            mPath.offset(-300, 250);
            mTextPaint.setStyle(Paint.Style.FILL);
            mTextPaint.setColor(Color.GREEN);
            canvas.drawTextOnPath(TEXT, mPath, 100, 0, mTextPaint);
            mTextPaint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(mPath, mTextPaint);


            mPath.offset(300, 0);
            mTextPaint.setStyle(Paint.Style.FILL);
            mTextPaint.setColor(Color.RED);
            canvas.drawTextOnPath(TEXT, mPath, 0, 30, mTextPaint);
            mTextPaint.setStyle(Paint.Style.STROKE);

            canvas.drawPath(mPath, mTextPaint);

            mPath.reset();
            mPath.moveTo(50,750);
            mPath.cubicTo(50, 750, 500, 1000, 700, 750);
            mTextPaint.setStyle(Paint.Style.FILL);
            mTextPaint.setColor(Color.MAGENTA);
            canvas.drawTextOnPath(TEXT, mPath, 0, 0, mTextPaint);
            mTextPaint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(mPath, mTextPaint);

        }

ColorFilter

ColorMatrix

[ a, b, c, d, e,
 f, g, h, i, j,
 k, l, m, n, o, 
p, q, r, s, t ]
Apply to [R, G, B, A], after clamping:

R' = a*R + b*G + c*B + d*A + e;

G' = f*R + g*G + h*B + i*A + j;

B' = k*R + l*G + m*B + n*A + o;

A' = p*R + q*G + r*B + s*A + t;

{
  Paint paint = new Paint();
  ColorMatrix colorMatrix = new ColorMatrix(new float[]{
    //  [ 1, 0, 0, 0, 0,
    //    0, 1, 0, 0, 0,
    //    0, 0, 1, 0, 0,
    //    0, 0, 0, 1, 0 ]
  });
  colorMatrix 
  paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix );
  canvas.drawBitmap(originalBitmap, 0, 0, paint);
}

//Grayscale
[0.33,0.33,0.33,0,0
 0.59,0.59,0.59,0,0
 0.11,0.11,0.11,0,0
 0,0,0,1 0 ]

//invert
[-1,0,0,0,0
 0,-1,0,0,0
 0,0.-1,0,0,
 0,0,0,1 0 ]

//Sepia Color
[0.393,0.349,0.272,0,0
 0.769,0.686,0.534,0,0
 0.189,0.168,0.131,0,0
 0,0,0,1 0 ]


/** Create a colorfilter that multiplies the RGB channels by one color, 
    and then adds a second color. */
// LightingColorFilter(int mul, int add)
//
//R' = R * mul.R + add.R
//G' = G * mul.G + add.G
//B' = B * mul.B + add.B

Porter-Duff Modes

//DST_IN
Bitmap bitmap = Bitmap.createBitmap(
    original.getWidth(), original.getHeight(), 
    Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(original, 0, 0, null);


Paint maskPaint = new Paint();
maskPaint.setXfermode(
    new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(mask, 0, 0, maskPaint);

SRC

DST

PathEffect

 public DrawView(Context context) {
            super(context);
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(6);
            mPath = makeFollowPath();
            mEffects = new PathEffect[6];
            /*
             null; 
             e[1] = new CornerPathEffect(10);
             e[2] = new DashPathEffect(new float[] {10, 5, 5, 5}, phase);
             e[3] = new PathDashPathEffect(makePathDash(), 12, phase,
                    PathDashPathEffect.Style.ROTATE);
             e[4] = new ComposePathEffect(e[2], e[1]);
             e[5] = new ComposePathEffect(e[3], e[1]); 
            */
        }
 
            };
        }

         @Override protected void onDraw(Canvas canvas) {
            canvas.drawColor(Color.WHITE);
            RectF bounds = new RectF();
            mPath.computeBounds(bounds, false);
            canvas.translate(10 - bounds.left, 10 - bounds.top);
            makeEffects(mEffects, mPhase);
            mPhase += 1;
            invalidate();
            for (int i = 0; i < mEffects.length; i++) {
                mPaint.setPathEffect(mEffects[i]);
                mPaint.setColor(mColors[i]);
                canvas.drawPath(mPath, mPaint);
                canvas.translate(0, 50);
            }
        }

Q&A

Thank you for attention!

rodin.illya@gmail.com

https://ua.linkedin.com/in/illya-rodin-54a37419

Made with Slides.com