19

If i have an ImageView that fills the screen.
The ImageView background is set to green color.
I place a bitmap in the ImageView, keeping bitmap proportions.

A portrait photo in this layout will show green on both left and right side
(Phone orientation= portrait).

Now, How do i get the left side x/y position of the edge when the green ends and bitmap begins.

The background for this endeavor project is that i want to write text on the image and save the image back to a new image with the text. The problem is..

Since I scale the image inSampleSize = 4; and the ImageView shrinking it even more, saving this new picture will give a small small approx 250x350 image.

What i want is to use the x/y positions and transfer the written text to the original inSampleSize = 4 image or to the sdcard 1500x3000 image

I know and read other questions about this that i have to "Do the math calculations" myself I just need this small answer.

I forgot i can take a screenshot to clarify.

this is what it look like: (I get a new pen on pressing the button "pen" each pen hold its own unique text and position on the screen

enter image description here

Here is the imageview

    import java.util.HashMap;
    import java.util.UUID;
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Point;
    import android.graphics.Rect;
    import android.graphics.Typeface;
    import android.graphics.drawable.BitmapDrawable;
    import android.graphics.drawable.Drawable;
    import android.os.Environment;
    import android.util.AttributeSet;
    import android.view.Display;
    import android.view.MotionEvent;
    import android.widget.EditText;
    import android.widget.ImageView;

    public class DrawView2 extends ImageView {

        private HashMap<String, ColorBall2> HashBall ;
        private String balID = ""; // variable to know what ball is being dragged
        public final String PTPPSERVICE_DERECTORY = "/PTPPservice/";    
        private Bitmap bitmap;
        private EditText ed;
        private Paint paint = new Paint();
        private Paint paint2 = new Paint();
        private Paint pTouch = new Paint();
        private EditText addtext;
        private Context ctx;
        private String imagePath;
        private boolean removeBall = false;
      int viewWidth = 0;
        int viewHeight = 0;
        double bitmapHight =0;
        double bitmapWidth =0;  
        double ratio =0;

        double startX = 0;
        double endX= 0;
        double startY= 0;
        double endY = 0;

        public DrawView2(Context context, AttributeSet atts,String image1) {

            super(context, atts);
            this.ctx = context;
            this.imagePath = image1;
            setFocusable(true);

            paint.setStyle(Paint.Style.FILL_AND_STROKE);
            paint.setColor(Color.BLACK);
            paint.setTypeface(Typeface.DEFAULT_BOLD); 

            paint2.setStyle(Paint.Style.FILL_AND_STROKE);
            paint2.setColor(Color.RED);

          addtext = (EditText) ((Activity) ctx).findViewById(R.id.edittextaddtext); 

            String filePath = Environment.getExternalStorageDirectory().toString() + imagePath;
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = 4;

            bitmap = BitmapFactory.decodeFile(filePath,options);
            // SAVE RATIO
            int x = bitmap.getWidth();
            int y = bitmap.getHeight();
            if(y>x)
                ratio = ((double)y)/x;
            if(x>y)
                ratio = ((double)x)/y;  
            if(y==x)
                ratio = 1;
            Drawable bit = new BitmapDrawable(bitmap);
            setImageDrawable(bit);

        }
        public double getRatio() {
            return ratio;
        }
        public HashMap<String, ColorBall2> getHashBall() {
            return HashBall;
        }
        // RETURN THE ON SCREEN RESIZED BITMAP
        public double getOnScreenBitmapHight(){

            return bitmapHight;
        }
        public double getOnScreenBitmapWidth(){

            return  bitmapWidth;
        }
        // BITMAP SIZE
        public int getBitmapHight(){

            return bitmap.getHeight();
        }
        public int getBitmapWidth(){

            return  bitmap.getWidth();
        }
        // GET IMAGEVIEW HIGHT WIDTH
        public int getViewWidth() {
            return viewWidth;
        }
        public int getViewHeight() {
            return viewHeight;
        }
        // START END X Y
        public double getStartX() {
            return startX;
        }
        public double getEndX() {
            return endX;
        }
        public double getStartY() {
            return startY;
        }
        public double getEndY() {
            return endY;
        }
        // SET BALL TEXT
        public void addTextToBall(String text) {
            if(balID != "")
            HashBall.get(balID).setText(text);
        }
        // PATH
        public String getImagePath() {
            return imagePath;
        }
        // THE ORIGINAL INSAMPELSIZE=4 BITMAP
        public Bitmap getBitmap() {
            return bitmap;
        }
        // STOP DRAWAING THE BALL
        public void removeBall(boolean value) {
           removeBall = value;      
        }   
        // THE RECT THAT RETURN WRONG VALUE
        public Rect getRect(){

            Rect r = getDrawable().copyBounds();

            int drawLeft = r.left;
            int drawTop = r.top;
            int drawRight = r.right;
            int drawBottom = r.bottom;
            return r;
        }

        @Override
        protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld){
            super.onSizeChanged(xNew, yNew, xOld, yOld);
            viewWidth = xNew;
            viewHeight = yNew;
        }

        public void addBall(){

// HERE I TRY TO CALCULATE THE BOUNDS LEFT,RIGHT,TOP AND BOTTOM EDGE OF THE BITMAP
//NOT GOING THAT GOOD
            if(HashBall == null)
                HashBall = new HashMap<String,ColorBall2>();

            //X
            double drawAbleWidth = viewWidth/ratio;
            startX = (viewWidth-drawAbleWidth)/2;

            double drawAbleHight = viewHeight/ratio;
            startY = drawAbleHight/2;

            int ballY = (viewHeight/2); 
            int ballX = (viewWidth/2);

            Point point1 = new Point();
            point1.x = (int) ballX;
            point1.y = (int) ballY;
            String uuId = UUID.randomUUID().toString();
            HashBall.put(uuId,(new ColorBall2(ctx,R.drawable.pen1, point1,uuId)));  


        }

        @Override 
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);


            //canvas.drawCircle(10,10,10,null);
            if(!removeBall && HashBall != null){
                for (String key : HashBall.keySet()) {
                    //System.out.println("Key: " + key + ", Value: " + map.get(key));
                    if(addtext!=null)
                        //canvas.drawCircle(HashBall.get(key).getX(),      HashBall.get(key).getY(), 10, paint2);
                        canvas.drawBitmap(HashBall.get(key).getBitmap(), HashBall.get(key).getX()-10, HashBall.get(key).getY()-80, null);
                      canvas.drawText  (HashBall.get(key).getText() + "  X="+HashBall.get(key).getX() + "  Y="+HashBall.get(key).getY()
                                , HashBall.get(key).getX(), HashBall.get(key).getY(), paint);
                }

            }

        }


        // events when touching the screen
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int eventaction = event.getAction(); 


            int X = (int)event.getX(); 
            int Y = (int)event.getY(); 

            switch (eventaction ) 
            { 

            case MotionEvent.ACTION_DOWN: // touch down so check if the finger is on a ball
                balID = "";
                for (String key : HashBall.keySet()) {

                    // check if inside the bounds of the ball (circle)
                    // get the center for the ball
                    int centerX = HashBall.get(key).getX() + 15;
                    int centerY = HashBall.get(key).getY() + 15;

                    // calculate the radius from the touch to the center of the ball
                    double radCircle  = Math.sqrt( (((centerX-X)*(centerX-X)) + (centerY-Y)*(centerY-Y)));

                    // if the radius is smaller then 23 (radius of a ball is 22), then it must be on the ball
                    if (radCircle < 33){
                        balID = HashBall.get(key).getID();
                        addtext.setText(HashBall.get(key).getText());
                        break;
                    }
                }

                break; 


            case MotionEvent.ACTION_MOVE:   // touch drag with the ball
                // move the balls the same as the finger
                if (balID != "") {
                    HashBall.get(balID).setX(X-25);
                    HashBall.get(balID).setY(Y-25);

                }
                break; 

            case MotionEvent.ACTION_UP: 
                // touch drop - just do things here after dropping

                break; 
            } 
            // redraw the canvas
            invalidate(); 
            return true; 
        }
    }
Erik
  • 5,039
  • 10
  • 63
  • 119

4 Answers4

28

Here is a method I wanted to share, it will return the offset of the bitmap inside an imageView using getImageMatrix

public static int[] getBitmapOffset(ImageView img,  Boolean includeLayout) {
        int[] offset = new int[2];
        float[] values = new float[9];

        Matrix m = img.getImageMatrix();
        m.getValues(values);

        offset[0] = (int) values[Matrix.MTRANS_Y];
        offset[1] = (int) values[Matrix.MTRANS_X];

        if (includeLayout) {
            ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) img.getLayoutParams();
            int paddingTop = (int) (img.getPaddingTop() );
            int paddingLeft = (int) (img.getPaddingLeft() );

            offset[0] += paddingTop + lp.topMargin;
            offset[1] += paddingLeft + lp.leftMargin;
        }
        return offset;
    }
Bugs Happen
  • 2,169
  • 4
  • 33
  • 59
Shlomi Schwartz
  • 8,693
  • 29
  • 109
  • 186
  • 1
    This is easy and effective way. Wonder why this couldn't catch attention. +1 from my side. – Pawan Dec 17 '12 at 10:34
  • @ShlomiSchwartz It is not giving the proper top and left offset. I have one image as a source inside imageview. ImageView is in centered parent. when i call this method to get the top left position of a bitmap it is not giving me the proper offset from top left corner. – Kutbi May 24 '19 at 18:48
25

If you know the ratios you can just derive the width of the margin that will be placed to the side of the image.

// These holds the ratios for the ImageView and the bitmap
double bitmapRatio  = ((double)bitmap.getWidth())/bitmap.getHeight()
double imageViewRatio  = ((double)imageView.getWidth())/imageView.getHeight()

Now, if the bitmapRatio is larger than the imageViewRatio, you know that this means that the bitmap is wider than the imageview if they have an equal height. In other words, you'll have blanks on the top & bottom.

