0

I'm loading images of various sizes inside an UIImageView. Some one the images come with annotations, each annotation has a unique position in the image. The annotation coordinates are relative to the original image size.

How do I transform the coordinates so the annotation show up at the same position in the UIImageView after resizing?

I could use AVMakeRectWithAspectRatioInsideRect to calculate the new position, but this only works with ScaleAspectFit and not ScaleAspectFill which I must use.

petard
  • 333
  • 1
  • 11

1 Answers1

3

You need to:

  • calculate the aspectRatio for aspectFill
  • multiply the x,y coords for your annotation by the aspectRatio
  • adjust that point by the amount of the image that extends outside the view frame

This is one way to do it (a little verbose, for clarity):

func aspectFillPoint(for point: CGPoint, in view: UIImageView) -> CGPoint {

    guard let img = view.image else {
        return CGPoint.zero
    }

    // imgSize will be modified
    var imgSize = img.size

    let viewSize = view.frame.size

    let aspectWidth  = viewSize.width / imgSize.width
    let aspectHeight = viewSize.height / imgSize.height

    // calculate aspectFill ratio
    let f = max(aspectWidth, aspectHeight)

    // scale imgSize
    imgSize.width *= f
    imgSize.height *= f

    // unless aspect ratio of view is the same as image,
    // it will either extend above and below or left and right
    // of the view frame
    let xOffset = (viewSize.width - imgSize.width) / 2.0
    let yOffset = (viewSize.height - imgSize.height) / 2.0

    // scale the original point, and adjust for offsets
    return CGPoint(
        x: (point.x * f) + xOffset,
        y: (point.y * f) + yOffset
        )

}

Assuming you have an image assigned to theImageView, which is set to .scaleAspectFill, you can call it like this:

let annotationPoint = CGPoint(x: 232, y: 148)

var newPoint = aspectFillPoint(for: annotationPoint, in: theImageView)

// Note: newPoint is relative to the View Bounds, so unless the
// imageView is at 0,0 we need to adjust for position
newPoint.x += theImageView.frame.origin.x
newPoint.y += theImageView.frame.origin.y
DonMag
  • 69,424
  • 5
  • 50
  • 86
  • thanks a lot! don't you need to account for the difference between original image size and destination uiimageview? like in this [post](https://stackoverflow.com/questions/43720720/how-to-crop-a-uiimageview-to-a-new-uiimage-in-aspect-fill-mode) – petard Aug 21 '17 at 14:53
  • "Accounting for the difference" is exactly what this code is doing. Put it into a project - or a storyboard - and see for yourself. – DonMag Aug 21 '17 at 15:21