gpt4 book ai didi

ios - 如何在 iOS 的 UIImageView 中裁剪圆圈内的图像

转载 作者:IT王子 更新时间:2023-10-29 07:56:46 25 4
gpt4 key购买 nike

我有一个应用程序,其中有一个显示主图像的 UIImageView 和另一个用作 mask 的 UIImageView ,它显示一个透明的圆圈,外面是不透明的,这个圆圈可以使用 UIPanGestureRecognizer 移动,我想知道如何将圆圈内的图像裁剪成新图像。这是附加的代码和屏幕截图

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.

// create pan gesture

UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePan:)];
[self.view addGestureRecognizer:pan];


CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [[self makeCircleAtLocation:self.view.center radius:100.0] CGPath];
shapeLayer.strokeColor = [[UIColor clearColor] CGColor];
shapeLayer.fillColor = nil;
shapeLayer.lineWidth = 3.0;

// Add CAShapeLayer to our view

[self.view.layer addSublayer:shapeLayer];

// Save this shape layer in a class property for future reference,
// namely so we can remove it later if we tap elsewhere on the screen.

self.circleLayer = shapeLayer;
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// Create a UIBezierPath which is a circle at a certain location of a certain radius.
// This also saves the circle's center and radius to class properties for future reference.

- (UIBezierPath *)makeCircleAtLocation:(CGPoint)location radius:(CGFloat)radius
{
self.circleCenter = location;
self.circleRadius = radius;

UIBezierPath *path = [UIBezierPath bezierPath];
[path addArcWithCenter:self.circleCenter
radius:self.circleRadius
startAngle:0.0
endAngle:M_PI * 2.0
clockwise:YES];

return path;
}

- (void)handlePan:(UIPanGestureRecognizer *)gesture
{
static CGPoint oldCenter;

if (gesture.state == UIGestureRecognizerStateBegan)
{
// If we're starting a pan, make sure we're inside the circle.
// So, calculate the distance between the circle's center and
// the gesture start location and we'll compare that to the
// radius of the circle.

CGPoint location = [gesture locationInView:gesture.view];
CGPoint translation = [gesture translationInView:gesture.view];
location.x -= translation.x;
location.y -= translation.y;

CGFloat x = location.x - self.circleCenter.x;
CGFloat y = location.y - self.circleCenter.y;
CGFloat distance = sqrtf(x*x + y*y);

// If we're outside the circle, cancel the gesture.
// If we're inside it, keep track of where the circle was.


oldCenter = self.circleCenter;
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
// Let's calculate the new center of the circle by adding the
// the translationInView to the old circle center.

CGPoint translation = [gesture translationInView:gesture.view];
CGPoint newCenter = CGPointMake(oldCenter.x + translation.x, oldCenter.y + translation.y);

// CGPoint newCenter = [gesture locationInView:self.view];
if (newCenter.x < 160) {
newCenter.x = 160;
}
else if (newCenter.x > self.view.frame.size.width - 160) {
newCenter.x = self.view.frame.size.width - 160;
}
if (newCenter.y < 242) {
newCenter.y = 242;
}
else if (newCenter.y > self.view.frame.size.height - imageMain.center.y) {
newCenter.y = self.view.frame.size.height - imageMain.center.y;
}

// Update the path for our CAShapeLayer

// self.circleLayer.path = [[self makeCircleAtLocation:newCenter radius:self.circleRadius] CGPath];
imageCircle.center = newCenter;

}
}

@end

结果是

enter image description here

最佳答案

要保存蒙版图像,可以使用 drawHierarchy(in:afterScreenUpdates:) .您可能还想使用 cropping(to:) 裁剪图像.请参阅下面我的 handleTap 示例。

