Преобразование точек с изображения в точки UIImageView, contentMode-aware

Скажем, у меня есть изображение (например, 1024 x 768 px), которое отображается в UIImageView (например, 300 x 300 пикселей). Теперь я хотел бы преобразовать точку из изображения, например. положение носа человека (x: 500, y: 600), в соответствующую точку на UIImageView с учетом его contentMode.

Если contentMode зафиксирован в UIViewContentModeScaleToFill, преобразование будет простым. Но если это UIViewContentModeScaleAspectFit, все становится более сложным.

Есть ли элегантный способ достичь этого? Я действительно не хочу вычислять это для каждого единственного contentMode (более 10, я думаю).

Спасибо!

Ответы

Ответ 1

Сегодня у меня было свободное время, чтобы собрать решение этой проблемы и опубликовать ее на GitHub: UIImageView-GeometryConversion

Это категория в UIImageView, которая предоставляет методы для преобразования точек и прямоугольников из изображения для просмотра координат и соблюдения всех 13 различных режимов содержимого.

Надеюсь, вам понравится!

Ответ 2

Это мое быстрое решение:

- (CGPoint)convertPoint:(CGPoint)sourcePoint fromContentSize:(CGSize)sourceSize {
    CGPoint targetPoint = sourcePoint;
    CGSize  targetSize  = self.bounds.size;

    CGFloat ratioX = targetSize.width / sourceSize.width;
    CGFloat ratioY = targetSize.height / sourceSize.height;

    if (self.contentMode == UIViewContentModeScaleToFill) {
        targetPoint.x *= ratioX;
        targetPoint.y *= ratioY;
    }
    else if(self.contentMode == UIViewContentModeScaleAspectFit) {
        CGFloat scale = MIN(ratioX, ratioY);

        targetPoint.x *= scale;
        targetPoint.y *= scale;

        targetPoint.x += (self.frame.size.width - sourceSize.width * scale) / 2.0f;
        targetPoint.y += (self.frame.size.height - sourceSize.height * scale) / 2.0f;
    }
    else if(self.contentMode == UIViewContentModeScaleAspectFill) {
        CGFloat scale = MAX(ratioX, ratioY);

        targetPoint.x *= scale;
        targetPoint.y *= scale;

        targetPoint.x += (self.frame.size.width - sourceSize.width * scale) / 2.0f;
        targetPoint.y += (self.frame.size.height - sourceSize.height * scale) / 2.0f;
    }

    return targetPoint;
}

- (CGRect)convertRect:(CGRect)sourceRect fromContentSize:(CGSize)sourceSize {
    CGRect targetRect = sourceRect;
    CGSize targetSize  = self.bounds.size;

    CGFloat ratioX = targetSize.width / sourceSize.width;
    CGFloat ratioY = targetSize.height / sourceSize.height;

    if (self.contentMode == UIViewContentModeScaleToFill) {
        targetRect.origin.x *= ratioX;
        targetRect.origin.y *= ratioY;

        targetRect.size.width *= ratioX;
        targetRect.size.height *= ratioY;
    }
    else if(self.contentMode == UIViewContentModeScaleAspectFit) {
        CGFloat scale = MIN(ratioX, ratioY);

        targetRect.origin.x *= scale;
        targetRect.origin.y *= scale;

        targetRect.origin.x += (self.frame.size.width - sourceSize.width * scale) / 2.0f;
        targetRect.origin.y += (self.frame.size.height - sourceSize.height * scale) / 2.0f;

        targetRect.size.width *= scale;
        targetRect.size.height *= scale;
    }
    else if(self.contentMode == UIViewContentModeScaleAspectFill) {
        CGFloat scale = MAX(ratioX, ratioY);

        targetRect.origin.x *= scale;
        targetRect.origin.y *= scale;

        targetRect.origin.x += (self.frame.size.width - sourceSize.width * scale) / 2.0f;
        targetRect.origin.y += (self.frame.size.height - sourceSize.height * scale) / 2.0f;

        targetRect.size.width *= scale;
        targetRect.size.height *= scale;
    }

    return targetRect;
}

Когда он будет реорганизован и оптимизирован, я опубликую его на github и отправлю ссылку здесь. Возможно, даже этот фрагмент может быть полезен для кого-то.

Ответ 3

Нет, нет встроенного, открытого или элегантного способа сделать это.

Вам нужно перепроектировать функции для режимов контента, в которых вы нуждаетесь.

Ответ 4

Почему вы не можете просто перемасштабировать координаты:

X (UIImageView) = (X (изображение)/1024) * 300

и

Y (UIImageView) = (Y (изображение)/768) * 300