将 UIScrollview 中显示的图像裁剪为覆盖层中显示的矩形

Posted

技术标签:

【中文标题】将 UIScrollview 中显示的图像裁剪为覆盖层中显示的矩形【英文标题】:Crop image displayed in UIScrollview to rect displayed in overlay 【发布时间】:2018-08-06 14:21:04 【问题描述】:

我一直在环顾四周,找不到问题的答案。我有一个带有嵌入式图像视图的滚动视图。您可以旋转和缩放图像。

视图层次结构如下所示:

|-> UIViewController
|--> UIView
|---> UIScrollView
|----> UIImageView

UIView 只是将控制器放在情节提要上时添加的默认视图。

我还在顶视图上绘制了一个叠加层,它看起来像这样:

我需要做的是将图像裁剪为叠加层的大小。叠加层是务实地创建的,但我保留了对用于方形中心的矩形的引用。用于生成叠加层的代码是:

 private void DrawOverlay()
    
        var overlayPath = UIBezierPath.FromRect(View.Bounds);

        // Calculate the size of the transparent area we need.
        var rectSize = View.Frame.Width * 80 / 100;
        nfloat clearStartX = View.Frame.GetMidX() - (rectSize / 2);
        nfloat clearWidth = View.Frame.Size.Width - (clearStartX * 2);
        nfloat clearStartY = View.Frame.GetMidY() - ((GetTopBarHeight() + rectSize) / 2);
        nfloat clearHeight = clearWidth;

        // Create the rectange for out transparent area;
        TransparentRect = new CGRect(clearStartX, clearStartY, clearWidth, clearHeight);

        var transparentPath = UIBezierPath.FromRect(TransparentRect);

        // Apply the transparent box to our overall view.
        overlayPath.AppendPath(transparentPath);
        overlayPath.UsesEvenOddFillRule = true;

        // Set the full colour.
        var fillLayer = new CAShapeLayer();
        fillLayer.Path = overlayPath.CGPath;
        fillLayer.FillRule = CAShapeLayer.FillRuleEvenOdd;
        fillLayer.FillColor = Colours.TransparentBackground.CGColor;

        View.Layer.AddSublayer(fillLayer);

        // Calculate the length of the white line we want.
        var lineWidth = rectSize * 20 / 100;

        // Create a bezier path based on the transparent rect we defined earlier, that and a combination of the line
        // width we can plot each point to draw the lines. Each MoveTo defines the start of a new corner.
        UIBezierPath path = new UIBezierPath();
        path.MoveTo(new CGPoint(clearStartX, clearStartY + lineWidth));
        path.AddLineTo(new CGPoint(clearStartX, clearStartY));
        path.AddLineTo(new CGPoint(clearStartX + lineWidth, clearStartY));

        path.MoveTo(new CGPoint((clearStartX + rectSize) - lineWidth, clearStartY));
        path.AddLineTo(new CGPoint(clearStartX + rectSize, clearStartY));
        path.AddLineTo(new CGPoint(clearStartX + rectSize, clearStartY + lineWidth));

        path.MoveTo(new CGPoint(clearStartX, (clearStartY + rectSize) - lineWidth));
        path.AddLineTo(new CGPoint(clearStartX, (clearStartY + rectSize)));
        path.AddLineTo(new CGPoint(clearStartX + lineWidth, (clearStartY + rectSize)));

        path.MoveTo(new CGPoint((clearStartX + rectSize) - lineWidth, (clearStartY + rectSize)));
        path.AddLineTo(new CGPoint((clearStartX + rectSize), (clearStartY + rectSize)));
        path.AddLineTo(new CGPoint((clearStartX + rectSize), (clearStartY + rectSize) - lineWidth));

        // Apply the path and set the width and colour.
        CAShapeLayer pathLayer = new CAShapeLayer();
        pathLayer.Path = path.CGPath;
        pathLayer.StrokeColor = UIColor.White.CGColor;
        pathLayer.LineWidth = 5.0f;
        pathLayer.FillColor = null;

        View.Layer.AddSublayer(pathLayer);
    

我尝试过像这样裁剪图像:

 var imageref = ImageView.Image.CGImage.WithImageInRect(TransparentRect);
 UIImage croppedImage = new UIImage(imageref);

这似乎也是这里大多数答案的方式。但是,这对我不起作用。首先,转换应用到滚动视图而不是图像视图,因为手势绑定到它,如下所示。

    public override void ViewDidLoad()
     
       base.ViewDidLoad();
       NavigationItem.Title = "Crop Image";

       var ButtonDone = new UIBarButtonItem("Done", 
       UIBarButtonItemStyle.Plain, (sender, e) =>
       
          CropImage();
       );  

       this.NavigationItem.SetRightBarButtonItem(ButtonDone, true);

       DrawOverlay();

       ScrollView.MinimumZoomScale = 1.0f;
       ScrollView.MaximumZoomScale = 5.0f;
       ScrollView.Delegate = this;
       ScrollView.ContentSize = new CGSize(ImageView.Frame.Size.Width, ImageView.Frame.Size.Height);
       var rotateGesture = new UIRotationGestureRecognizer((g) =>
       
          g.View.Transform = CGAffineTransform.Rotate(g.View.Transform, g.Rotation);
          g.Rotation = 0;
       );
       rotateGesture.Delegate = this;


       ScrollView.AddGestureRecognizer(rotateGesture);
    

    [Export("viewForZoomingInScrollView:")]
    public UIView ViewForZoomingInScrollView(UIScrollView scrollView)
    
       return ImageView;
    

[Export("gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:")]
    public bool ShouldRecognizeSimultaneously(UIGestureRecognizer gestureRecognizer, UIGestureRecognizer otherGestureRecognizer)
    
        return true;
    

那么如何将图像裁剪为透明覆盖矩形并保持缩放和旋转变换?

感谢您对此问题的任何帮助。

【问题讨论】:

【参考方案1】:

所以我设法使用找到的这个例子解决了这个问题here 和here。

其他一切都很好,只是在我们裁剪时处理两个视图之间的比例。

【讨论】:

你能分享你的解决方案吗?

以上是关于将 UIScrollview 中显示的图像裁剪为覆盖层中显示的矩形的主要内容,如果未能解决你的问题,请参考以下文章

UIScrollView中的drawRect裁剪

Objective-C:从 UIScrollView 获取缩放的裁剪图像

在 UIScrollView 问题中裁剪缩放图像

捕捉 UIScrollView 的可见部分后裁剪图像的透明部分

在 iPhone 中裁剪后 UIImage 显示模糊

以全分辨率从 UIScrollView 中捕获缩放的 UIImageView