Conversely, if bitmapRatio is smaller than imageViewRatio then you'll have blanks to the left and right. From this you can get one of the co-ordinates pretty trivially as it'll be 0!

if(bitmapRatio > imageViewRatio)
{
  drawLeft = 0;
}
else
{
  drawTop = 0;
}

To get the other co-ordinate, think about the second case where you have space left & right. Here the heights of the the bitmap and imageView are equal and thus the ratio between the widths is equal to ratio between the ratios. You can use this to figure out width of the bitmap as you know the width of the imageView. Similarly you can figure out the heights if the width are equal, except that you have to use the inverse of the ratio between the ratios as the width is inversely proportional the the ratio:

if(bitmapRatio > imageViewRatio)
{
  drawLeft = 0;
  drawHeight = (imageViewRatio/bitmapRatio) * imageView.getHeight();
}
else
{
  drawTop = 0;
  drawWidth = (bitmapRatio/imageViewRatio) * imageView.getWidth();
}

Once you have the width or height of the bitmap, getting the space to the side is simple, it is just half the difference between the bitmap and imageView width or height:

if(bitmapRatio > imageViewRatio)
{
  drawLeft = 0;
  drawHeight = (imageViewRatio/bitmapRatio) * imageView.getHeight();
  drawTop = (imageView.getHeight() - drawHeight)/2;
}
else
{
  drawTop = 0;
  drawWidth = (bitmapRatio/imageViewRatio) * imageView.getWidth();
  drawLeft = (imageView.getWidth() - drawWidth)/2;
}
pheelicks
  • 7,461
  • 2
  • 45
  • 50
  • thanks i will work with this. I hope you got the bounty 50+. I cannot see the bounty maybe it expire, please advice! – Erik May 26 '11 at 20:10
  • 1
    I think the bounty expired, but no worries – pheelicks May 26 '11 at 20:27
  • 3
    I am looking for the same thing - but why on earth is the only solution SO damn complicated? The ImageView itself must know where it places the image - so why do I have to "recalculate" that exact same thing? Where's the getter of the ImageView to determine offset and size? Getting really annoyed by Android API by now... :( – Zordid Sep 04 '11 at 14:15
  • Don't see why you find it's complicated. If you don't care how the code works, then just copy-pasting the above is as easy as using an API call - it's only a couple of lines of code... – pheelicks Sep 06 '11 at 04:40
3

You should be able to get the (x, y) coordinates of the drawable inside, if that's what you're looking for. Try this:

ImageView img = (ImageView)findViewById(R.id.img);
Rect r = img.getDrawable().getBounds();

int drawLeft = r.left;
int drawTop = r.top;
int drawRight = r.right;
int drawBottom = r.bottom;

drawLeft is your X value.

drawTop is your Y value.

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • Yes that's what i was thinking, android have .getBounds() nice thanks will test it and get back to accept answer – Erik May 16 '11 at 21:42
  • from that code i get drawBottom = 648 but the image in the picture is only 374, the @Override onSizeChanged returns 374. drawLeft=0, drawTop=0. In the piture above x=31. thats what i want – Erik May 16 '11 at 21:50
  • drawBottom should be the absolute Y position of the image on screen, so that might be right. Not sure about why drawLeft is showing zero. Depends when you call it, though. I'm not sure if the drawable itself has been measured in `onSizeChanged()`. – Kevin Coppock May 16 '11 at 22:04
  • I notice something, The inSampleSize = 4 bitmap is saved as a field and the hight=648 and width=388. Same as r.bottom=648. But r.right=388 and r.left=0. This make no sense. Maybe i have to do the calculation based om some Ratio value from inSampleSize = 4 bitmap. This feels unpredictable dunno. you say - "Depends when you call it". Im caling it when i create a new ball and i see with breakpoint that onSizeChanged is not involved – Erik May 17 '11 at 05:40
  • Sorry about the last comment, kind of BRAINI(thinking loud). well onSizeChanged = 289x374 and i have the bitmap ratio, that gives me data to make calculations where the on-screen image is positioned. It's on-screen image location is center so that should be easy, will try... – Erik May 17 '11 at 05:49
  • Try measuring it within a click listener somewhere. Everything is drawn at that point, so `getBounds()` should certainly return the correct values at that point. – Kevin Coppock May 17 '11 at 12:23
  • @kcoppock Im trying in listener but left=0. Looks like it return the ImageView width/hight only, dunno – Erik May 18 '11 at 20:36
  • I have tried for 2 days now trying to get the drawLeft. Maybe im all wrong in this. from the above picture Im expecting drawLeft to be like 30 but it's always null. bottom and right is 648, 388 and that is the Bitmap size., Someone know? – Erik May 19 '11 at 16:59
0

Had a lottt of trouble with that myself, turns out to be actually quite simple :)

float points[] = {bitmap.getWidth()/2,bitmap.getHeight()/2}; matrix.mapPoints(points); matrix.postScale(scale, scale, points[0], points[1]);

Gilad
  • 17
  • 1