问题描述
我正在尝试制作一个简单的图像橡皮擦工具,用户可以在其中擦除和恢复绘制到图像中,就像在此图像中一样:
经过多次尝试和测试,我在UI端使用以下代码实现了足够的“擦除”功能:
// Drawing code - on user touch
// `currentPath` is a `UIBezierPath` property of the containing class.
guard let image = pickedImage else { return }
UIGraphicsBeginImageContextWithOptions(imageView.frame.size,false,0)
if let context = UIGraphicsGetCurrentContext() {
mainImageView.layer.render(in: context)
context.addpath(currentPath.cgPath)
context.setBlendMode(.clear)
context.setlinewidth(translatedBrushWidth)
context.setLineCap(.round)
context.setLineJoin(.round)
context.setstrokeColor(UIColor.clear.cgColor)
context.strokePath()
let capturedImage = UIGraphicsGetimageFromCurrentimageContext()
imageView.image = capturedImage
}
UIGraphicsEndImageContext()
在用户修饰时,我对 currentPath
应用缩放变换,以全尺寸渲染带有剪切部分的图像,以保持 UI 性能。
我现在想弄清楚的是如何处理“恢复”功能。本质上,用户应该在擦除的部分上绘制以显示原始图像。
我试过查看 CGContextClipToMask
,但我不确定如何实现。
我还研究了在渲染实际图像之前实现这种“擦除/恢复”效果的其他方法,例如在图像上屏蔽 CAShapeLayer
,但在这种方法中恢复也成为一个问题。
非常感谢任何帮助,以及使用 UI 级别和渲染级别的路径擦除和恢复的替代方法。 谢谢!
解决方法
是的,我建议将 CALayer 添加到您的图像层作为蒙版。
您可以将遮罩层设为 CAShapeLayer
并在其中绘制几何形状,也可以使用简单的 CALayer
作为遮罩,其中遮罩层的 contents
属性是CGImage
。然后将不透明像素绘制到遮罩中以显示图像内容,或将透明像素绘制到“擦除”相应的图像像素中。
这种方法是硬件加速的,而且速度相当快。
处理橡皮擦功能的撤消/重做需要您收集对遮罩层的更改以及遮罩的先前状态。
编辑:
我创建了 a small demo app on Github 来展示如何使用 CGImage 作为图像视图上的遮罩
这是该项目的自述文件:
MaskableImageView
该项目演示了如何使用 CALayer
屏蔽 UIView
。
它定义了 UIImageView 的一个自定义子类,MaskableView
。
MaskableView
类具有包含 CALayer 的属性 maskLayer
。
MaskableView
在其 didSet
属性上定义了一个 bounds
方法,以便当视图的边界发生变化时,它会调整遮罩层的大小以匹配图像视图的大小。
MaskableView
有一个方法 installSampleMask
,它构建一个与图像视图大小相同的图像,大部分填充不透明的黑色,但中心有一个小矩形填充黑色,alpha 为0.7.半透明的中心矩形使图像视图部分透明并显示下面的视图。
演示应用程序在 MaskableView
中安装了几个子视图、Scampers 的示例图像、我的一只狗和一个 UILabel。它还在 MaskableView
下方安装了棋盘格图像,以便您可以更轻松地看到半透明部分。
MaskableView
具有 circleRadius
、maskDrawingAlpha
和 drawingAction
属性,用于让用户通过点击要更新的视图来擦除/取消擦除图像面具。
MaskableView
将 UIPanGestureRecognizer
和 UITapGestureRecognizer
附加到自身,操作为 gestureRecognizerUpdate
。 gestureRecognizerUpdate
方法从手势识别器中获取点击/拖动位置,并使用它在图像蒙版上绘制一个圆圈,该圆要么减少图像蒙版的 alpha(以部分擦除像素)或增加图像蒙版的 alpha(以使那些像素更不透明。)
MaskableView
的蒙版图很粗糙,仅用于演示目的。它绘制了一系列离散的圆圈,而不是根据用户的拖动手势将路径渲染到遮罩中。更好的解决方案是连接来自手势识别器的点,并使用它们将平滑曲线渲染到蒙版中。
应用程序的屏幕如下所示: