anyone knows how to zoom paint view with image correctly?
At following code, I used canvas zoom in order to zoom paint view with image including using setImageMatrix().
But problem arised, that is entire screen became to zoom in/out but not paint view and image only.
So If anyone knows this issue, reply plz.
PaintScreen.java
public class PaintScreen extends Activity implements ColorPickerDialog.OnColorChangedListener{
Context mContext;
private Paint mPaint;
MaskFilter mEmboss;
MaskFilter mBlur;
private ImageView mImageView;
private LinearLayout mPaintBaseLayout;
private FrameLayout mTouchBaseLayout;
private PaintView mPaintView;
private int[] mPixels;
private Bitmap mBitmapImage;
private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
MultiTouchListener multiTouchLitener = new MultiTouchListener(this);
private static final String TAG = "Touch";
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
Matrix savedMatrix2 = new Matrix();
private int WIDTH = 0;
private int HEIGHT = 1;
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int POINT2 = 2;
static final int ZOOM = 3;
int mode = NONE;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
float newDist;
float distanceOffset = 50f;
float minOffset = 50f;
float maxOffset = 10000f;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.paint_mode1_paint);
this.initialize();
this.PaintSet();
}
private void initialize()
{
mPaintBaseLayout = (LinearLayout) findViewById(R.id.paint_paint_base_layout);
mTouchBaseLayout = (FrameLayout) findViewById(R.id.paint_touch_base_layout);
mContext = this;
mPaint = new Paint();
mPaintView = new PaintView(mContext);
mPaintView.setBackgroundColor(Color.TRANSPARENT);
mPaintBaseLayout.addView(mPaintView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
mPaintBaseLayout.setBackgroundColor(Color.TRANSPARENT);
mPaintView.setScaleType(ScaleType.MATRIX);
mPaintView.setMPaint(mPaint);
Intent intent = getIntent();
Bundle itstr = intent.getExtras();
String imagePath = itstr.getString("image_path");
Drawable d = Drawable.createFromPath(imagePath);
mPaintView.setBackgroundDrawable(d);
mPaintView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
dumpEvent(event);
PaintView view = (PaintView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
start.set(event.getX(), event.getY());
savedMatrix.set(matrix);
midPoint(mid, event);
mode = POINT2;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
distanceOffset = minOffset;
break;
case MotionEvent.ACTION_MOVE:
if (mode == POINT2)
{
newDist = spacing(event);
if (newDist - oldDist > 5f
|| newDist - oldDist < -5f) {
mode = ZOOM;
} else {
start.set(event.getX(), event.getY());
mode = DRAG;
}
} else
if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
}
else if (mode == ZOOM) {
newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
} else {
view.onTouchEvent(event);
}
break;
}
matrixTurning(matrix, view);
view.setImageMatrix(matrix);
view.cMatrix(matrix);
return true;
}
});
}
/** Show an event in the LogCat view, for debugging */
private static void dumpEvent(MotionEvent event) {
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",
"POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
sb.append("(pid ").append(
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++) {
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
Log.d(TAG, sb.toString());
}
/** Determine the space between the first two fingers */
private static float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private static void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
private void matrixTurning(Matrix matrix, ImageView view){
float[] value = new float[9];
matrix.getValues(value);
float[] savedValue = new float[9];
savedMatrix2.getValues(savedValue);
// view size
int width = view.getWidth();
int height = view.getHeight();
//image size
Drawable d = view.getDrawable();
if(d == null) return;
int imageWidth = d.getIntrinsicWidth();
int imageHeight = d.getIntrinsicHeight();
int scaleWidth = (int)(imageWidth*value[0]);
int scaleHeight = (int)(imageHeight*value[0]);
if(value[2] < width - scaleWidth) value[2] = width - scaleWidth;
if(value[5] < height - scaleHeight) value[5] = height - scaleHeight;
if(value[2] > 0) value[2] = 0;
if(value[5] > 0) value[5] = 0;
if(value[0] > 10 || value[4] > 10){
value[0] = savedValue[0];
value[4] = savedValue[4];
value[2] = savedValue[2];
value[5] = savedValue[5];
}
if(imageWidth > width || imageHeight > height){
if(scaleWidth < width && scaleHeight < height){
int target = WIDTH;
if(imageWidth < imageHeight) target = HEIGHT;
if(target == WIDTH) value[0] = value[4] = (float)width/imageWidth;
if(target == HEIGHT) value[0] = value[4] = (float)height/imageHeight;
scaleWidth = (int)(imageWidth*value[0]);
scaleHeight = (int)(imageHeight*value[4]);
if(scaleWidth == width) value[0] = value[4] = (float)width/imageWidth;
if(scaleHeight == height) value[0] = value[4] = (float)height/imageHeight;
}
}else{
if(value[0] < 1) value[0] = 1;
if(value[4] < 1) value[4] = 1;
}
scaleWidth = (int)(imageWidth*value[0]);
scaleHeight = (int)(imageHeight*value[4]);
if(scaleWidth < width){
value[2] = (float)width/2-(float)scaleWidth/2;
}
if(scaleHeight < height){
value[5] = (float)height/2-(float)scaleHeight/2;
}
matrix.setValues(value);
savedMatrix2.set(matrix);
}
public void PaintSet(){
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(24);
getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(24, BlurMaskFilter.Blur.NORMAL);
}
public void colorChanged(int color) {
mPaint.setColor(color);
}
}
PaintView.java
public class PaintView extends ImageView {
private Context mContext;
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private Bitmap testBitmap;
private Canvas mCanvas;
private Canvas tCanvas;
private Path mPath;
private Paint mBitmapPaint;
// onDraw
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
// onTouch
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
public PaintView(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
mContext = context;
mBitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
//mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
//canvas.drawColor(0xFFAAAAAA);
super.onDraw(canvas);
mCanvas = canvas;
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
public void setMPaint(Paint paint) {
mPaint = paint;
}
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, 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();
Log.d("PaintView", "ev ->" + event.getAction());
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;
}
public void cMatrix(Matrix matrix) {
mCanvas.setMatrix(matrix);
}
}
#Override
protected void onDraw(Canvas canvas) {
//canvas.drawColor(0xFFAAAAAA);
super.onDraw(canvas);
mCanvas = canvas;
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
In this method you write, mCanvas = canvas; instead of this write, canvas = mCanvas.
Hello try with below code for paint and capture new bitmap with pain image.first zoom in/out image and on button click draw paint.then click on done button for save your final merge bitmap.Hop its helpful to you.
public class PaintScreen extends Activity {
Context mContext;
private Paint mPaint;
MaskFilter mEmboss;
MaskFilter mBlur;
private LinearLayout mPaintBaseLayout, mPaintBaseLayout2;
private PaintView mPaintView;
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix matrix1 = new Matrix();
Matrix savedMatrix = new Matrix();
Matrix savedMatrix2 = new Matrix();
Matrix dmMtrx = new Matrix();
private int WIDTH = 0;
private int HEIGHT = 1;
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int POINT2 = 2;
static final int ZOOM = 3;
int mode = NONE;
private static final float MIN_ZOOM = 0.0f;
private static final float MAX_ZOOM = 1.0f;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
float newDist;
float distanceOffset = 50f;
float minOffset = 50f;
float maxOffset = 10000f;
private boolean falg = true;
private int startval = 0;
Bitmap newbm;
private float finalscale;
Bitmap bm;
private float scaledImageOffsetX;
private float scaledImageOffsetY;
ImageView imageView;
ProgressDialog dialog;
private float[] matrixValues;
Bitmap temp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_main);
this.initialize();
this.PaintSet();
imageView = (ImageView) findViewById(R.id.imageview1);
Button button = (Button) findViewById(R.id.btnzoom);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (falg) {
getFlag(false);
} else {
getFlag(true);
}
}
});
Button btnset = (Button) findViewById(R.id.btnset);
btnset.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
startval = 1;
mPaintBaseLayout.setDrawingCacheEnabled(true);
/*newbm = Bitmap.createBitmap(bm.getWidth(),
bm.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newbm);
mPaintBaseLayout.draw(canvas);*/
// mPaintView.clear();
/*
mPaintView.setScaleType(ScaleType.MATRIX);
mPaintView.setMPaint(mPaint);
mPaintView.setImageBitmap(newbm);*/
imageView.setVisibility(View.VISIBLE);
mPaintBaseLayout.setVisibility(View.GONE);
new SaveImageAsynk().execute();
}
});
imageView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix1);
start.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
start.set(event.getX(), event.getY());
savedMatrix.set(matrix1);
midPoint(mid, event);
// mode = POINT2;
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
distanceOffset = minOffset;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
distanceOffset = minOffset;
break;
case MotionEvent.ACTION_MOVE:
if (mode == POINT2) {
newDist = spacing(event);
if (newDist - oldDist > 5f
|| newDist - oldDist < -5f) {
mode = ZOOM;
} else {
start.set(event.getX(), event.getY());
mode = DRAG;
}
} else if (mode == DRAG) {
matrix1.set(savedMatrix);
matrix1.postTranslate(event.getX() - start.x,
event.getY() - start.y);
} else if (mode == ZOOM) {
newDist = spacing(event);
if (newDist > 10f) {
matrix1.set(savedMatrix);
float scale = newDist / oldDist;
matrix1.postScale(scale, scale, mid.x,
mid.y);
finalscale = scale;
}
}
break;
}
view.setImageMatrix(matrix1);
// matrixTurning(matrix1, view);
return true; // indicate event was handled
}
});
}
class SaveImageAsynk extends AsyncTask<String, String, String>{
Bitmap tempBm;
#Override
protected String doInBackground(String... params) {
temp = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, false);
newbm = Bitmap.createBitmap(mPaintBaseLayout.getWidth(),
mPaintBaseLayout.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newbm);
mPaintBaseLayout.draw(canvas);
tempBm = combineImages(newbm, temp);
if (newbm != null) {
newbm = null;
}
if (temp != null) {
temp = null;
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
imageView.setImageBitmap(tempBm);
try {
dialog.dismiss();
if (dialog != null) {
dialog = null;
}
} catch (Exception e) {
}
}
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(PaintScreen.this);
dialog.setMessage("Loading...");
dialog.show();
}
}
public Bitmap combineImages(Bitmap c, Bitmap s) {
Bitmap cs = null;
int width, height = 0;
if (c.getWidth() > s.getWidth()) {
width = c.getWidth();
height = c.getHeight() + s.getHeight();
} else {
width = s.getWidth();
height = c.getHeight() + s.getHeight();
}
Log.e("hw :", "X = "+width + " Y = "+height);
cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(s,new Matrix(), null);
comboImage.drawBitmap(c,Math.abs(scaledImageOffsetX),Math.abs(scaledImageOffsetY), null);
return cs;
}
private void initialize() {
mPaintBaseLayout = (LinearLayout) findViewById(R.id.paint_paint_base_layout);
mPaintBaseLayout2 = (LinearLayout) findViewById(R.id.paint_paint_base_layout2);
mContext = this;
mPaint = new Paint();
mPaintView = new PaintView(mContext);
mPaintView.setBackgroundColor(Color.TRANSPARENT);
mPaintBaseLayout.addView(mPaintView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
mPaintBaseLayout.setBackgroundColor(Color.TRANSPARENT);
// mPaintView.setScaleType(ScaleType.FIT_XY);
mPaintView.setAdjustViewBounds(true);
mPaintView.setMPaint(mPaint);
bm = BitmapFactory.decodeResource(getResources(), R.drawable.nat);
mPaintView.setImageBitmap(bm);
mPaintView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
PaintView view = (PaintView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (falg) {
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
} else {
view.onTouchEvent(event);
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
if (falg) {
oldDist = spacing(event);
if (oldDist > 10f) {
start.set(event.getX(), event.getY());
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
}
break;
case MotionEvent.ACTION_UP:
if (falg) {
mode = NONE;
distanceOffset = minOffset;
}
case MotionEvent.ACTION_POINTER_UP:
if (falg) {
mode = NONE;
distanceOffset = minOffset;
}
break;
case MotionEvent.ACTION_MOVE:
if (falg) {
if (mode == POINT2) {
newDist = spacing(event);
if (newDist - oldDist > 5f
|| newDist - oldDist < -5f) {
mode = ZOOM;
} else {
start.set(event.getX(), event.getY());
mode = DRAG;
}
} else if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
} else if (mode == ZOOM) {
newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
finalscale = scale;
}
}
} else {
view.onTouchEvent(event);
}
break;
}
limitZoom(matrix);
view.setImageMatrix(matrix);
matrixTurning(matrix, view);
RectF r = new RectF();
matrix.mapRect(r);
scaledImageOffsetX = r.left;
scaledImageOffsetY = r.top;
return true;
}
});
}
private void limitZoom(Matrix m) {
float[] values = new float[9];
m.getValues(values);
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
if(scaleX > MAX_ZOOM) {
scaleX = MAX_ZOOM;
} else if(scaleX < MIN_ZOOM) {
scaleX = MIN_ZOOM;
}
if(scaleY > MAX_ZOOM) {
scaleY = MAX_ZOOM;
} else if(scaleY < MIN_ZOOM) {
scaleY = MIN_ZOOM;
}
values[Matrix.MSCALE_X] = scaleX;
values[Matrix.MSCALE_Y] = scaleY;
m.setValues(values);
}
public boolean getFlag(boolean b) {
return falg = b;
}
/** Determine the space between the first two fingers */
private static float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private static void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
private void matrixTurning(Matrix matrix, ImageView view) {
float[] value = new float[9];
matrix.getValues(value);
float[] savedValue = new float[9];
savedMatrix2.getValues(savedValue);
// view size
int width = view.getWidth();
int height = view.getHeight();
// image size
Drawable d = view.getDrawable();
if (d == null)
return;
int imageWidth = d.getIntrinsicWidth();
int imageHeight = d.getIntrinsicHeight();
int scaleWidth = (int) (imageWidth * value[0]);
int scaleHeight = (int) (imageHeight * value[0]);
if (value[2] < width - scaleWidth)
value[2] = width - scaleWidth;
if (value[5] < height - scaleHeight)
value[5] = height - scaleHeight;
if (value[2] > 0)
value[2] = 0;
if (value[5] > 0)
value[5] = 0;
if (value[0] > 10 || value[4] > 10) {
value[0] = savedValue[0];
value[4] = savedValue[4];
value[2] = savedValue[2];
value[5] = savedValue[5];
}
if (imageWidth > width || imageHeight > height) {
if (scaleWidth < width && scaleHeight < height) {
int target = WIDTH;
if (imageWidth < imageHeight)
target = HEIGHT;
if (target == WIDTH)
value[0] = value[4] = (float) width / imageWidth;
if (target == HEIGHT)
value[0] = value[4] = (float) height / imageHeight;
scaleWidth = (int) (imageWidth * value[0]);
scaleHeight = (int) (imageHeight * value[4]);
if (scaleWidth == width)
value[0] = value[4] = (float) width / imageWidth;
if (scaleHeight == height)
value[0] = value[4] = (float) height / imageHeight;
}
} else {
if (value[0] < 1)
value[0] = 1;
if (value[4] < 1)
value[4] = 1;
}
scaleWidth = (int) (imageWidth * value[0]);
scaleHeight = (int) (imageHeight * value[4]);
if (scaleWidth < width) {
value[2] = (float) width / 2 - (float) scaleWidth / 2;
}
if (scaleHeight < height) {
value[5] = (float) height / 2 - (float) scaleHeight / 2;
}
matrix.setValues(value);
savedMatrix2.set(matrix);
}
public void PaintSet() {
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(10);
// getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(24, BlurMaskFilter.Blur.NORMAL);
}
public void colorChanged(int color) {
mPaint.setColor(color);
}
}
class PaintView extends ImageView {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
// onDraw
private Paint mPaint;
// onTouch
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mBitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
// canvas.drawColor(0xFFAAAAAA);
super.onDraw(canvas);
mCanvas = canvas;
// canvas = mCanvas;
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
// canvas.drawBitmap(mBitmap, PaintScreen.matrix, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
public void clear() {
mPaint.reset();
// invalidate();
}
public void setMPaint(Paint paint) {
mPaint = paint;
}
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, 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();
Log.d("PaintView", "ev ->" + event.getAction());
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;
}
public void cMatrix(Matrix matrix) {
mCanvas.setMatrix(matrix);
}
}
Related
I have custom image view that can be zoomed in and out. But also I have "canvas.drawBitmap" in onDraw method:
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (isPinShouldBeDrawn) {
Bitmap marker = BitmapFactory.decodeResource(getResources(), R.drawable.ic_pin_raster_64);
canvas.drawBitmap(marker, lastTouchX, lastTouchY, null);
}
isPinShouldBeDrawn = false;
}
In "onTouchEvent" method I can move the image:
#SuppressWarnings("deprecation")
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouchEvent(MotionEvent event) {
if (mDetector.onTouchEvent(event)) {
return true;
}
int touchCount = event.getPointerCount();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_1_DOWN:
case MotionEvent.ACTION_POINTER_2_DOWN:
if (touchCount >= 2) {
float distance = distance(event.getX(0), event.getX(1),
event.getY(0), event.getY(1));
mPrevDistance = distance;
isScaling = true;
} else {
mPrevMoveX = (int) event.getX();
mPrevMoveY = (int) event.getY();
}
case MotionEvent.ACTION_MOVE:
if (touchCount >= 2 && isScaling) {
float dist = distance(event.getX(0), event.getX(1),
event.getY(0), event.getY(1));
float scale = (dist - mPrevDistance) / dispDistance();
mPrevDistance = dist;
scale += 1;
scale = scale * scale;
zoomTo(scale, mWidth / 2, mHeight / 2);
cutting();
} else if (!isScaling) {
int distanceX = mPrevMoveX - (int) event.getX();
int distanceY = mPrevMoveY - (int) event.getY();
mPrevMoveX = (int) event.getX();
mPrevMoveY = (int) event.getY();
mMatrix.postTranslate(-distanceX, -distanceY);
cutting();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_2_UP:
if (event.getPointerCount() <= 1) {
isScaling = false;
}
break;
}
return true;
}
But bitmaps from onDraw not moving. If i'm trying to save new bitmap, it's saving only visible area, and after that I can't zoom it at all or move; Save method:
public void save() {
Bitmap returnedBitmap = Bitmap.createBitmap(
getWidth(),
getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
draw(canvas);
setImageBitmap(returnedBitmap);
}
How to synchronized move and scale the image and added bitmaps? Please help!
Whole class:
import android.annotation.SuppressLint;
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.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import androidx.appcompat.widget.AppCompatImageView;
import com.signalsense.signalsenseapp.R;
public class ScaleImageView extends AppCompatImageView implements OnTouchListener {
static final float STROKE_WIDTH = 10f;
static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
public static Path path = new Path();
public static int imageheight, imagewidth;
private static Matrix mMatrix;
final RectF dirtyRect = new RectF();
private final Context mContext;
private final float MAX_SCALE = 2f;
private final float[] mMatrixValues = new float[9];
float lastTouchX;
float lastTouchY;
Paint paint = new Paint();
String TAG = "ScaleImageView";
private boolean isPinShouldBeDrawn = false;
// display width height.
private int mWidth;
private int mHeight;
private int mIntrinsicWidth;
private int mIntrinsicHeight;
private float mScale;
private float mMinScale;
private float mPrevDistance;
private boolean isScaling;
private int mPrevMoveX;
private int mPrevMoveY;
private GestureDetector mDetector;
public ScaleImageView(Context context, AttributeSet attr) {
super(context, attr);
this.mContext = context;
initialize();
}
public ScaleImageView(Context context) {
super(context);
this.mContext = context;
initialize();
}
private void resetDirtyRect(float eventX, float eventY) {
dirtyRect.left = Math.min(lastTouchX, eventX);
dirtyRect.right = Math.max(lastTouchX, eventX);
dirtyRect.top = Math.min(lastTouchY, eventY);
dirtyRect.bottom = Math.max(lastTouchY, eventY);
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
this.initialize();
}
#Override
public void setImageResource(int resId) {
super.setImageResource(resId);
this.initialize();
}
private void initialize() {
this.setScaleType(ScaleType.MATRIX);
mMatrix = new Matrix();
Drawable d = getDrawable();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(STROKE_WIDTH);
if (d != null) {
mIntrinsicWidth = d.getIntrinsicWidth();
mIntrinsicHeight = d.getIntrinsicHeight();
setOnTouchListener(this);
}
mDetector = new GestureDetector(mContext,
new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onDoubleTap(MotionEvent e) {
maxZoomTo((int) e.getX(), (int) e.getY());
cutting();
return super.onDoubleTap(e);
}
#Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
lastTouchX = e.getX();
lastTouchY = e.getY();
isPinShouldBeDrawn = true;
invalidate();
save();
}
});
}
#Override
protected boolean setFrame(int l, int t, int r, int b) {
mWidth = r - l;
mHeight = b - t;
mMatrix.reset();
int r_norm = r - l;
mScale = (float) r_norm / (float) mIntrinsicWidth;
int paddingHeight = 0;
int paddingWidth = 0;
// scaling vertical
if (mScale * mIntrinsicHeight > mHeight) {
mScale = (float) mHeight / (float) mIntrinsicHeight;
mMatrix.postScale(mScale, mScale);
paddingWidth = (r - mWidth) / 2;
paddingHeight = 0;
// scaling horizontal
} else {
mMatrix.postScale(mScale, mScale);
paddingHeight = (b - mHeight) / 2;
paddingWidth = 0;
}
mMatrix.postTranslate(paddingWidth, paddingHeight);
setImageMatrix(mMatrix);
mMinScale = mScale;
zoomTo(mScale, mWidth / 2, mHeight / 2);
cutting();
return super.setFrame(l, t, r, b);
}
protected float getValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
return mMatrixValues[whichValue];
}
protected float getScale() {
return getValue(mMatrix, Matrix.MSCALE_X);
}
public float getTranslateX() {
return getValue(mMatrix, Matrix.MTRANS_X);
}
protected float getTranslateY() {
return getValue(mMatrix, Matrix.MTRANS_Y);
}
protected void maxZoomTo(int x, int y) {
if (mMinScale != getScale() && (getScale() - mMinScale) > 0.1f) {
// threshold 0.1f
float scale = mMinScale / getScale();
zoomTo(scale, x, y);
} else {
float scale = MAX_SCALE / getScale();
zoomTo(scale, x, y);
}
}
public void zoomTo(float scale, int x, int y) {
if (getScale() * scale < mMinScale) {
return;
}
if (scale >= 1 && getScale() * scale > MAX_SCALE) {
return;
}
mMatrix.postScale(scale, scale);
// move to center
mMatrix.postTranslate(-(mWidth * scale - mWidth) / 2,
-(mHeight * scale - mHeight) / 2);
// move x and y distance
mMatrix.postTranslate(-(x - (mWidth / 2)) * scale, 0);
mMatrix.postTranslate(0, -(y - (mHeight / 2)) * scale);
setImageMatrix(mMatrix);
}
public void cutting() {
int width = (int) (mIntrinsicWidth * getScale());
int height = (int) (mIntrinsicHeight * getScale());
imagewidth = width;
imageheight = height;
if (getTranslateX() < -(width - mWidth)) {
mMatrix.postTranslate(-(getTranslateX() + width - mWidth), 0);
}
if (getTranslateX() > 0) {
mMatrix.postTranslate(-getTranslateX(), 0);
}
if (getTranslateY() < -(height - mHeight)) {
mMatrix.postTranslate(0, -(getTranslateY() + height - mHeight));
}
if (getTranslateY() > 0) {
mMatrix.postTranslate(0, -getTranslateY());
}
if (width < mWidth) {
mMatrix.postTranslate((mWidth - width) / 2, 0);
}
if (height < mHeight) {
mMatrix.postTranslate(0, (mHeight - height) / 2);
}
setImageMatrix(mMatrix);
}
private float distance(float x0, float x1, float y0, float y1) {
float x = x0 - x1;
float y = y0 - y1;
return (float) Math.sqrt(x * x + y * y);
}
private float dispDistance() {
return (float) Math.sqrt(mWidth * mWidth + mHeight * mHeight);
}
public void clear() {
path.reset();
invalidate();
}
public void save() {
Bitmap returnedBitmap = Bitmap.createBitmap(
getWidth(),
getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
draw(canvas);
setImageBitmap(returnedBitmap);
}
#SuppressWarnings("deprecation")
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouchEvent(MotionEvent event) {
if (mDetector.onTouchEvent(event)) {
return true;
}
int touchCount = event.getPointerCount();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_1_DOWN:
case MotionEvent.ACTION_POINTER_2_DOWN:
if (touchCount >= 2) {
float distance = distance(event.getX(0), event.getX(1),
event.getY(0), event.getY(1));
mPrevDistance = distance;
isScaling = true;
} else {
mPrevMoveX = (int) event.getX();
mPrevMoveY = (int) event.getY();
}
case MotionEvent.ACTION_MOVE:
if (touchCount >= 2 && isScaling) {
float dist = distance(event.getX(0), event.getX(1),
event.getY(0), event.getY(1));
float scale = (dist - mPrevDistance) / dispDistance();
mPrevDistance = dist;
scale += 1;
scale = scale * scale;
zoomTo(scale, mWidth / 2, mHeight / 2);
cutting();
} else if (!isScaling) {
int distanceX = mPrevMoveX - (int) event.getX();
int distanceY = mPrevMoveY - (int) event.getY();
mPrevMoveX = (int) event.getX();
mPrevMoveY = (int) event.getY();
mMatrix.postTranslate(-distanceX, -distanceY);
cutting();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_2_UP:
if (event.getPointerCount() <= 1) {
isScaling = false;
}
break;
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (isPinShouldBeDrawn) {
Bitmap marker = BitmapFactory.decodeResource(getResources(), R.drawable.ic_pin_raster_64);
canvas.drawBitmap(marker, lastTouchX, lastTouchY, null);
}
isPinShouldBeDrawn = false;
}
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouch(View v, MotionEvent event) {
return super.onTouchEvent(event);
}
}
Sorry for english, it's not my native language :)
Record normalized coordinates on touch events,
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
//lastTouchX = e.getX();
//lastTouchY = e.getY();
float[] touchCoords = new float[]{ e.getX(), e.getY()}; // Touch point in screen-X,Y coords.
Matrix matrix_inverse = new Matrix();
mMatrix.invert(matrix_inverse); // XY to UV mapping matrix.
matrix_inverse.mapPoints(touchCoords); // Touch point in bitmap-U,V coords.
lastTouchX = touchCoords[0];
lastTouchY = touchCoords[1];
isPinShouldBeDrawn = true;
invalidate();
save();
}
Then, draw the overlay bitmap by applying the transform.
protected void onDraw(Canvas canvas)
{
// TODO Auto-generated method stub
super.onDraw(canvas);
if (isPinShouldBeDrawn)
{
Bitmap marker = BitmapFactory.decodeResource(getResources(), R.drawable.ic_pin_raster_64);
//canvas.drawBitmap(marker, lastTouchX, lastTouchY, null);
Matrix matrix_marker = new Matrix();
matrix_marker.setTranslate(lastTouchX, lastTouchY);
matrix_marker.postConcat(mMatrix);
canvas.drawBitmap(marker, matrix_marker, null);
}
isPinShouldBeDrawn = false;
}
If you'd like to bake the overlays onto the bitmap, set the invert matrix to the canvas and call draw().
public void save()
{
Bitmap returnedBitmap = Bitmap.createBitmap(
mIntrinsicWidth,
mIntrinsicHeight,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
Matrix matrix_inverse = new Matrix();
mMatrix.invert(matrix_inverse);
canvas.setMatrix(matrix_inverse);
draw(canvas);
setImageBitmap(returnedBitmap);
}
I have certain data in placed in my ScrollView. I want to enable it to zoom in/ zoom out. It contains simple ImageView and TextView.
Any suggestions will be helpful.
Thank you.
Here is my code:
<ScrollView
android:id="#+id/viewSoupMenu"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/soupback" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="50dp">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="35dp"
android:layout_marginTop="30dp"
android:background="#android:color/transparent"
android:src="#drawable/flowericon" />
<ImageButton
android:id="#+id/btnVegClearSoup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="20dp"
android:background="#android:color/transparent"
android:src="#drawable/btnvegsoupclearclickedxml" />
</LinearLayout>
</ScrollView>
You can use the class mentioned below for enabling Pinch Zoom in your ImageView and you can create a duplicate class of this class which extends TextView instead of ImageView for enabling zooming in it.
public class PinchZoomImageView extends ImageView implements OnTouchListener{
public PinchZoomImageView(Context context) {
super(context);
_init();
}
public PinchZoomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
_init();
}
public PinchZoomImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
_init();
}
private void _init(){
//setOnTouchListener(this);
view = (ImageView) this;
view.setOnTouchListener(this);
metric = new DisplayMetrics();
// Work around a Cupcake bug
d_dpi=((0.52f/(metric.densityDpi))*240.0f)-0.52f;
Log.d("ash","dpi= "+d_dpi);
if(metric.densityDpi==160)
d_dpi=0.34f;
matrix.setTranslate(1f, 1f);
matrix.setScale((0.52f/800.0f)*metric.widthPixels+d_dpi, (0.52f/480.0f)*metric.heightPixels+d_dpi);
view.setImageMatrix(matrix);
bMap = BitmapFactory.decodeResource(getResources(), R.drawable.mfigure);
btsize = BitmapFactory.decodeResource(getResources(), R.drawable.map);
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(hasFocus){
init();
}
}
private void init() {
maxZoom = (3.0f/480.0f)*metric.heightPixels+d_dpi;
minZoom = (0.52f/800.0f)*metric.widthPixels+d_dpi;
height = view.getDrawable().getIntrinsicHeight();
width = view.getDrawable().getIntrinsicWidth();
viewRect = new RectF(0, 0, view.getWidth(), view.getHeight());
}
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX()/metric.widthPixels * 800, event.getY()/metric.heightPixels * 480);
Log.d(TAG, "mode=DRAG");
mode = DRAG;
click = true;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
click = false;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "mode=NONE");
if(click)
onClick(event.getX(), event.getY(),true);
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
temp_x = ((start.x) - ((event.getX()/metric.widthPixels)*800));
temp_y = ((start.y) - ((event.getY()/metric.heightPixels) * 480));
if(FloatMath.sqrt(temp_x * temp_x + temp_y * temp_y)< 10)
break;
matrix.set(savedMatrix);
// limit pan
matrix.getValues(matrixValues);
float currentY = matrixValues[Matrix.MTRANS_Y];
float currentX = matrixValues[Matrix.MTRANS_X];
float currentScale = matrixValues[Matrix.MSCALE_X];
float currentHeight = height * currentScale;
float currentWidth = width * currentScale;
float dx = (event.getX()/metric.widthPixels * 800) - start.x;
float dy = (event.getY()/metric.heightPixels * 480) - start.y;
float newX = currentX+dx;
float newY = currentY+dy;
RectF drawingRect = new RectF(newX, newY, newX+currentWidth, newY+currentHeight);
float diffUp = Math.min(viewRect.bottom-drawingRect.bottom, viewRect.top-drawingRect.top);
float diffDown = Math.max(viewRect.bottom-drawingRect.bottom, viewRect.top-drawingRect.top);
float diffLeft = Math.min(viewRect.left-drawingRect.left, viewRect.right-drawingRect.right);
float diffRight = Math.max(viewRect.left-drawingRect.left, viewRect.right-drawingRect.right);
if(diffUp > 0 ){
dy +=diffUp;
}
if(diffDown < 0){
dy +=diffDown;
}
if( diffLeft> 0){
dx += diffLeft;
}
if(diffRight < 0){
dx += diffRight;
}
matrix.postTranslate(dx, dy);
//selection.set(selection.x + dx, selection.y + dy);
click = false;
}
else if (mode == ZOOM) {
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.getValues(matrixValues);
float currentScale = matrixValues[Matrix.MSCALE_X];
// limit zoom
if (scale * currentScale > maxZoom) {
scale = maxZoom / currentScale;
} else if (scale * currentScale < minZoom) {
scale = minZoom / currentScale;
}
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
float mv[] = new float[9];
matrix.getValues(mv);
Log.d("PV", "Click x " + mv[Matrix.MTRANS_X] + " y " + mv[Matrix.MTRANS_Y] + " cx " + event.getX() + " cy " + event.getY());
view.setImageMatrix(matrix);
view.invalidate();
return true; // indicate event was handled
}
public void onClick(float x, float y,boolean state){
Log.d("TAG","x="+x+" y "+y);
float mv[] = new float[9];
matrix.getValues(mv);
if(btsize != null)
btsize.recycle();
btsize = BitmapFactory.decodeResource(getResources(), R.drawable.map);
if(btSel != null)
btSel.recycle();
btSel = BitmapFactory.decodeResource(getResources(), R.drawable.mfigure);
Canvas canvas;
try{
canvas = new Canvas(btsize);
}
catch(Exception e){
btsize = BitmapFactory.decodeResource(getResources(), R.drawable.map).copy(Config.ARGB_8888,true);
canvas = new Canvas(btsize);
}
x -= mv[Matrix.MTRANS_X];
y -= mv[Matrix.MTRANS_Y];
float wdt = btsize.getWidth() * mv[Matrix.MSCALE_X];
float ht = btsize.getHeight() * mv[Matrix.MSCALE_Y];
float tw = x/wdt;
float th = y/ht;
selPoint.set(tw, th);
if(state)
canvas.drawBitmap(btSel, (tw * btsize.getWidth()) - (btSel.getWidth()/2), (th * btsize.getHeight()) - (btSel.getHeight()/2), null);
else
canvas.drawBitmap(btSel, (x * btsize.getWidth()) - (btSel.getWidth()/2), (y * btsize.getHeight()) - (btSel.getHeight()/2), null);
setImageBitmap(btsize);
}
/** Determine the space between the first two fingers */
private float spacing(MotionEvent event) {
float x = ((event.getX(0)/metric.widthPixels)*800) - ((event.getX(1)/metric.widthPixels)*800);
float y = ((event.getY(0)/metric.heightPixels) * 480) - ((event.getY(1)/metric.heightPixels) * 480);
return FloatMath.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private void midPoint(PointF point, MotionEvent event) {
float x = ((event.getX(0)/metric.widthPixels) * 800) + ((event.getX(1)/metric.widthPixels)*800);
float y = ((event.getY(0)/metric.heightPixels) * 480) + ((event.getY(1)/metric.heightPixels) * 480);
point.set(x / 2, y / 2);
}
private static final String TAG = "Touch";
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
// Limit zoomable/pannable image
private ImageView view;
private float[] matrixValues = new float[9];
private float maxZoom;
private float minZoom;
private float height;
private float width;
private RectF viewRect;
private float temp_x,temp_y;
private boolean click = false;
public PointF selPoint = new PointF();
Bitmap bMap;
private float d_dpi;
Paint paint = new Paint();
Canvas canvas = new Canvas();
private DisplayMetrics metric;
Bitmap bt = null;
Bitmap btsize = null;
Bitmap btSel = null;
}
Try using FrameLayout and have a look at this official document: Zooming a View.
I have a custom imageview and have implemented zoom/drag functionality to it using matrix scaling.
My problem is that when I open the activity having the imagview, the opened image is smaller than the imageview.
I want the image to exactly fit the imageview. Please suggest how can I achieve this.
P.S: I can not use 'fitXY' or any scaleType other than matrix (because i am using matrix for zooming n all). I have tried using centreInside, fitXy etc already.
courtesy Android Image View Pinch Zooming: ImageView extended:
public class CustomImageVIew extends ImageView implements OnTouchListener {
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
private int mode = NONE;
private PointF mStartPoint = new PointF();
private PointF mMiddlePoint = new PointF();
private Point mBitmapMiddlePoint = new Point();
private float oldDist = 1f;
private float matrixValues[] = {0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f};
private float scale;
private float oldEventX = 0;
private float oldEventY = 0;
private float oldStartPointX = 0;
private float oldStartPointY = 0;
private int mViewWidth = -1;
private int mViewHeight = -1;
private int mBitmapWidth = -1;
private int mBitmapHeight = -1;
private boolean mDraggable = false;
public CustomImageVIew(Context context) {
this(context, null, 0);
}
public CustomImageVIew(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomImageVIew(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setOnTouchListener(this);
}
#Override
public void onSizeChanged (int w, int h, int oldw, int oldh){
super.onSizeChanged(w, h, oldw, oldh);
mViewWidth = w;
mViewHeight = h;
}
public void setBitmap(Bitmap bitmap){
if(bitmap != null){
setImageBitmap(bitmap);
mBitmapWidth = bitmap.getWidth();
mBitmapHeight = bitmap.getHeight();
mBitmapMiddlePoint.x = (mViewWidth / 2) - (mBitmapWidth / 2);
mBitmapMiddlePoint.y = (mViewHeight / 2) - (mBitmapHeight / 2);
matrix.postTranslate(mBitmapMiddlePoint.x, mBitmapMiddlePoint.y);
this.setImageMatrix(matrix);
}
}
#Override
public boolean onTouch(View v, MotionEvent event){
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
mStartPoint.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if(oldDist > 10f){
savedMatrix.set(matrix);
midPoint(mMiddlePoint, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if(mode == DRAG){
drag(event);
} else if(mode == ZOOM){
zoom(event);
}
break;
}
return true;
}
public void drag(MotionEvent event){
matrix.getValues(matrixValues);
float left = matrixValues[2];
float top = matrixValues[5];
float bottom = (top + (matrixValues[0] * mBitmapHeight)) - mViewHeight;
float right = (left + (matrixValues[0] * mBitmapWidth)) -mViewWidth;
float eventX = event.getX();
float eventY = event.getY();
float spacingX = eventX - mStartPoint.x;
float spacingY = eventY - mStartPoint.y;
float newPositionLeft = (left < 0 ? spacingX : spacingX * -1) + left;
float newPositionRight = (spacingX) + right;
float newPositionTop = (top < 0 ? spacingY : spacingY * -1) + top;
float newPositionBottom = (spacingY) + bottom;
boolean x = true;
boolean y = true;
if(newPositionRight < 0.0f || newPositionLeft > 0.0f){
if(newPositionRight < 0.0f && newPositionLeft > 0.0f){
x = false;
} else{
eventX = oldEventX;
mStartPoint.x = oldStartPointX;
}
}
if(newPositionBottom < 0.0f || newPositionTop > 0.0f){
if(newPositionBottom < 0.0f && newPositionTop > 0.0f){
y = false;
} else{
eventY = oldEventY;
mStartPoint.y = oldStartPointY;
}
}
if(mDraggable){
matrix.set(savedMatrix);
matrix.postTranslate(x? eventX - mStartPoint.x : 0, y? eventY - mStartPoint.y : 0);
this.setImageMatrix(matrix);
if(x)oldEventX = eventX;
if(y)oldEventY = eventY;
if(x)oldStartPointX = mStartPoint.x;
if(y)oldStartPointY = mStartPoint.y;
}
}
public void zoom(MotionEvent event){
matrix.getValues(matrixValues);
float newDist = spacing(event);
float bitmapWidth = matrixValues[0] * mBitmapWidth;
float bimtapHeight = matrixValues[0] * mBitmapHeight;
boolean in = newDist > oldDist;
if(!in && matrixValues[0] < 1){
return;
}
if(bitmapWidth > mViewWidth || bimtapHeight > mViewHeight){
mDraggable = true;
} else{
mDraggable = false;
}
float midX = (mViewWidth / 2);
float midY = (mViewHeight / 2);
matrix.set(savedMatrix);
scale = newDist / oldDist;
matrix.postScale(scale, scale, bitmapWidth > mViewWidth ? mMiddlePoint.x : midX, bimtapHeight > mViewHeight ? mMiddlePoint.y : midY);
this.setImageMatrix(matrix);
}
/** Determine the space between the first two fingers */
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float)Math.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
}
add this to imageView in the layout:
android:scaleType="centerCrop"
I used canvas in order to zoom paint view with image including using setImageMatrix(). As shown below class use for zoom and draw line.But problem arised, that is entire screen became to zoom in/out then when i click on paint button i pass one Boolean as false which draw line on touch of finger.but after draw line on image i want to start pinch zoom again with this drawing line on and then i can also zoom in/out with drawing paint but its not going in proper way change x-y of paint view. So If anyone knows this issue, reply plz.
public class PaintScreen extends Activity {
Context mContext;
private Paint mPaint;
MaskFilter mEmboss;
MaskFilter mBlur;
private LinearLayout mPaintBaseLayout;
private PaintView mPaintView;
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
Matrix savedMatrix2 = new Matrix();
private int WIDTH = 0;
private int HEIGHT = 1;
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int POINT2 = 2;
static final int ZOOM = 3;
int mode = NONE;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
float newDist;
float distanceOffset = 50f;
float minOffset = 50f;
float maxOffset = 10000f;
private boolean falg = true;
private int startval = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_main);
this.initialize();
this.PaintSet();
Button button = (Button) findViewById(R.id.btnzoom);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (falg) {
getFlag(false);
} else {
getFlag(true);
}
}
});
Button btnset = (Button) findViewById(R.id.btnset);
btnset.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
startval = 1;
}
});
}
private void initialize() {
mPaintBaseLayout = (LinearLayout) findViewById(R.id.paint_paint_base_layout);
mContext = this;
mPaint = new Paint();
mPaintView = new PaintView(mContext);
mPaintView.setBackgroundColor(Color.TRANSPARENT);
mPaintBaseLayout.addView(mPaintView, new LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
mPaintBaseLayout.setBackgroundColor(Color.TRANSPARENT);
mPaintView.setScaleType(ScaleType.MATRIX);
mPaintView.setMPaint(mPaint);
Bitmap bm = BitmapFactory
.decodeResource(getResources(), R.drawable.nat);
mPaintView.setImageBitmap(bm);
mPaintView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
PaintView view = (PaintView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (falg) {
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
} else {
view.onTouchEvent(event);
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
if (falg) {
oldDist = spacing(event);
if (oldDist > 10f) {
start.set(event.getX(), event.getY());
savedMatrix.set(matrix);
midPoint(mid, event);
// mode = POINT2;
mode = ZOOM;
}
}
break;
case MotionEvent.ACTION_UP:
if (falg) {
mode = NONE;
distanceOffset = minOffset;
}
case MotionEvent.ACTION_POINTER_UP:
if (falg) {
mode = NONE;
distanceOffset = minOffset;
}
break;
case MotionEvent.ACTION_MOVE:
if (falg) {
if (mode == POINT2) {
newDist = spacing(event);
if (newDist - oldDist > 5f
|| newDist - oldDist < -5f) {
mode = ZOOM;
} else {
start.set(event.getX(), event.getY());
mode = DRAG;
}
} else if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
} else if (mode == ZOOM) {
newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
} else {
view.onTouchEvent(event);
}
break;
}
// if (startval == 1) {
view.cMatrix(matrix);
// }
view.setImageMatrix(matrix);
matrixTurning(matrix, view);
return true;
}
});
}
public boolean getFlag(boolean b) {
return falg = b;
}
/** Determine the space between the first two fingers */
private static float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private static void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
private void matrixTurning(Matrix matrix, ImageView view) {
float[] value = new float[9];
matrix.getValues(value);
float[] savedValue = new float[9];
savedMatrix2.getValues(savedValue);
// view size
int width = view.getWidth();
int height = view.getHeight();
// image size
Drawable d = view.getDrawable();
if (d == null)
return;
int imageWidth = d.getIntrinsicWidth();
int imageHeight = d.getIntrinsicHeight();
int scaleWidth = (int) (imageWidth * value[0]);
int scaleHeight = (int) (imageHeight * value[0]);
if (value[2] < width - scaleWidth)
value[2] = width - scaleWidth;
if (value[5] < height - scaleHeight)
value[5] = height - scaleHeight;
if (value[2] > 0)
value[2] = 0;
if (value[5] > 0)
value[5] = 0;
if (value[0] > 10 || value[4] > 10) {
value[0] = savedValue[0];
value[4] = savedValue[4];
value[2] = savedValue[2];
value[5] = savedValue[5];
}
if (imageWidth > width || imageHeight > height) {
if (scaleWidth < width && scaleHeight < height) {
int target = WIDTH;
if (imageWidth < imageHeight)
target = HEIGHT;
if (target == WIDTH)
value[0] = value[4] = (float) width / imageWidth;
if (target == HEIGHT)
value[0] = value[4] = (float) height / imageHeight;
scaleWidth = (int) (imageWidth * value[0]);
scaleHeight = (int) (imageHeight * value[4]);
if (scaleWidth == width)
value[0] = value[4] = (float) width / imageWidth;
if (scaleHeight == height)
value[0] = value[4] = (float) height / imageHeight;
}
} else {
if (value[0] < 1)
value[0] = 1;
if (value[4] < 1)
value[4] = 1;
}
scaleWidth = (int) (imageWidth * value[0]);
scaleHeight = (int) (imageHeight * value[4]);
if (scaleWidth < width) {
value[2] = (float) width / 2 - (float) scaleWidth / 2;
}
if (scaleHeight < height) {
value[5] = (float) height / 2 - (float) scaleHeight / 2;
}
matrix.setValues(value);
savedMatrix2.set(matrix);
}
public void PaintSet() {
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(10);
// getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(24, BlurMaskFilter.Blur.NORMAL);
}
public void colorChanged(int color) {
mPaint.setColor(color);
}
}
class PaintView extends ImageView {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
// onDraw
private Paint mPaint;
// onTouch
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mBitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
// canvas.drawColor(0xFFAAAAAA);
super.onDraw(canvas);
mCanvas = canvas;
// canvas = mCanvas;
Matrix localMatrix = new Matrix();
localMatrix.setRectToRect(
new RectF(0.0F, 0.0F, mBitmap.getWidth(), mBitmap
.getHeight()),
new RectF(0.0F, 0.0F, this.mCanvas.getWidth(),
this.mCanvas.getHeight()),
Matrix.ScaleToFit.CENTER);
canvas.drawBitmap(mBitmap, localMatrix, mBitmapPaint);
// canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
// canvas.drawBitmap(mBitmap, PaintScreen.matrix, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
public void setMPaint(Paint paint) {
mPaint = paint;
}
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, 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();
Log.d("PaintView", "ev ->" + event.getAction());
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;
}
public void cMatrix(Matrix matrix) {
mCanvas.setMatrix(matrix);
}
}
Image with pinch zoom and paint on image
imageView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix1);
start.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
start.set(event.getX(), event.getY());
savedMatrix.set(matrix1);
midPoint(mid, event);
// mode = POINT2;
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
distanceOffset = minOffset;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
distanceOffset = minOffset;
break;
case MotionEvent.ACTION_MOVE:
if (mode == POINT2) {
newDist = spacing(event);
if (newDist - oldDist > 5f
|| newDist - oldDist < -5f) {
mode = ZOOM;
} else {
start.set(event.getX(), event.getY());
mode = DRAG;
}
} else if (mode == DRAG) {
matrix1.set(savedMatrix);
matrix1.postTranslate(event.getX() - start.x,
event.getY() - start.y);
} else if (mode == ZOOM) {
newDist = spacing(event);
if (newDist > 10f) {
matrix1.set(savedMatrix);
float scale = newDist / oldDist;
matrix1.postScale(scale, scale, mid.x,
mid.y);
finalscale = scale;
}
}
break;
}
view.setImageMatrix(matrix1);
// matrixTurning(matrix1, view);
return true; // indicate event was handled
}
});
}
mPaintView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
PaintView view = (PaintView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (falg) {
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
} else {
view.onTouchEvent(event);
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
if (falg) {
oldDist = spacing(event);
if (oldDist > 10f) {
start.set(event.getX(), event.getY());
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
}
break;
case MotionEvent.ACTION_UP:
if (falg) {
mode = NONE;
distanceOffset = minOffset;
}
case MotionEvent.ACTION_POINTER_UP:
if (falg) {
mode = NONE;
distanceOffset = minOffset;
}
break;
case MotionEvent.ACTION_MOVE:
if (falg) {
if (mode == POINT2) {
newDist = spacing(event);
if (newDist - oldDist > 5f
|| newDist - oldDist < -5f) {
mode = ZOOM;
} else {
start.set(event.getX(), event.getY());
mode = DRAG;
}
} else if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
} else if (mode == ZOOM) {
newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
finalscale = scale;
}
}
} else {
view.onTouchEvent(event);
}
break;
}
limitZoom(matrix);
view.setImageMatrix(matrix);
matrixTurning(matrix, view);
RectF r = new RectF();
matrix.mapRect(r);
scaledImageOffsetX = r.left;
scaledImageOffsetY = r.top;
return true;
}
});
}
private void limitZoom(Matrix m) {
float[] values = new float[9];
m.getValues(values);
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
if(scaleX > MAX_ZOOM) {
scaleX = MAX_ZOOM;
} else if(scaleX < MIN_ZOOM) {
scaleX = MIN_ZOOM;
}
if(scaleY > MAX_ZOOM) {
scaleY = MAX_ZOOM;
} else if(scaleY < MIN_ZOOM) {
scaleY = MIN_ZOOM;
}
values[Matrix.MSCALE_X] = scaleX;
values[Matrix.MSCALE_Y] = scaleY;
m.setValues(values);
}
public boolean getFlag(boolean b) {
return falg = b;
}
PaintView.class
class PaintView extends ImageView {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
// onDraw
private Paint mPaint;
// onTouch
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mBitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
// canvas.drawColor(0xFFAAAAAA);
super.onDraw(canvas);
mCanvas = canvas;
// canvas = mCanvas;
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
// canvas.drawBitmap(mBitmap, PaintScreen.matrix, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
public void clear() {
mPaint.reset();
// invalidate();
}
public void setMPaint(Paint paint) {
mPaint = paint;
}
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, 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();
Log.d("PaintView", "ev ->" + event.getAction());
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;
}
public void cMatrix(Matrix matrix) {
mCanvas.setMatrix(matrix);
}
}
I have created my own ImageView which hopefully will
do overlays , zooming , panning and measuring between two points.
So far all but the measuring works The canvas.drawline shows nothing ?
This may be dirty and could probably be cleaned quite a bit.
Anyone got an Idea why the canvas.drawline does not work ?
Thanks in Advance
public class myImage extends ImageView implements OnTouchListener {
private static final short UNKNOWN = 0;
private static final short IMG_INIT = 1;
private static final short SET_IMAGE = 2;
private static final short DRAGGING = 3;
private static final short MARKING = 4;
private static final short STARTING = 5;
private static final short ZOOM_PAN = 6;
private static final short OVERLAY = 7;
private static short STATE = UNKNOWN;
private static PointF pointA = null;
private static PointF pointB = null;
private static PointF pointC = null;
private PointF busy = new PointF();
private Bitmap tracking = BitmapFactory.decodeResource(getResources(), R.drawable.target);
private Drawable[] layers = new Drawable[2];
private Paint mPaint;
private Bitmap mBitmap;
private Canvas busyCanvas;
private int touch_counter = 0;
#Override
protected void onDraw(Canvas canvas) {
switch (STATE) {
/* 0 */ case UNKNOWN: super.onDraw(canvas); break;
/* 1 */ case IMG_INIT: break;
/* 2 */ case SET_IMAGE: super.onDraw(canvas); break;
/* 3 */ case DRAGGING: break;
/* 4 */ case MARKING:
canvas.drawBitmap(mBitmap, matrix, mPaint);
if (touch_counter == 0 && pointB != null && CURRENT_STATUS == "DRAW_LINE" ) {
mPaint.setColor(Color.BLUE);
canvas.drawLine(pointA.x, pointA.y, pointB.x, pointB.y, mPaint);
This is What does Not Show up OR work
}
break;
/* 5 */ case STARTING: break;
/* 6 */ case ZOOM_PAN: super.onDraw(canvas); break;
/* 7 */ case OVERLAY: super.onDraw(canvas); break;
}
STATE = UNKNOWN;
}
public void InitOverlay(String fName) {
fName = "/sdcard/DCIM/"+fName;
if ( (fName.endsWith(".jpg") || fName.endsWith(".png")) ) {
Matrix matrix = new Matrix();
matrix.postScale(0.35f, 0.35f);
Bitmap bitm2 = BitmapFactory.decodeFile( fName );
layers[0] = new BitmapDrawable( mBitmap ); layers[0].setAlpha(255);
layers[1] = new BitmapDrawable( Bitmap.createBitmap(bitm2, 0, 0, bitm2.getWidth(), bitm2.getHeight(), matrix, true) ); layers[1].setAlpha( 50);
LayerDrawable layerDraw = new LayerDrawable(layers);
super.setImageDrawable(layerDraw);
super.invalidate();
STATE = OVERLAY;
}
}
private void OverLay(View view , MotionEvent event) {
if ( STATE == UNKNOWN && event.getAction() == MotionEvent.ACTION_MOVE) {
STATE = OVERLAY;
if ( event.getX() > 1 && event.getX() < 1130 ) {
layers[1].setAlpha( (int) (event.getX() / 4.35f) );
}
}
}
private void AddPoints(View view , MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: touch_start(event.getX() , event.getY()); break;
case MotionEvent.ACTION_MOVE: touch_busy (event.getX() , event.getY()); break;
case MotionEvent.ACTION_UP: touch_end (event.getX() , event.getY()); break;
}
}
private void touch_start(float x, float y) {
STATE = STARTING;
touch_counter++;
busy.x = ((x - 32.0f + (float)getScrollX()));
busy.y = ((y - 70.0f + (float)getScrollY()));
}
private void touch_busy(float x, float y) {
busy.x = ((x - 32.0f + (float)getScrollX()));
busy.y = ((y - 70.0f + (float)getScrollY()));
STATE = DRAGGING;
}
private void touch_end(float x, float y) {
STATE = MARKING;
if (touch_counter == 1) {
pointA = new PointF();
pointA.x = ((x - 32.0f)); // + ViewOffset.x));
pointA.y = ((y - 70.0f)); // + ViewOffset.y));
} else if (touch_counter == 2) {
pointB = new PointF();
pointB.x = ((x - 32.0f));
pointB.y = ((y - 70.0f));
if (CURRENT_STATUS == "DRAW_LINE") touch_counter = 0;
Log.i("Image" , "At this Point Calling Draw ");
super.draw(busyCanvas);
}
}
public myImage(Context context , FrameLayout screen) {
super(context);
super.setLayerType(LAYER_TYPE_HARDWARE, null);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF0000FF);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(5);
STATE = IMG_INIT;
invalidate();
}
public void freeImage() {
try {
mBitmap.recycle();
tracking.recycle();
} catch (Exception err) {
ImageExceptionHandler(err);
}
}
#Override
public void setImageBitmap(Bitmap bmp) {
try {
STATE = SET_IMAGE;
busyCanvas = new Canvas();
busyCanvas.setBitmap(bmp);
mBitmap = bmp;
busyCanvas.setBitmap(bmp);
} catch (Exception err) {
ImageExceptionHandler(err);
}
super.setImageBitmap(bmp);
}
private void ImageExceptionHandler(Exception err) {
Log.e("image" , "==============================================");
Log.e("image" , "EXCEPTION Handling ");
Log.e("image" , "==============================================");
err.printStackTrace();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (CURRENT_STATUS == "PAN & ZOOM" ) ScrollAndZoom(v , event);
else if (CURRENT_STATUS == "OVERLAY" ) OverLay(v , event);
else if (CURRENT_STATUS == "DRAW_LINE" ) AddPoints(v , event);
else {
Log.w("ERROR" , "Should Never Be Here myImage On Touch");
Log.w("ERROR" , "Should Never Be Here myImage On Touch");
}
return true;
}
public void init() {
super.setScaleType( ImageView.ScaleType.MATRIX );
mode = NONE;
matrix = new Matrix();
matrix.set(getImageMatrix());
savematrix = new Matrix();
start = new PointF();
mid = new PointF();
oldDist = 1f;
oldfactor = 1f;
factor = 1f;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.i("Image" , "Size Changed ["+w+"] x ["+h+"] ["+oldw+"] x ["+oldh+"] ");
super.onSizeChanged(w, h, oldw, oldh);
}
private static final short NONE = 0;
private static final short ZOOM = 1;
private static final short DRAG = 2;
private Matrix matrix = new Matrix();
private Matrix savematrix = new Matrix();
private short mode = NONE;
private PointF start = new PointF();
private PointF mid = new PointF();
private float oldDist = 1f;
private float oldfactor = 1f;
private float factor = 1f;
private void ScrollAndZoom(View view , MotionEvent event) {
STATE = ZOOM_PAN;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: start.set(event.getX() , event.getY());
savematrix.set(matrix);
mode = DRAG;
break;
//------------------------------------------------
case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event);
midPoint(mid , event);
mode = ZOOM;
oldfactor = factor;
break;
//------------------------------------------------
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: start = new PointF();
mode = NONE;
matrix.set(getImageMatrix());
setBackgroundColor(Color.BLACK);
break;
//------------------------------------------------
case MotionEvent.ACTION_MOVE: matrix.set(savematrix);
if (mode == DRAG) {
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
setBackgroundColor(Color.BLACK);
matrix.postTranslate(dx, dy);
setImageMatrix(matrix);
} else if (mode == ZOOM) {
float newD = spacing(event);
float newfactor = newD / oldDist;
factor = oldfactor * newfactor;
zoom(newfactor);
}
break;
//------------------------------------------------
}
}
private void zoom (Float scale) {
setBackgroundColor(Color.BLACK);
matrix.postScale(scale , scale , mid.x , mid.y);
setImageMatrix(matrix);
}
private float spacing(MotionEvent event) {
float dx = event.getX(1) - event.getX(0);
float dy = event.getY(1) - event.getY(0);
return FloatMath.sqrt(dx*dx + dy*dy);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2f , y / 2f);
}
}
Making some progress some steps backwards
I have re-written some of it It will now Draw the Line and Zoom the entire image with the line zooming also.
However if I draw a line, then Zoom in Good !
But When I draw again it draws the line a Ultra zooms in, and when you zoom out most of the image is now lost? ? and ideas why?
Thanks in advance
Here is the current code
public class myImage extends ImageView implements OnTouchListener {
private static final short NONE = 0;
private static final short ZOOM = 1;
private static final short DRAG = 2;
private static short mode = NONE;
private static PointF pointA = null;
private static PointF pointB = null;
private ImageView pointer = null;
private PointF busy = new PointF();
private PointF start = new PointF();
private PointF mid = new PointF();
private Matrix matrix = new Matrix();
private Matrix savematrix = new Matrix();
private Bitmap tracking = BitmapFactory.decodeResource(getResources(), R.drawable.target);
private Drawable[] layers = new Drawable[2];
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mPaint;
private int touch_counter = 0;
private long touchTime = -1;
private float oldDist = 1f;
private float oldfactor = 1f;
private float factor = 1f;
public myImage(Context context , FrameLayout screen) {
super(context);
super.setLayerType(LAYER_TYPE_HARDWARE, null);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF0000FF);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(2);
mPaint.setTextSize(20f);
super.setScaleType( ImageView.ScaleType.MATRIX );
mode = NONE;
matrix = new Matrix();
matrix.set(getImageMatrix());
savematrix = new Matrix();
start = new PointF();
mid = new PointF();
oldDist = 1f;
oldfactor = 1f;
factor = 1f;
}
public void freeImage() {
try {
mBitmap.recycle();
tracking.recycle();
} catch (Exception err) {
ImageExceptionHandler(err);
}
}
#Override
public void setImageBitmap(Bitmap bmp) {
try {
mBitmap = bmp;
mCanvas = new Canvas(bmp);
mCanvas.setBitmap(bmp);
} catch (Exception err) {
ImageExceptionHandler(err);
}
super.setImageBitmap(bmp);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if ( CURRENT_STATUS == "PAN & ZOOM" ) ScrollAndZoom(v , event);
else if ( CURRENT_STATUS == "DRAW_LINE" ) AddPoints(v , event);
else {
Log.w("ERROR" , "Should Never Be Here myImage On Touch");
Log.w("ERROR" , "Should Never Be Here myImage On Touch ["+eedsActivity.CURRENT_STATUS+"] ");
Log.w("ERROR" , "Should Never Be Here myImage On Touch ["+eedsActivity.CURRENT_IMAGE +"] ");
Log.w("ERROR" , "Should Never Be Here myImage On Touch");
}
return true;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.i("Image" , "Size Changed ["+w+"] x ["+h+"] ["+oldw+"] x ["+oldh+"] ");
super.onSizeChanged(w, h, oldw, oldh);
}
private void myDrawLine(PointF ptA , PointF ptB) {
mCanvas.drawBitmap(mBitmap , matrix , mPaint);
mPaint.setColor(Color.BLUE);
mCanvas.drawLine( ptA.x , ptA.y , ptB.x , ptB.y , mPaint);
if (ptA.x <= ptB.x ) mCanvas.translate( (ptA.x + 0.0f), (ptA.y + 0.0f) );
else mCanvas.translate( (ptA.x + 0.0f), (ptA.y + 0.0f) );
line newLine = new line(ptA , ptB , factor);
switch (newLine.getQuadrant()) {
case 1: mCanvas.rotate( (float) newLine.getAngle() ); break;
case 2: mCanvas.rotate( (newLine.getAngle() - 180.0f) ); break;
case 3: mCanvas.rotate( (newLine.getAngle() + 180.0f) ); break;
case 4: mCanvas.rotate( (float) newLine.getAngle() ); break;
}
String result = "";
mPaint.setColor(Color.YELLOW);
result = String.format("%4.3f mm", newLine.getDistance() );
mCanvas.drawText( result, ((newLine.getDistance() * line.PX_TO_MM) / 3.0f), -6.0f, mPaint);
invalidate();
}
public void recenter() {
oldDist = 1f;
oldfactor = 1f;
factor = 1f;
setBackgroundColor(Color.BLACK);
matrix.setScale(1f, 1f);
matrix.postTranslate(0f , 0f);
setImageMatrix(matrix);
}
private void AddPoints(View view , MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: touch_start(event.getX() , event.getY()); break;
case MotionEvent.ACTION_MOVE: touch_busy (event.getX() , event.getY()); break;
case MotionEvent.ACTION_UP: touch_end (event.getX() , event.getY()); break;
}
}
private void touch_start(float x, float y) {
touch_counter++;
busy.x = (x - 32.0f);
busy.y = (y - 70.0f);
LayoutParams lp = new LayoutParams(32 , 32);
pointer = new ImageView(super.getContext());
pointer.setBackgroundDrawable(getResources().getDrawable(R.drawable.target2));
lp.leftMargin = (int) x;
lp.topMargin = (int) y;
((ViewGroup) super.getParent()).addView(pointer , lp);
}
private void touch_busy(float x, float y) {
busy.x = (x - 32.0f);
busy.y = (y - 70.0f);
if (pointer != null) {
pointer.setLeft( (int)busy.x ); pointer.setRight ( (int)(busy.x+32) );
pointer.setTop ( (int)busy.y ); pointer.setBottom( (int)(busy.y+32) );
}
}
private void touch_end(float x, float y) {
((ViewGroup) super.getParent()).removeView(pointer);
if (touch_counter == 1) {
pointA = new PointF();
pointA.x = ((x - 32.0f));
pointA.y = ((y - 70.0f));
} else if (touch_counter == 2) {
pointB = new PointF();
pointB.x = ((x - 32.0f));
pointB.y = ((y - 70.0f));
}
if (touch_counter == 2) {
myDrawLine(pointA , pointB);
pointA = null; pointB = null;
pointC = null; touch_counter = 0;
}
}
private void ScrollAndZoom(View view , MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: if ((System.currentTimeMillis() - touchTime) < 400) {
// Double Click
touchTime = -1;
setBackgroundColor(Color.BLACK);
matrix.setScale(1f, 1f);
matrix.postTranslate(0f , 0f);
setImageMatrix(matrix);
} else {
// Single Click
touchTime = System.currentTimeMillis();
start.set(event.getX() , event.getY());
savematrix.set(matrix);
mode = DRAG;
}
break;
//------------------------------------------------
case MotionEvent.ACTION_POINTER_DOWN: touchTime = -1;
oldDist = distance(event);
midPoint(mid , event);
mode = ZOOM;
oldfactor = factor;
break;
//------------------------------------------------
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: start = new PointF();
mode = NONE;
matrix.set(getImageMatrix());
setBackgroundColor(Color.BLACK);
break;
//------------------------------------------------
case MotionEvent.ACTION_MOVE: matrix.set(savematrix);
if (mode == DRAG) {
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
setBackgroundColor(Color.BLACK);
matrix.postTranslate(dx, dy);
setImageMatrix(matrix);
} else if (mode == ZOOM) {
float newD = distance(event);
float newfactor = newD / oldDist;
factor = oldfactor * newfactor;
setBackgroundColor(Color.BLACK);
matrix.postScale(newfactor , newfactor , mid.x , mid.y);
setImageMatrix(matrix);
}
break;
//------------------------------------------------
}
}
private float distance(MotionEvent event) {
float dx = event.getX(1) - event.getX(0);
float dy = event.getY(1) - event.getY(0);
return FloatMath.sqrt(dx*dx + dy*dy);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2f , y / 2f);
}
private void ImageExceptionHandler(Exception err) {
Log.e("image" , "==============================================");
Log.e("image" , "EXCEPTION Handling ");
Log.e("image" , "==============================================");
err.printStackTrace();
}
}
It looks to me like pointB is always null, because you only ever get one ACTION_DOWN per gesture. When the first finger goes down, you get the action, and it triggers touch_start(), setting touch_counter to 1. When the second finger goes down, it doesn't, because you get an ACTION_POINTER_DOWN instead, which isn't checked for.
That's assuming you want a two-finger gesture. If it's meant to be a 'touch here and then touch there' instead, then you shouldn't set touch_counter to zero with each touch_end().
Your line is only drawn when STATE is 'MARKING'; at the end of onDraw you're setting your state back to UNKNOWN which calls the base class's onDraw but doesn't draw your line. If you want your line to stick around in other states, you'll have to redraw it every time onDraw gets called.