There have been many questions exactly like this. I have gone through them but couldn't get it working.
My Activity
public class MainActivity extends Activity {
private static final String TAG = "GT:MA";
private ImageView imageView;
Bitmap original;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "in onCreate method");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) this.findViewById(R.id.image);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
int resId = getResources().getIdentifier("beerl", "drawable", "com.sivaprasadvarma.grabtouch");
original = BitmapFactory.decodeResource(getResources(), resId, options);
Log.i(TAG, "original size after decoding: "
+ String.valueOf(original.getWidth()) + " / "
+ String.valueOf(original.getHeight()));
imageView.setImageBitmap(original);
imageView.setOnTouchListener(myOnTouchSelectingListener);
}
// I've implemented diff methods in answers here
// http://stackoverflow.com/questions/4933612/how-to-convert-coordinates-of-the-image-view-to-the-coordinates-of-the-bitmap
OnTouchListener myOnTouchSelectingListener =
new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
Log.i(TAG, "---------------------");
// 1st method
float eventX = event.getX();
float eventY = event.getY();
float[] eventXY = new float[] {eventX, eventY};
Log.i(TAG, "1: touched position: " + String.valueOf(eventX) + " / "
+ String.valueOf(eventY));
//2nd method
Matrix invertMatrix = new Matrix();
((ImageView)view).getImageMatrix().invert(invertMatrix);
invertMatrix.mapPoints(eventXY);
int x = Integer.valueOf((int)eventXY[0]);
int y = Integer.valueOf((int)eventXY[1]);
Log.i(TAG, "2: Inverted touch position by invMatrix: "
+ String.valueOf(x) + " / "
+ String.valueOf(y));
Drawable imgDrawable = ((ImageView)view).getDrawable();
Bitmap bitmap = ((BitmapDrawable)imgDrawable).getBitmap();
// make sure they are of same size
Log.i(TAG, "from getter drawable size: "
+ String.valueOf(bitmap.getWidth()) + " / "
+ String.valueOf(bitmap.getHeight()));
Log.i(TAG, "actual drawable size: "
+ String.valueOf(original.getWidth()) + " / "
+ String.valueOf(original.getHeight()));
//Limit x, y range within bitmap
if(x < 0){
x = 0;
}else if(x > bitmap.getWidth()-1){
x = bitmap.getWidth()-1;
}
if(y < 0){
y = 0;
}else if(y > bitmap.getHeight()-1){
y = bitmap.getHeight()-1;
}
// mapping them back to bitmap coordinates
Rect imageBounds = imgDrawable.getBounds();
//original height and width of the bitmap
int intrinsicHeight = imgDrawable.getIntrinsicHeight();
int intrinsicWidth = imgDrawable.getIntrinsicWidth();
Log.i(TAG, "intrinsic width / height: "
+ String.valueOf(intrinsicWidth) + " / "
+ String.valueOf(intrinsicHeight));
//height and width of the visible (scaled) image
int scaledHeight = imageBounds.height();
int scaledWidth = imageBounds.width();
//Find the ratio of the original image to the scaled image
//Should normally be equal unless a disproportionate scaling
float heightRatio = intrinsicHeight / scaledHeight;
float widthRatio = intrinsicWidth / scaledWidth;
// 3rd method
//get the distance from the left and top of the image bounds
int scaledImageOffsetX = Math.round(event.getX() - imageBounds.left);
int scaledImageOffsetY = Math.round(event.getY() - imageBounds.top);
//scale these distances according to the ratio of your scaling
//For example, if the original image is 1.5x the size of the scaled
//image, and your offset is (10, 20), your original image offset
//values should be (15, 30).
int originalImageOffsetX = Math.round(scaledImageOffsetX * widthRatio);
int originalImageOffsetY = Math.round(scaledImageOffsetY * heightRatio);
Log.i(TAG, "3: mapped position: "
+ String.valueOf(originalImageOffsetX) + " / "
+ String.valueOf(originalImageOffsetY));
//4th method
int inv_scaledImageOffsetX = x - imageBounds.left;
int inv_scaledImageOffsetY = y - imageBounds.top;
int inv_originalImageOffsetX = Math.round(inv_scaledImageOffsetX * widthRatio);
int inv_originalImageOffsetY = Math.round(inv_scaledImageOffsetY * heightRatio);
Log.i(TAG, "4: inv mapped position: "
+ String.valueOf(inv_originalImageOffsetX) + " / "
+ String.valueOf(inv_originalImageOffsetY));
int touchedRGB = bitmap.getPixel(x, y);
int org_touchedRGB = original.getPixel(x, y);
// 5th method
float[] point_coords = getPointerCoords((ImageView)view, event);
Log.i(TAG, "5: pointer coords position: "
+ String.valueOf(Math.round(point_coords[0])) + " / "
+ String.valueOf(Math.round(point_coords[1])));
Log.i(TAG, "getter touched color: " + "#" + Integer.toHexString(touchedRGB));
Log.i(TAG, "original touched color: " + "#" + Integer.toHexString(org_touchedRGB));
Log.i(TAG, "---------------------");
return true;
}
};
private final float[] getPointerCoords(ImageView view, MotionEvent e)
{
final int index = e.getActionIndex();
final float[] coords = new float[] { e.getX(index), e.getY(index) };
Matrix matrix = new Matrix();
view.getImageMatrix().invert(matrix);
matrix.postTranslate(view.getScrollX(), view.getScrollY());
matrix.mapPoints(coords);
return coords;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
My Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="horizontal" >
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:contentDescription="@string/descImage"
android:src="@drawable/beerl" />
</LinearLayout>
Basically I've implemented 5 ways to get the position of touched pixel in the activity and i'm logging them and I have only a ImageView in my layout. The size of my image is 960x540. so when i'm touching at approx'ly middle of the image I should get value close to 480/270, but i'm getting following in the log when i touch close to middle of image
7-16 11:00:50.097: I/GT:MA(3273): ---------------------
07-16 11:00:50.097: I/GT:MA(3273): 1: touched position: 330.0 / 166.0
07-16 11:00:50.097: I/GT:MA(3273): 2: Inverted touch position by invMatrix: 330 / 166
07-16 11:00:50.097: I/GT:MA(3273): from getter drawable size: 960 / 540
07-16 11:00:50.097: I/GT:MA(3273): actual drawable size: 960 / 540
07-16 11:00:50.097: I/GT:MA(3273): intrinsic width / height: 640 / 360
07-16 11:00:50.097: I/GT:MA(3273): 3: mapped position: 330 / 166
07-16 11:00:50.097: I/GT:MA(3273): 4: inv mapped position: 330 / 166
07-16 11:00:50.097: I/GT:MA(3273): 5: pointer coords position: 330 / 166
07-16 11:00:50.097: I/GT:MA(3273): getter touched color: #ffcd7d27
07-16 11:00:50.097: I/GT:MA(3273): original touched color: #ffcd7d27
07-16 11:00:50.097: I/GT:MA(3273): ---------------------
when I click near bottom right of image i'm getting the following in log
07-16 11:03:31.419: I/GT:MA(3273): ---------------------
07-16 11:03:31.419: I/GT:MA(3273): 1: touched position: 635.0 / 348.0
07-16 11:03:31.419: I/GT:MA(3273): 2: Inverted touch position by invMatrix: 635 / 348
07-16 11:03:31.419: I/GT:MA(3273): from getter drawable size: 960 / 540
07-16 11:03:31.419: I/GT:MA(3273): actual drawable size: 960 / 540
07-16 11:03:31.419: I/GT:MA(3273): intrinsic width / height: 640 / 360
07-16 11:03:31.419: I/GT:MA(3273): 3: mapped position: 635 / 348
07-16 11:03:31.419: I/GT:MA(3273): 4: inv mapped position: 635 / 348
07-16 11:03:31.429: I/GT:MA(3273): 5: pointer coords position: 635 / 348
07-16 11:03:31.429: I/GT:MA(3273): getter touched color: #ff242722
07-16 11:03:31.429: I/GT:MA(3273): original touched color: #ff242722
07-16 11:03:31.429: I/GT:MA(3273): ---------------------
the entire project is here[zip] in case if you want to take a clear look a the whole thing.
Why are the intrinsicWidth and intrinsicHeight different from actual width and height of BitmapDrawable. It looks like I'm getting correct value's If we assume that image has size intrinsicWidth X intrinsicHeight. Why is it so ? How to get correct bitmap coordinates of the pixel touched.