2

我敢肯定,这个问题已经从各种不同的角度被问过很多次了,但我还无法在这里找到答案。

我想要实现 我想要做的是显示一个 UIImage,并允许用户在图像上绘制一个矩形,并最终裁剪他们的选择。

到目前为止的研究, 我在这里找到了关于处理裁剪的 SO 的先前问题,但是它们通常处理不变的静态裁剪区域,这确实导致了这种机制的以下限制

  1. 您感兴趣的图像区域可能位于任何位置,例如,如果您要裁剪路标,它可能位于一张图像的中心,但在另一张图像上左对齐,因此您无法预测哪个区域作物。
  2. 感兴趣区域的大小和比例可能会发生变化,例如,一张图像可能是该路标的特写,因此裁剪区域会更大,但另一张图像可能是从远处拍摄的,这意味着裁剪区域会更小。

结合上述两个变量,几乎不可能准确预测图像中感兴趣的区域在哪里,所以我依靠用户通过能够在我们周围“绘制”一个框来定义这一点'在这种情况下,对路标感兴趣。

这在 Android 上非常好,因为您可以将所有艰苦的工作委派给一个好的意图,例如:

Intent intent = new Intent("com.android.camera.action.CROP");

但是,我找不到适用于 iOS 的等价物。

我从这个来源找到了这段代码:

- (UIImage *)imageByDrawingCircleOnImage:(UIImage *)image
{
    // begin a graphics context of sufficient size
    UIGraphicsBeginImageContext(image.size);

    // draw original image into the context
    [image drawAtPoint:CGPointZero];

    // get the context for CoreGraphics
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // set stroking color and draw circle
    [[UIColor redColor] setStroke];

    // make circle rect 5 px from border
    CGRect circleRect = CGRectMake(0, 0,
                image.size.width,
                image.size.height);
    circleRect = CGRectInset(circleRect, 5, 5);

    // draw circle
    CGContextStrokeEllipseInRect(ctx, circleRect);

    // make image out of bitmap context
    UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();

    // free the context
    UIGraphicsEndImageContext();

    return retImage;
}

我认为这是裁剪的一个很好的起点(但是它确实有麦田圈),它确实依赖于在调用时预定义要裁剪的区域CGRectMake

这个previous question还详细说明了如何进行实际裁剪。

我假设要允许用户绘制矩形,我需要与手势集成?

问题: 如何允许用户在图像视图上绘制矩形,以裁剪该区域?

4

2 回答 2

2

你可以试试BJImageCropper

一个简单的 UIView 子类,允许用户裁剪图像。如果你使用它,我很想知道!推特:@barrettjacobsen

于 2012-06-01T11:27:30.890 回答
0

这篇文章已经有 5 年的历史了,但未来的参考资料,这就是我设法完成它的方式。以下代码是Rob 的答案和一些图像裁剪的组合

此处使用 Xcode 9 和 Swift 4

  1. 添加 2 个视图控制器

为第一个视图控制器添加 ImageView 和 2 个按钮,为最后一个视图控制器添加另一个图像视图

在此处输入图像描述

将所有视图链接到源文件

  1. 视图控制器

    import UIKit
    
    extension UIView {
    func snapshot(afterScreenUpdates: Bool = false) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
    drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
    let image = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return image
    }
    }
    
    extension UIImage {
    func crop( rect: CGRect) -> UIImage {
    var rect = rect
    rect.origin.x*=self.scale
    rect.origin.y*=self.scale
    rect.size.width*=self.scale
    rect.size.height*=self.scale
    
    let imageRef = self.cgImage!.cropping(to: rect)
    let image = UIImage(cgImage: imageRef!, scale: self.scale, orientation: self.imageOrientation)
    return image
    }
    }
    

类视图控制器:UIViewController {

var rec: CGRect!
var cropImage: UIImage!
@IBOutlet weak var imageView: UIImageView!

private let shapeLayer: CAShapeLayer = {
    let _shapeLayer = CAShapeLayer()
    _shapeLayer.fillColor = UIColor.clear.cgColor
    _shapeLayer.strokeColor = UIColor.green.cgColor
    _shapeLayer.lineWidth = 2
    return _shapeLayer
}()

private var startPoint: CGPoint!

override func viewDidLoad() {
    super.viewDidLoad()
    imageView.layer.addSublayer(shapeLayer)
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    clear()
    startPoint = touches.first?.location(in: imageView)
}

func clear() {
    imageView.layer.sublayers = nil
    imageView.image = UIImage(named: "aa")
    imageView.layer.addSublayer(shapeLayer)
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let startPoint = startPoint, let touch = touches.first else { return }
    let point: CGPoint

    if let predictedTouch = event?.predictedTouches(for: touch)?.last {
        point = predictedTouch.location(in: imageView)
    } else {
        point = touch.location(in: imageView)
    }
    updatePath(from: startPoint, to: point)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let startPoint = startPoint, let touch = touches.first else { return }
    let point = touch.location(in: imageView)
    updatePath(from: startPoint, to: point)
    imageView.image = imageView.snapshot(afterScreenUpdates: true)
    shapeLayer.path = nil
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    shapeLayer.path = nil
}

private func updatePath(from startPoint: CGPoint, to point: CGPoint) {
    let size = CGSize(width: point.x - startPoint.x, height: point.y - startPoint.y)
    rec = CGRect(origin: startPoint, size: size)
    shapeLayer.path = UIBezierPath(rect: rec).cgPath
}
@IBAction func btnTapped(_ sender: Any) {
    clear()
}

@IBAction func btnCropTapped(_ sender: Any) {
    let newRec = CGRect(origin: CGPoint(x: rec.origin.x, y: rec.origin.y), size: rec.size)
    cropImage = imageView.image?.crop(rect: newRec)
    print(rec)
    print(newRec)
    self.performSegue(withIdentifier: "toImage", sender: nil)
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "toImage" {
        if let destination = segue.destination as? ImageViewController {
            destination.croppedImage = cropImage
        }
    }
}

}

于 2018-05-18T13:15:26.540 回答