在SwiftUI中根据矩形裁剪图像

时间:2020-04-19 13:43:33

标签: swift swiftui

我有一个可以使用 DragGesture() 拖动的图像。我想裁剪矩形区域内可见的图像。这是我的代码...

struct CropImage: View {

    @State private var currentPosition: CGSize = .zero
    @State private var newPosition: CGSize = .zero

    var body: some View {
        VStack {
            ZStack {
                Image("test_pic")
                    .resizable()
                    .scaledToFit()
                    .offset(x: self.currentPosition.width, y: self.currentPosition.height)

                Rectangle()
                    .fill(Color.black.opacity(0.3))
                    .frame(width: UIScreen.screenWidth * 0.7 , height: UIScreen.screenHeight/5)
                    .overlay(Rectangle().stroke(Color.white, lineWidth: 3))
            }
            .gesture(DragGesture()
                .onChanged { value in
                    self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height)
            }
            .onEnded { value in
                self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height)

                self.newPosition = self.currentPosition
            })


            Button ( action : {
                // how to crop the image according to rectangle area

            } ) {
                Text("Crop Image")
                    .padding(.all, 10)
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .shadow(color: .gray, radius: 1)
                    .padding(.top, 50)
            }
        }
    }
}

为便于理解...

enter image description here

2 个答案:

答案 0 :(得分:1)

感谢Asperi's answer,我实现了一个轻量级的swiftUI库来裁剪图像。这里是库和演示。 Demo

魔术在下面:

public var body: some View {
        GeometryReader { proxy  in
           // ...
                        
                        Button(action: {
  // how to crop the image according to rectangle area
                            if self.tempResult == nil {
                                self.cropTheImageWithImageViewSize(proxy.size)
                            }
                            self.resultImage = self.tempResult
                        })  {
            Text("Crop Image")
                .padding(.all, 10)
                .background(Color.blue)
                .foregroundColor(.white)
                .shadow(color: .gray, radius: 1)
                .padding(.top, 50)
        }
                    }
  }

func cropTheImageWithImageViewSize(_ size: CGSize) {

    let imsize =  inputImage.size
    let scale = max(inputImage.size.width / size.width,
                    inputImage.size.height / size.height)

    
    let zoomScale = self.scale

    let currentPositionWidth = self.dragAmount.width * scale
        let currentPositionHeight = self.dragAmount.height * scale
    
    let croppedImsize = CGSize(width: (self.cropSize.width * scale) / zoomScale, height: (self.cropSize.height * scale) / zoomScale)
     
    let xOffset = (( imsize.width - croppedImsize.width) / 2.0) - (currentPositionWidth  / zoomScale)
    let yOffset = (( imsize.height - croppedImsize.height) / 2.0) - (currentPositionHeight  / zoomScale)
    let croppedImrect: CGRect = CGRect(x: xOffset, y: yOffset, width: croppedImsize.width, height: croppedImsize.height)
          
    if let cropped = inputImage.cgImage?.cropping(to: croppedImrect) {
       //uiimage here can write to data in png or jpeg
        let croppedIm = UIImage(cgImage: cropped)
        tempResult = croppedIm
        result = Image(uiImage: croppedIm)
    }
}

答案 1 :(得分:-1)

在这里可以使用.clipShape。使用Xcode 11.4 / iOS 13.4进行了测试

demo

struct CropFrame: Shape {
    let isActive: Bool
    func path(in rect: CGRect) -> Path {
        guard isActive else { return Path(rect) } // full rect for non active

        let size = CGSize(width: UIScreen.screenWidth * 0.7, height: UIScreen.screenHeight/5)
        let origin = CGPoint(x: rect.midX - size.width / 2, y: rect.midY - size.height / 2)
        return Path(CGRect(origin: origin, size: size).integral)
    }
}

struct CropImage: View {

    @State private var currentPosition: CGSize = .zero
    @State private var newPosition: CGSize = .zero
    @State private var clipped = false

    var body: some View {
        VStack {
            ZStack {
                Image("test_pic")
                    .resizable()
                    .scaledToFit()
                    .offset(x: self.currentPosition.width, y: self.currentPosition.height)

                Rectangle()
                    .fill(Color.black.opacity(0.3))
                    .frame(width: UIScreen.screenWidth * 0.7 , height: UIScreen.screenHeight/5)
                    .overlay(Rectangle().stroke(Color.white, lineWidth: 3))
            }
            .clipShape(
                CropFrame(isActive: clipped)
            )
            .gesture(DragGesture()
                .onChanged { value in
                    self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height)
            }
            .onEnded { value in
                self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height)

                self.newPosition = self.currentPosition
            })


            Button (action : { self.clipped.toggle() }) {
                Text("Crop Image")
                    .padding(.all, 10)
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .shadow(color: .gray, radius: 1)
                    .padding(.top, 50)
            }
        }
    }
}