但我注意到您显然是通过叠加图像来进行遮蔽。我可能建议使用 UIBezierPath 作为 ImageView 图层蒙版的基础,以及用于绘制圆的 CAShapeLayer(假设您想要绘制圆圈时的边框。如果您的蒙版是规则形状(例如圆圈),则可能更灵活地使其成为带有 UIBezierPathCAShapeLayer(而不是而不是图像),因为这样你不仅可以用平移手势四处移动它,还可以用捏合手势缩放它:

enter image description here

这是一个示例实现:

//  ViewController.swift
// CircleMaskDemo
//
// Created by Robert Ryan on 4/18/18.
// Copyright © 2018-2022 Robert Ryan. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var pinch: UIPinchGestureRecognizer!
@IBOutlet weak var pan: UIPanGestureRecognizer!

private let maskLayer = CAShapeLayer()

private lazy var radius: CGFloat = min(view.bounds.width, view.bounds.height) * 0.3
private lazy var center: CGPoint = CGPoint(x: view.bounds.midX, y: view.bounds.midY)

private let pathLayer: CAShapeLayer = {
let _pathLayer = CAShapeLayer()
_pathLayer.fillColor = UIColor.clear.cgColor
_pathLayer.strokeColor = UIColor.black.cgColor
_pathLayer.lineWidth = 3
return _pathLayer
}()

override func viewDidLoad() {
super.viewDidLoad()

imageView.layer.addSublayer(pathLayer)
imageView.layer.mask = maskLayer
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(pinch)
imageView.addGestureRecognizer(pan)
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

updateCirclePath(at: center, radius: radius)
}

private var oldCenter: CGPoint!
private var oldRadius: CGFloat!
}

// MARK: - Actions

extension ViewController {
@IBAction func handlePinch(_ gesture: UIPinchGestureRecognizer) {
let scale = gesture.scale

if gesture.state == .began { oldRadius = radius }

updateCirclePath(at: center, radius: oldRadius * scale)
}

@IBAction func handlePan(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: gesture.view)

if gesture.state == .began { oldCenter = center }

let newCenter = CGPoint(x: oldCenter.x + translation.x, y: oldCenter.y + translation.y)

updateCirclePath(at: newCenter, radius: radius)
}

@IBAction func handleTap(_ gesture: UITapGestureRecognizer) {
let fileURL = try! FileManager.default
.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("image.png")

let scale = imageView.window!.screen.scale
let radius = self.radius * scale
let center = CGPoint(x: self.center.x * scale, y: self.center.y * scale)

let frame = CGRect(x: center.x - radius,
y: center.y - radius,
width: radius * 2.0,
height: radius * 2.0)

// temporarily remove the circleLayer

let saveLayer = pathLayer
saveLayer.removeFromSuperlayer()

// render the clipped image

let image = UIGraphicsImageRenderer(size: imageView.frame.size).image { _ in
imageView.drawHierarchy(in: imageView.bounds, afterScreenUpdates: true)
}

// add the circleLayer back

imageView.layer.addSublayer(saveLayer)

// crop the image

guard
let imageRef = image.cgImage?.cropping(to: frame),
let data = UIImage(cgImage: imageRef).pngData()
else {
return
}

// save the image

try? data.write(to: fileURL)

// tell the user we're done

let alert = UIAlertController(title: nil, message: "Saved", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
}

// MARK: - Private utility methods

private extension ViewController {
func updateCirclePath(at center: CGPoint, radius: CGFloat) {
self.center = center
self.radius = radius

let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
maskLayer.path = path.cgPath
pathLayer.path = path.cgPath
}
}

// MARK: - UIGestureRecognizerDelegate

extension ViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
let tuple = (gestureRecognizer, otherGestureRecognizer)
return tuple == (pan, pinch) || tuple == (pinch, pan)
}
}

如果您不想在圆周围绘制边框,那就更简单了,因为您可以拉取与 circleLayer 相关的任何内容。

如果您对 Objective-C 示例感兴趣,请参阅 previous revision of this answer .

关于ios - 如何在 iOS 的 UIImageView 中裁剪圆圈内的图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20165906/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com