diff options
author | leoz <leoz@yahoo.com> | 2024-02-21 15:12:18 -0500 |
---|---|---|
committer | leoz <leoz@yahoo.com> | 2024-02-21 15:12:18 -0500 |
commit | 92d61886ad1381a6133167d0a5f770a43c14523d (patch) | |
tree | 4b35240348e552f3b4ac3c2931b706e2a581b6f8 /Sources | |
parent | f76d234da71a5c2c8d23ed6a6516b809337f5bfb (diff) |
Rotate image
Diffstat (limited to 'Sources')
-rw-r--r-- | Sources/SwiftyCrop/Models/CropViewModel.swift | 61 | ||||
-rw-r--r-- | Sources/SwiftyCrop/View/CropView.swift | 13 |
2 files changed, 70 insertions, 4 deletions
diff --git a/Sources/SwiftyCrop/Models/CropViewModel.swift b/Sources/SwiftyCrop/Models/CropViewModel.swift index a9557ac..9d5e16d 100644 --- a/Sources/SwiftyCrop/Models/CropViewModel.swift +++ b/Sources/SwiftyCrop/Models/CropViewModel.swift @@ -123,6 +123,47 @@ class CropViewModel: ObservableObject { } /** + Rotates the image to the angle that is rotated inside the view. + - Parameters: + - image: The UIImage to rotate + - angle: The Angle to rotate to + - Returns: A rotated UIImage if the rotating operation is successful; otherwise nil. + */ + func rotate(_ image: UIImage, _ angle: Angle) -> UIImage? { + guard let orientedImage = image.correctlyOriented else { + return nil + } + + guard let cgImage = orientedImage.cgImage else { + return nil + } + + let ciImage = CIImage(cgImage: cgImage) + + // Prepare filter + let filter = CIFilter.straightenFilter( + image: ciImage, + radians: angle.radians + ) + + // Get output image + guard let output = filter?.outputImage else { + return nil + } + + // Create resulting image + let context = CIContext() + guard let result = context.createCGImage( + output, + from: output.extent + ) else { + return nil + } + + return UIImage(cgImage: result) + } + + /** Calculates the rectangle to crop. - Parameters: - image: The UIImage to calculate the rectangle to crop for @@ -178,3 +219,23 @@ private extension UIImage { return normalizedImage } } + +private extension CIFilter { + /** + Creates the straighten filter. + - Parameters: + - inputImage: The CIImage to use as an input image + - radians: An angle in radians + - Returns: A generated CIFilter. + */ + static func straightenFilter(image: CIImage, radians: Double) -> CIFilter? { + let angle: Double = radians != 0 ? -radians : 0 + guard let filter = CIFilter(name: "CIStraightenFilter") else { + return nil + } + filter.setDefaults() + filter.setValue(image, forKey: kCIInputImageKey) + filter.setValue(angle, forKey: kCIInputAngleKey) + return filter + } +} diff --git a/Sources/SwiftyCrop/View/CropView.swift b/Sources/SwiftyCrop/View/CropView.swift index c76f7f8..9619efb 100644 --- a/Sources/SwiftyCrop/View/CropView.swift +++ b/Sources/SwiftyCrop/View/CropView.swift @@ -64,7 +64,7 @@ struct CropView: View { .onEnded { _ in viewModel.lastOffset = viewModel.offset } - + let rotationGesture = RotationGesture() .onChanged { value in viewModel.angle = value @@ -138,10 +138,15 @@ struct CropView: View { } private func cropImage() -> UIImage? { - if maskShape == .circle && configuration.cropImageCircular { - return viewModel.cropToCircle(image) + if let rotatedImage: UIImage = viewModel.rotate(image, viewModel.lastAngle) { + if maskShape == .circle && configuration.cropImageCircular { + return viewModel.cropToCircle(rotatedImage) + } else { + return viewModel.cropToSquare(rotatedImage) + } + return rotatedImage } else { - return viewModel.cropToSquare(image) + return nil } } |