背景图片和 canvas with pencilKit Swiftui
Background Image and canvas with pencilKit Swiftui
我正在学习 PencilKit。
我有一个canvas,我想设置一个我们可以在上面绘制的背景图片。
当我保存 canvas 时,我希望我的背景图片可见
但是我有一个错误:
无法将类型 'Image' 的值转换为预期的参数类型 'UIImage?'
Image("badmintoncourt") 是我资产中的图像
我找不到解决方法,但我可能没有以正确的方式将背景图片添加到 canvas
struct Home : View {
@State var canvas = PKCanvasView()
@Environment(\.undoManager) private var undoManager
@State var showingAlert = false
var body: some View{
NavigationView{
MyCanvas(canvasView: canvas)
.navigationTitle("Drawing")
.navigationBarTitleDisplayMode(.inline)
}
}
}
struct MyCanvas: UIViewRepresentable {
var canvasView: PKCanvasView
let picker = PKToolPicker.init()
func makeUIView(context: Context) -> PKCanvasView {
self.canvasView.tool = PKInkingTool(.pen, color: .black, width: 15)
self.canvasView.isOpaque = false
self.canvasView.backgroundColor = UIColor.clear
self.canvasView.becomeFirstResponder()
let imageView = Image("badmintoncourt")
let subView = self.canvasView.subviews[0]
subView.addSubview(imageView)
subView.sendSubviewToBack(imageView)
return canvasView
}
func updateUIView(_ uiView: PKCanvasView, context: Context) {
picker.addObserver(canvasView)
picker.setVisible(true, forFirstResponder: uiView)
DispatchQueue.main.async {
uiView.becomeFirstResponder()
}
}
}
编辑:
这是我保存图像的代码:
func SaveImage(){
let image = canvas.drawing.image(from: canvas.drawing.bounds, scale: 1)
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
Image
不是 UIView
,在这种情况下您必须使用 UIImageView
let imageView = UIImageView(image: UIImage(named: "badmintoncourt"))
let subView = self.canvasView.subviews[0]
subView.addSubview(imageView)
subView.sendSubviewToBack(imageView)
这就是我解决这个问题的方法,允许在图像上绘制并将两者保存在一个最终图像中。此解决方案使 canvas 用于绘制图像的大小。
我将 canvas 添加为图像的叠加层,并将绘图存储在单独的图像中。完成绘图后,我将两张图片合二为一。
struct DrawOnImageView: View {
@Binding var image: UIImage
let onSave: (UIImage) -> Void
@State private var drawingOnImage: UIImage = UIImage()
@State private var canvasView: PKCanvasView = PKCanvasView()
init(image: Binding<UIImage>, onSave: @escaping (UIImage) -> Void) {
self.image = image
self.onSave = onSave
}
var body: some View {
VStack {
Button(action: { save() }, label: Text("Save"))
Image(uiImage: self.image)
.resizable()
.aspectRatio(contentMode: .fit)
.edgesIgnoringSafeArea(.all)
.overlay(CanvasView(canvasView: $canvasView, onSaved: onChanged), alignment: .bottomLeading)
}
}
private func onChanged() -> Void {
self.drawingOnImage = canvasView.drawing.image(
from: canvasView.bounds, scale: UIScreen.main.scale)
}
private func initCanvas() -> Void {
self.canvasView = PKCanvasView();
self.canvasView.isOpaque = false
self.canvasView.backgroundColor = UIColor.clear
self.canvasView.becomeFirstResponder()
}
private func save() -> Void {
onSave(self.image.mergeWith(topImage: drawingOnImage))
}
}
UIImage 的这个扩展将允许您合并图像。我使用了这个答案中的代码
public extension UIImage {
func mergeWith(topImage: UIImage) -> UIImage {
let bottomImage = self
UIGraphicsBeginImageContext(size)
let areaSize = CGRect(x: 0, y: 0, width: bottomImage.size.width, height: bottomImage.size.height)
bottomImage.draw(in: areaSize)
topImage.draw(in: areaSize, blendMode: .normal, alpha: 1.0)
let mergedImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return mergedImage
}
}
最后,这是我的 canvas 观点,尽管我认为您的代码中的 MyCanvas 应该可以正常工作。我的观点基于 this PencilKit tutorial.
struct CanvasView {
@Binding var canvasView: PKCanvasView
let onSaved: () -> Void
@State var toolPicker = PKToolPicker()
}
extension CanvasView: UIViewRepresentable {
func makeUIView(context: Context) -> PKCanvasView {
canvasView.tool = PKInkingTool(.pen, color: .gray, width: 10)
#if targetEnvironment(simulator)
canvasView.drawingPolicy = .anyInput
#endif
canvasView.delegate = context.coordinator
showToolPicker()
return canvasView
}
func updateUIView(_ uiView: PKCanvasView, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator(canvasView: $canvasView, onSaved: onSaved)
}
}
private extension CanvasView {
func showToolPicker() {
toolPicker.setVisible(true, forFirstResponder: canvasView)
toolPicker.addObserver(canvasView)
canvasView.becomeFirstResponder()
}
}
class Coordinator: NSObject {
var canvasView: Binding<PKCanvasView>
let onSaved: () -> Void
init(canvasView: Binding<PKCanvasView>, onSaved: @escaping () -> Void) {
self.canvasView = canvasView
self.onSaved = onSaved
}
}
extension Coordinator: PKCanvasViewDelegate {
func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
if !canvasView.drawing.bounds.isEmpty {
onSaved()
}
}
}
我正在学习 PencilKit。
我有一个canvas,我想设置一个我们可以在上面绘制的背景图片。
当我保存 canvas 时,我希望我的背景图片可见
但是我有一个错误: 无法将类型 'Image' 的值转换为预期的参数类型 'UIImage?'
Image("badmintoncourt") 是我资产中的图像 我找不到解决方法,但我可能没有以正确的方式将背景图片添加到 canvas
struct Home : View {
@State var canvas = PKCanvasView()
@Environment(\.undoManager) private var undoManager
@State var showingAlert = false
var body: some View{
NavigationView{
MyCanvas(canvasView: canvas)
.navigationTitle("Drawing")
.navigationBarTitleDisplayMode(.inline)
}
}
}
struct MyCanvas: UIViewRepresentable {
var canvasView: PKCanvasView
let picker = PKToolPicker.init()
func makeUIView(context: Context) -> PKCanvasView {
self.canvasView.tool = PKInkingTool(.pen, color: .black, width: 15)
self.canvasView.isOpaque = false
self.canvasView.backgroundColor = UIColor.clear
self.canvasView.becomeFirstResponder()
let imageView = Image("badmintoncourt")
let subView = self.canvasView.subviews[0]
subView.addSubview(imageView)
subView.sendSubviewToBack(imageView)
return canvasView
}
func updateUIView(_ uiView: PKCanvasView, context: Context) {
picker.addObserver(canvasView)
picker.setVisible(true, forFirstResponder: uiView)
DispatchQueue.main.async {
uiView.becomeFirstResponder()
}
}
}
编辑: 这是我保存图像的代码:
func SaveImage(){
let image = canvas.drawing.image(from: canvas.drawing.bounds, scale: 1)
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
Image
不是 UIView
,在这种情况下您必须使用 UIImageView
let imageView = UIImageView(image: UIImage(named: "badmintoncourt"))
let subView = self.canvasView.subviews[0]
subView.addSubview(imageView)
subView.sendSubviewToBack(imageView)
这就是我解决这个问题的方法,允许在图像上绘制并将两者保存在一个最终图像中。此解决方案使 canvas 用于绘制图像的大小。
我将 canvas 添加为图像的叠加层,并将绘图存储在单独的图像中。完成绘图后,我将两张图片合二为一。
struct DrawOnImageView: View {
@Binding var image: UIImage
let onSave: (UIImage) -> Void
@State private var drawingOnImage: UIImage = UIImage()
@State private var canvasView: PKCanvasView = PKCanvasView()
init(image: Binding<UIImage>, onSave: @escaping (UIImage) -> Void) {
self.image = image
self.onSave = onSave
}
var body: some View {
VStack {
Button(action: { save() }, label: Text("Save"))
Image(uiImage: self.image)
.resizable()
.aspectRatio(contentMode: .fit)
.edgesIgnoringSafeArea(.all)
.overlay(CanvasView(canvasView: $canvasView, onSaved: onChanged), alignment: .bottomLeading)
}
}
private func onChanged() -> Void {
self.drawingOnImage = canvasView.drawing.image(
from: canvasView.bounds, scale: UIScreen.main.scale)
}
private func initCanvas() -> Void {
self.canvasView = PKCanvasView();
self.canvasView.isOpaque = false
self.canvasView.backgroundColor = UIColor.clear
self.canvasView.becomeFirstResponder()
}
private func save() -> Void {
onSave(self.image.mergeWith(topImage: drawingOnImage))
}
}
UIImage 的这个扩展将允许您合并图像。我使用了这个答案中的代码
public extension UIImage {
func mergeWith(topImage: UIImage) -> UIImage {
let bottomImage = self
UIGraphicsBeginImageContext(size)
let areaSize = CGRect(x: 0, y: 0, width: bottomImage.size.width, height: bottomImage.size.height)
bottomImage.draw(in: areaSize)
topImage.draw(in: areaSize, blendMode: .normal, alpha: 1.0)
let mergedImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return mergedImage
}
}
最后,这是我的 canvas 观点,尽管我认为您的代码中的 MyCanvas 应该可以正常工作。我的观点基于 this PencilKit tutorial.
struct CanvasView {
@Binding var canvasView: PKCanvasView
let onSaved: () -> Void
@State var toolPicker = PKToolPicker()
}
extension CanvasView: UIViewRepresentable {
func makeUIView(context: Context) -> PKCanvasView {
canvasView.tool = PKInkingTool(.pen, color: .gray, width: 10)
#if targetEnvironment(simulator)
canvasView.drawingPolicy = .anyInput
#endif
canvasView.delegate = context.coordinator
showToolPicker()
return canvasView
}
func updateUIView(_ uiView: PKCanvasView, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator(canvasView: $canvasView, onSaved: onSaved)
}
}
private extension CanvasView {
func showToolPicker() {
toolPicker.setVisible(true, forFirstResponder: canvasView)
toolPicker.addObserver(canvasView)
canvasView.becomeFirstResponder()
}
}
class Coordinator: NSObject {
var canvasView: Binding<PKCanvasView>
let onSaved: () -> Void
init(canvasView: Binding<PKCanvasView>, onSaved: @escaping () -> Void) {
self.canvasView = canvasView
self.onSaved = onSaved
}
}
extension Coordinator: PKCanvasViewDelegate {
func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
if !canvasView.drawing.bounds.isEmpty {
onSaved()
}
}
}