在滚动视图内缩放旋转图像以适合(填充)叠加矩阵的帧

时间:2014-11-09 03:02:49

标签: ios objective-c uiscrollview cgaffinetransform

通过this question and answer我现在有了一种工作方法,可以检测任意旋转的图像何时不在裁剪矩形之外。

下一步是弄清楚如何正确调整它包含滚动视图缩放以确保裁剪矩形内没有空格。为了澄清,我想放大(放大)图像;作物直肠应该保持不变形。

布局层次结构如下所示:

containing UIScrollView
    UIImageView (this gets arbitrarily rotated)
        crop rect overlay view

... UIImageView也可以在scrollView中进行缩放和平移。

有4个手势事件需要考虑:

  1. 平移手势(已完成):通过检测是否已错误平移并重置contentOffset来完成。
  2. 旋转CGAffineTransform
  3. 滚动视图缩放
  4. 调整裁剪矩形覆盖框架
  5. 据我所知,我应该可以使用2,3和4的相同逻辑来调整滚动视图的zoomScale,以使图像正确匹配。

    如何正确计算使旋转的图像完全适合裁剪矩形所需的缩放比率?

    为了更好地说明我想要完成的任务,下面是一个不正确尺寸的示例:

    enter image description here

    我需要计算所需的缩放比例,使其看起来像这样:

    enter image description here

    这是我到目前为止使用的Oluseyi解决方案的代码。当旋转角度很小(例如小于1弧度)时,它可以工作,但除此之外的任何东西都会变得非常糟糕。

    CGRect visibleRect = [_scrollView convertRect:_scrollView.bounds toView:_imageView];
    CGRect cropRect = _cropRectView.frame;
    
    CGFloat rotationAngle = fabs(self.rotationAngle);
    
    CGFloat a = visibleRect.size.height * sinf(rotationAngle);
    CGFloat b = visibleRect.size.width * cosf(rotationAngle);
    CGFloat c = visibleRect.size.height * cosf(rotationAngle);
    CGFloat d = visibleRect.size.width * sinf(rotationAngle);
    
    CGFloat zoomDiff = MAX(cropRect.size.width / (a + b), cropRect.size.height / (c + d));
    CGFloat newZoomScale = (zoomDiff > 1) ? zoomDiff : 1.0 / zoomDiff;
    
    [UIView animateWithDuration:0.2
                          delay:0.05
                        options:NO
                     animations:^{
                             [self centerToCropRect:[self convertRect:cropRect toView:self.zoomingView]];
                             _scrollView.zoomScale = _scrollView.zoomScale * newZoomScale;
                     } completion:^(BOOL finished) {
                         if (![self rotatedView:_imageView containsViewCompletely:_cropRectView]) 
                         {
                             // Damn, it's still broken - this happens a lot
                         }
                         else
                         {
                             // Woo! Fixed
                         }
                         _didDetectBadRotation = NO;
                     }];
    

    注意我正在使用AutoLayout,这会使帧和边界变得愚蠢。

3 个答案:

答案 0 :(得分:9)

假设您的图像矩形(图中的蓝色)和裁剪矩形(红色)具有相同的纵横比和中心。旋转时,图像矩形现在有一个边界矩形(绿色),这是您希望裁剪缩放到的(有效地,缩小图像)。

要有效扩展,您需要知道新边界矩形的尺寸,并使用适合裁剪矩形的比例因子。边界矩形的尺寸显然是

(a + b) x (c + d)

请注意,每个分段a,b,c,d是由边界矩形和旋转后的图像矩形形成的直角三角形的相邻或相对侧。

a = image_rect_height * sin(rotation_angle)
b = image_rect_width * cos(rotation_angle)
c = image_rect_width * sin(rotation_angle)
d = image_rect_height * cos(rotation_angle)

您的比例因子只是

MAX(crop_rect_width / (a + b), crop_rect_height / (c + d))

这是参考图:

enter image description here

答案 1 :(得分:3)

填充叠加矩阵的框架:

对于方形裁剪,您需要知道旋转图像的新边界,这将填充裁剪视图。

让我们来看看参考图: the reference diagram 您需要找到直角三角形的高度(图像编号2)。两个高度相等。

CGFloat sinAlpha = sin(alpha);
CGFloat cosAlpha = cos(alpha);
CGFloat hypotenuse = /* calculate */;
CGFloat altitude = hypotenuse * sinAlpha * cosAlpha;

然后,您需要计算旋转图像的新宽度和所需的比例因子,如下所示:

 CGFloat newWidth = previousWidth + altitude * 2;
 CGFloat scale = newWidth / previousWidth;

我已实施此方法here

答案 2 :(得分:0)

我将使用示例代码回答,但基本上这个问题变得非常简单,如果你想在旋转视图坐标系中。

Dim values = {cavityPairAStatus, cavityPairBStatus, cavityPairCStatus, cavityPairDStatus}
If values.Any(Function(v) v.Equals("PASS")) AndAlso values.All(Function(v) v.Equals("PASS") OrElse v.Equals("N/A")) Then
   …
End If