放大滚动视图内的旋转图像以适应(填充)覆盖矩形的框架

通过这个问题和答案,我现在已经有了一个检测任意旋转的图像何时不完全在裁剪矩之外的工作方法。

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

布局层次结构如下所示:

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

…其中UIImageView也可以在scrollView中缩放和平移。

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

  1. 平移手势(完成):通过检测是否被错误地平移并重置contentOffset来完成。
  2. 旋转CGAffineTransform
  3. 滚动视图缩放
  4. 修剪矩形覆盖框的调整

据我所知,我应该能够使用相同的逻辑2,3和4来调整scrollScale的滚动视图,使图像适合正确。

如何正确地计算使旋转的图像完全适合于裁剪内部所需的缩放比例?

为了更好地说明我想要完成的事情,下面是一个错误大小的例子:

在这里输入图像说明

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

在这里输入图像说明

以下是我目前使用Oluseyi的解决scheme的代码。 它适用于旋转angular度较小(例如小于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使框架和边界愚蠢。

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

要有效地缩放,您需要知道新的边界矩形的尺寸,并使用适合剪裁的缩放因子。 边界矩形的尺寸相当明显

 (a + b) x (c + d) 

请注意,每个片段a,b,c,d都是由边界矩形和旋转的图像矩形组成的直angular三angular形的相邻边或相反边。

 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)) 

这是一个参考图:

在这里输入图像说明

填充覆盖矩形的框架:

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

我们来看看参考图: 参考图 你需要find一个直angular三angular形的高度(图像编号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; 

我在这里实现了这个方法。

我会回答使用示例代码,但基本上这个问题变得很容易,如果你会想在旋转视图坐标系统。

 UIView* container = [[UIView alloc] initWithFrame:CGRectMake(80, 200, 100, 100)]; container.backgroundColor = [UIColor blueColor]; UIView* content2 = [[UIView alloc] initWithFrame:CGRectMake(-50, -50, 150, 150)]; content2.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.5]; [container addSubview:content2]; [self.view setBackgroundColor:[UIColor blackColor]]; [self.view addSubview:container]; [container.layer setSublayerTransform:CATransform3DMakeRotation(M_PI / 8.0, 0, 0, 1)]; //And now the calculations CGRect containerFrameInContentCoordinates = [content2 convertRect:container.bounds fromView:container]; CGRect unionBounds = CGRectUnion(content2.bounds, containerFrameInContentCoordinates); CGFloat midX = CGRectGetMidX(content2.bounds); CGFloat midY = CGRectGetMidY(content2.bounds); CGFloat scaleX1 = (-1 * CGRectGetMinX(unionBounds) + midX) / midX; CGFloat scaleX2 = (CGRectGetMaxX(unionBounds) - midX) / midX; CGFloat scaleY1 = (-1 * CGRectGetMinY(unionBounds) + midY) / midY; CGFloat scaleY2 = (CGRectGetMaxY(unionBounds) - midY) / midY; CGFloat scaleX = MAX(scaleX1, scaleX2); CGFloat scaleY = MAX(scaleY1, scaleY2); CGFloat scale = MAX(scaleX, scaleY); content2.transform = CGAffineTransformScale(content2.transform, scale, scale);