I am trying to develop an application which crops an image. The rectangle to crop is created by touching two times on the image (topLeft point, bottomRight point). When the user has tapped, a red rectangle is displayed on the screen to see the crop area.
Then with this rectangle, I would like to crop the image. But I am facing to an issue, the crop does not work and give me bad result.
Below my code :
@objc
func tap(_ sender: UITapGestureRecognizer) {
let location = sender.location(in: sourceImageView)
print(#function + ":: location: \(location)")
if location1 == nil {
location1 = location
} else if location2 == nil {
location2 = location
print("Processing to crop the image...")
guard let _topLeft = location1,
let _bottomRight = location2 else {
fatalError("Processing failed...")
}
let _topRight = CGPoint(x: _bottomRight.x, y: _topLeft.y)
let _bottomLeft = CGPoint(x: _topLeft.x, y: _bottomRight.y)
let _width = _topLeft.distance(point: _topRight)
let _height = _topLeft.distance(point: _bottomLeft)
let cropArea = CGRect(origin: _topLeft, size: CGSize(width: _width, height: _height))
// Displaying red rectangle on the source image
let outline = CALayer()
outline.frame = cropArea
outline.borderWidth = 2.0
outline.borderColor = UIColor.red.cgColor
sourceImageView.layer.addSublayer(outline)
guard let sourceImage = sourceImageView.image,
let sourceCGImage = sourceImage.cgImage else {
fatalError("Cannot get CG Image from source img")
}
let viewSize = self.view.frame.size
let imageViewScaleWidth = viewSize.width / CGFloat(sourceCGImage.width)
let imageViewScaleHeight = viewSize.height / CGFloat(sourceCGImage.height)
let scale = 1 / min(imageViewScaleWidth, imageViewScaleHeight)
let scaleWidth = 1 / imageViewScaleWidth
let scaleHeight = 1 / imageViewScaleHeight
let newWidth = cropArea.height * scale
let newHeight = cropArea.width * scale
let newXCord = (cropArea.topLeft.x * scale) + newHeight
let newYCord = (cropArea.topLeft.y * scale)
let newCropArea = CGRect(origin: CGPoint(x: newXCord,
y: newYCord),
size: CGSize(width: newHeight,
height: newWidth))
guard let croppedSourceImage = sourceCGImage.cropping(to: newCropArea) else {
print("Cannot crop the current image.")
return
}
}
}
I think my issue comes from the rectangle projection on the source image.
Thanks
EDIT :
public extension CGPoint {
/// Distance between two points.
///
/// - Parameter point: A `CGPoint` instance.
public func distance(point p: CGPoint) -> CGFloat {
return sqrt(pow((p.x - x), 2) + pow((p.y - y), 2))
}
}