gesture-imageview icon indicating copy to clipboard operation
gesture-imageview copied to clipboard

Trying to make sense of position and scale values

Open mdpearce opened this issue 12 years ago • 6 comments

Hi, I'm just having a bit of difficulty figuring out the values to use for scale and position. I'm using a GestureImageViewListener and logging the values provided to onScale() and onPosition(), but don't see how they relate to the actual area of the image which is being displayed.

For example, I've got a 960x720 bitmap being displayed in my GestureImageView, and the width of the view is the full width of the screen (on my test device, 720). When the image is loaded with ScaleType.CENTER_CROP, and I scroll the GestureImageView so that the top-left corner of the bitmap is displayed at the top-left corner of the view, I get position values of x=632, y=474 and scale value of 2.6333334. Could you please tell me what these numbers are actually referring to, as I can't seem to figure it out.

Thanks

mdpearce avatar Jun 12 '12 05:06 mdpearce

I should point out, what I'm actually trying to find is the top-left corner of the underlying bitmap area which is currently being displayed.

mdpearce avatar Jun 12 '12 06:06 mdpearce

i was having the same problems. i was trying to get pixel coordinates on original picture from on-view coordinates, given x,y and scale. didn't work out and i dropped the feature. would like to try again if someone gives a hint. i tried looking at the source code, but i don't really understand canvas

edofic avatar Jun 12 '12 07:06 edofic

Here's how I accomplished that.

In GestureImageViewTouchListener at the bottom of: public GestureImageViewTouchListener(final GestureImageView image, int displayWidth, int displayHeight) {

I added: calculateTopLeft()

So that it would immediately scroll to the top left boundary.

protected void calculateTopLeft() { int effectiveWidth = Math.round( (float) imageWidth * currentScale ); int effectiveHeight = Math.round( (float) imageHeight * currentScale ); float diff = (float)(effectiveWidth - displayWidth) / 2.0f; float getLeft = centerX - diff; float diff2 = (float)(effectiveHeight - displayHeight) / 2.0f; float getTop = centerY + diff2; image.setPosition(getLeft, getTop); }

jaydoublay avatar Oct 06 '12 06:10 jaydoublay

And if you want it to always center X or Y, you can change

float getLeft = centerX - diff; to float getLeft = centerX;

or float getTop = centerY + diff2; to float getTop = centerY;

jaydoublay avatar Oct 06 '12 06:10 jaydoublay

Answer to original question by @mdpearce:

First off, thank you Jason for this great widget, it was just what I needed when I needed it.

I have been using gesture-imageview from Ruby via ruboto. I converted view click points to underlying bitmap and original image points like this:

(I realize most readers will be using Java, but this easy to read and convert as needed)

Tracking touch info in my GestureImageViewTouchListener:

class TouchListener
  attr_reader :info
  def initialize
    @info = OpenStruct.new
  end
  def onTouch x, y
    @info.xv = x
    @info.yv = y
  end
  def onScale s
    @info.s = s
  end
  def onPosition x,y
    @info.xp = x
    @info.yp = y
  end
end

My click listener takes that info and calculates bitmap and image points:

def image_view_on_click 
  info = @listener.info
  s = info.s                                                         # scale from bitmap to view
  xp, yp = [ info.xp, info.yp ]                                      # 'position' point = center of bitmap in view coordinates
  xv, yv = [ info.xv, info.yv ]                                      # click point in view coordinates
  wb, hb = [ @image_view.getImageWidth, @image_view.getImageHeight ] # bitmap width & height
  xo, yo = [ ( ( s * wb ) / 2  ) - xp, ( ( s * hb ) /  2  ) - yp ]   # offset translation from view to bitmap
  xb, yb = [ ( xv + xo ) / s, ( yv + yo ) / s ]                      # bitmap point from view point
  if xb >= 0 && yb >=0 && xb < wb && yb < hb
    xi, yi = [ ( xb * @image.sample ).round , ( yb * @image.sample).round ]  # scale bitmap point by inSampleSize for final image point
    xv, yv = [ xv.round, yv.round ]
    xb, yb = [ xb.round, yb.round ]
    log "point: view: #{xv},#{yv} bitmap: #{xb},#{yb} image: #{xi},#{yi}"
  else
    log "point outside bitmap"
  end
  true # consume click event
end

I would also guess that a more elegant solution is possible via the view matrix, perhaps inverting the matrix and using it to transform view points to bitmap points.

gfowley avatar Oct 12 '12 02:10 gfowley

In GestureImageView,

protected void computeStartingScale(int imageWidth, int imageHeight, int measuredWidth, int measuredHeight) { switch (getScaleType()) { case CENTER: startingScale = 1.0f; break;

    case CENTER_CROP:

        startingScale = Math.max((float) measuredHeight
                / (float) imageHeight, (float) measuredWidth
                / (float) imageWidth);

        startY =  (float) imageHeight * startingScale / 2; // add this line to make the image top_crop

        break;

...

yorkwang avatar Aug 23 '13 07:08 yorkwang