Skip to content

Instantly share code, notes, and snippets.

@CallumCoombes
Created June 26, 2018 09:10
Show Gist options
  • Save CallumCoombes/aef8f8dbd8aa8a8c69b17b33e1618103 to your computer and use it in GitHub Desktop.
Save CallumCoombes/aef8f8dbd8aa8a8c69b17b33e1618103 to your computer and use it in GitHub Desktop.
ImageView to allow users to paint on image with their finger and add a cross image on a painted area.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Toast;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import static android.graphics.Bitmap.Config.ARGB_8888;
public class FingerPaintImageView extends android.support.v7.widget.AppCompatImageView {
private final String TAG = getClass().getSimpleName();
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
private boolean placingCross = false;
private Toast warningToast = Toast.makeText(getContext(), "You must select a shaded area", Toast.LENGTH_SHORT);
private final int gridSpaceCount = 20;
private Bitmap imageViewBitmap = this.getImageViewBitmapFromVector(/*this.getDrawable()*/getResources().getDrawable(R.drawable.front_bpi_man));
private boolean crossPlaced = false;
private float crossX;
private float crossY;
public FingerPaintImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//initialise values
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(20);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.ARGB_8888); //changed from w and h
mCanvas = new Canvas(mBitmap);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//get image and scale it
int nh = (int) ( imageViewBitmap.getHeight() * (512.0 / imageViewBitmap.getWidth()) );
imageViewBitmap = Bitmap.createScaledBitmap(imageViewBitmap, 512, nh, true);
//set bitmap as the imageview's bitmap
setImageBitmap(imageViewBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//draw the bitmap on the canvas
canvas.drawBitmap(imageViewBitmap, getMatrix(), null);
//do painting stuff
if (mBitmap != null) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint); //this draws path when held down
if (placingCross && isOnImage(mX, mY)) {
crossPlaced = true;
crossX = mX;
crossY = mY;
}
if (crossPlaced) {
Bitmap crossBitmap = getImageViewBitmapFromVector(getResources().getDrawable(R.drawable.cross_yellow_25px));
int crossXCenter = crossBitmap.getWidth() / 2;
int crossYCenter = crossBitmap.getHeight() / 2;
canvas.drawBitmap(crossBitmap, crossX - crossXCenter, crossY - crossYCenter, null);
}
}
}
//get bitmap from vector drawable
private Bitmap getImageViewBitmapFromVector(Drawable d) {
try {
Bitmap bitmap;
bitmap = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(), ARGB_8888);
Canvas canvas = new Canvas(bitmap);
d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
d.draw(canvas);
return bitmap;
} catch (OutOfMemoryError e) {
// Handle the error
return null;
}
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private boolean isStarted = false;
//handle start touch
private void touch_start(float x, float y) {
mPath.reset();
if (isOnImage(x, y)) {
if (!placingCross) {
mPath.moveTo(x, y);
}
mX = x;
mY = y;
// Log.d(TAG, "touch_start: started on white - mX=" + mX + ", mY=" + mY);
isStarted = true;
}
// Log.d(TAG, "touch_start: not started - mX=" + mX + ", mY=" + mY);
}
//handle moving touch
private void touch_move(float x, float y) {
if (isOnImage(x, y)) {
if (!isStarted) {
touch_start(x, y);
}
// Log.d(TAG, "touch_move: drawn on white - mX=" + mX + ", mY=" + mY);
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
if (!placingCross) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
}
mX = x;
mY = y;
}
} else {
if (isStarted) {
touch_up();
}
}
}
//handle touch stopped
private void touch_up() {
if (isStarted) {
// Log.d(TAG, "touch_up- mX=" + mX + ", mY=" + mY);
isStarted = false;
if (!placingCross) {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint); //this draws the path once it is finished
}
// kill this so we don't double draw
mPath.reset();
}
}
//check if x,y position is on the bitmap image
public boolean isOnImage(float x, float y) {
int pixel = imageViewBitmap.getPixel((int) x, (int) y);
int alphaValue = Color.alpha(pixel);
if (placingCross) {
int paintPixel = mBitmap.getPixel((int) x, (int) y);
//if placing cross, check for selection of a shaded red area
if (Color.red(paintPixel) == 255 & Color.blue(paintPixel) == 0 & Color.green(paintPixel) == 0) {
return true;
} else {
if (warningToast != null) warningToast.cancel();
// warningToast = Toast.makeText(getContext(), "You must select a shaded area", Toast.LENGTH_SHORT);
warningToast.show();
return false;
}
} else if (alphaValue > 0) {
//if normal shading mode, just check not transparent
return true;
} else {
return false;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//CHANGING THIS X Y MEANS THAT WHERE YOU CLICK ISN'T RIGHT, DON'T CHANGE IT HERE!
float x = event.getX();
float y = event.getY();
if (x < imageViewBitmap.getWidth() && x > 0 &&
y < imageViewBitmap.getHeight() && y > 0 &&
x != 0.0 && y != 0.0) {
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;
}
return false;
}
public void clear() {
mBitmap.eraseColor(Color.TRANSPARENT);
invalidate();
System.gc();
crossPlaced = false;
crossX = 0.0f;
crossY = 0.0f;
}
public void setPlacingCross(boolean placingCross) {
this.placingCross = placingCross;
mX = 0;
mY = 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment