Skip to content
This repository was archived by the owner on Apr 6, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 33 additions & 24 deletions Classes/WDCropBorderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,39 @@ import UIKit
internal class WDCropBorderView: UIView {
private let kNumberOfBorderHandles: CGFloat = 8
private let kHandleDiameter: CGFloat = 24
private var lockAspectRatio: Bool

convenience init(frame: CGRect, lockAspectRatio locked: Bool) {
self.init(frame: frame)
self.lockAspectRatio = locked
}

override init(frame: CGRect) {
self.lockAspectRatio = false
super.init(frame: frame)

self.backgroundColor = UIColor.clearColor()
self.backgroundColor = UIColor.clear
}

required init?(coder aDecoder: NSCoder) {
self.lockAspectRatio = false
super.init(coder: aDecoder)

self.backgroundColor = UIColor.clearColor()
self.backgroundColor = UIColor.clear
}

override func drawRect(rect: CGRect) {
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()

CGContextSetStrokeColorWithColor(context,
UIColor(red: 1, green: 1, blue: 1, alpha: 0.5).CGColor)
CGContextSetLineWidth(context, 1.5)
CGContextAddRect(context, CGRectMake(kHandleDiameter / 2, kHandleDiameter / 2,
rect.size.width - kHandleDiameter, rect.size.height - kHandleDiameter))
CGContextStrokePath(context)
context?.setStrokeColor(UIColor(red: 1, green: 1, blue: 1, alpha: 0.5).cgColor)
context?.setLineWidth(1.5)
context?.addRect(CGRect(x: kHandleDiameter / 2, y: kHandleDiameter / 2,
width: rect.size.width - kHandleDiameter, height: rect.size.height - kHandleDiameter))
context?.strokePath()

CGContextSetRGBFillColor(context, 1, 1, 1, 0.95)
context?.setFillColor(red: 1, green: 1, blue: 1, alpha: 0.95)
for handleRect in calculateAllNeededHandleRects() {
CGContextFillEllipseInRect(context, handleRect)
context?.fillEllipse(in: handleRect)
}
}

Expand All @@ -53,17 +60,19 @@ internal class WDCropBorderView: UIView {
let bottomRowY = height - kHandleDiameter
let middleRowY = bottomRowY / 2

//starting with the upper left corner and then following clockwise
let topLeft = CGRectMake(leftColX, topRowY, kHandleDiameter, kHandleDiameter)
let topCenter = CGRectMake(centerColX, topRowY, kHandleDiameter, kHandleDiameter)
let topRight = CGRectMake(rightColX, topRowY, kHandleDiameter, kHandleDiameter)
let middleRight = CGRectMake(rightColX, middleRowY, kHandleDiameter, kHandleDiameter)
let bottomRight = CGRectMake(rightColX, bottomRowY, kHandleDiameter, kHandleDiameter)
let bottomCenter = CGRectMake(centerColX, bottomRowY, kHandleDiameter, kHandleDiameter)
let bottomLeft = CGRectMake(leftColX, bottomRowY, kHandleDiameter, kHandleDiameter)
let middleLeft = CGRectMake(leftColX, middleRowY, kHandleDiameter, kHandleDiameter)

return [topLeft, topCenter, topRight, middleRight, bottomRight, bottomCenter, bottomLeft,
middleLeft]
var handleArray = [CGRect]()
handleArray.append(CGRect(x: leftColX, y: topRowY, width: kHandleDiameter, height: kHandleDiameter)) //top left
handleArray.append(CGRect(x: rightColX, y: topRowY, width: kHandleDiameter, height: kHandleDiameter)) //top right
handleArray.append(CGRect(x: rightColX, y: bottomRowY, width: kHandleDiameter, height: kHandleDiameter)) //bottom right
handleArray.append(CGRect(x: leftColX, y: bottomRowY, width: kHandleDiameter, height: kHandleDiameter)) //bottom left

if !lockAspectRatio {
handleArray.append(CGRect(x: centerColX, y: topRowY, width: kHandleDiameter, height: kHandleDiameter)) //top center
handleArray.append(CGRect(x: rightColX, y: middleRowY, width: kHandleDiameter, height: kHandleDiameter)) //middle right
handleArray.append(CGRect(x: centerColX, y: bottomRowY, width: kHandleDiameter, height: kHandleDiameter)) //bottom center
handleArray.append(CGRect(x: leftColX, y: middleRowY, width: kHandleDiameter, height: kHandleDiameter)) //middle left
}

return handleArray
}
}
}
24 changes: 12 additions & 12 deletions Classes/WDImageCropOverlayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@ internal class WDImageCropOverlayView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)

self.backgroundColor = UIColor.clearColor()
self.userInteractionEnabled = true
self.backgroundColor = UIColor.clear
self.isUserInteractionEnabled = true
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)

self.backgroundColor = UIColor.clearColor()
self.userInteractionEnabled = true
self.backgroundColor = UIColor.clear
self.isUserInteractionEnabled = true
}

override func drawRect(rect: CGRect) {
override func draw(_ rect: CGRect) {

let toolbarSize = CGFloat(UIDevice.currentDevice().userInterfaceIdiom == .Pad ? 0 : 54)
let toolbarSize = CGFloat(UIDevice.current.userInterfaceIdiom == .pad ? 0 : 54)

let width = CGRectGetWidth(self.frame)
let height = CGRectGetHeight(self.frame) - toolbarSize
let width = self.frame.width
let height = self.frame.height - toolbarSize

let heightSpan = floor(height / 2 - self.cropSize.height / 2)
let widthSpan = floor(width / 2 - self.cropSize.width / 2)
Expand All @@ -43,11 +43,11 @@ internal class WDImageCropOverlayView: UIView {

// fill inner border
UIColor(red: 1, green: 1, blue: 1, alpha: 0.5).set()
UIRectFrame(CGRectMake(widthSpan - 2, heightSpan - 2, self.cropSize.width + 4,
self.cropSize.height + 4))
UIRectFrame(CGRect(x: widthSpan - 2, y: heightSpan - 2, width: self.cropSize.width + 4,
height: self.cropSize.height + 4))

// fill inner rect
UIColor.clearColor().set()
UIRectFill(CGRectMake(widthSpan, heightSpan, self.cropSize.width, self.cropSize.height))
UIColor.clear.set()
UIRectFill(CGRect(x: widthSpan, y: heightSpan, width: self.cropSize.width, height: self.cropSize.height))
}
}
106 changes: 49 additions & 57 deletions Classes/WDImageCropView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ private class ScrollView: UIScrollView {
private override func layoutSubviews() {
super.layoutSubviews()

if let zoomView = self.delegate?.viewForZoomingInScrollView?(self) {
if let zoomView = self.delegate?.viewForZooming?(in: self) {
let boundsSize = self.bounds.size
var frameToCenter = zoomView.frame

Expand All @@ -38,19 +38,20 @@ private class ScrollView: UIScrollView {

internal class WDImageCropView: UIView, UIScrollViewDelegate {
var resizableCropArea = false
var lockAspectRatio = false

private var scrollView: UIScrollView!
private var imageView: UIImageView!
private var cropOverlayView: WDImageCropOverlayView!
private var xOffset: CGFloat!
private var yOffset: CGFloat!

private static func scaleRect(rect: CGRect, scale: CGFloat) -> CGRect {
return CGRectMake(
rect.origin.x * scale,
rect.origin.y * scale,
rect.size.width * scale,
rect.size.height * scale)
private static func scaleRect(_ rect: CGRect, scale: CGFloat) -> CGRect {
return CGRect(
x: rect.origin.x * scale,
y: rect.origin.y * scale,
width: rect.size.width * scale,
height: rect.size.height * scale)
}

var imageToCrop: UIImage? {
Expand All @@ -72,7 +73,7 @@ internal class WDImageCropView: UIView, UIScrollViewDelegate {
} else {
if self.resizableCropArea {
self.cropOverlayView = WDResizableCropOverlayView(frame: self.bounds,
initialContentSize: CGSizeMake(newValue.width, newValue.height))
initialContentSize: CGSize(width: newValue.width, height: newValue.height), lockAspectRatio: self.lockAspectRatio)
} else {
self.cropOverlayView = WDImageCropOverlayView(frame: self.bounds)
}
Expand All @@ -85,24 +86,24 @@ internal class WDImageCropView: UIView, UIScrollViewDelegate {
override init(frame: CGRect) {
super.init(frame: frame)

self.userInteractionEnabled = true
self.backgroundColor = UIColor.blackColor()
self.isUserInteractionEnabled = true
self.backgroundColor = UIColor.black
self.scrollView = ScrollView(frame: frame)
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.delegate = self
self.scrollView.clipsToBounds = false
self.scrollView.decelerationRate = 0
self.scrollView.backgroundColor = UIColor.clearColor()
self.scrollView.backgroundColor = UIColor.clear
self.addSubview(self.scrollView)

self.imageView = UIImageView(frame: self.scrollView.frame)
self.imageView.contentMode = .ScaleAspectFit
self.imageView.backgroundColor = UIColor.blackColor()
self.imageView.contentMode = .scaleAspectFit
self.imageView.backgroundColor = UIColor.black
self.scrollView.addSubview(self.imageView)

self.scrollView.minimumZoomScale =
CGRectGetWidth(self.scrollView.frame) / CGRectGetHeight(self.scrollView.frame)
self.scrollView.frame.width / self.scrollView.frame.height
self.scrollView.maximumZoomScale = 20
self.scrollView.setZoomScale(1.0, animated: false)
}
Expand All @@ -111,31 +112,31 @@ internal class WDImageCropView: UIView, UIScrollViewDelegate {
super.init(coder: aDecoder)
}

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if !resizableCropArea {
return self.scrollView
}

let resizableCropView = cropOverlayView as! WDResizableCropOverlayView
let outerFrame = CGRectInset(resizableCropView.cropBorderView.frame, -10, -10)
let outerFrame = resizableCropView.cropBorderView.frame.insetBy(dx: -10, dy: -10)

if CGRectContainsPoint(outerFrame, point) {
if outerFrame.contains(point) {
if resizableCropView.cropBorderView.frame.size.width < 60 ||
resizableCropView.cropBorderView.frame.size.height < 60 {
return super.hitTest(point, withEvent: event)
return super.hitTest(point, with: event)
}

let innerTouchFrame = CGRectInset(resizableCropView.cropBorderView.frame, 30, 30)
if CGRectContainsPoint(innerTouchFrame, point) {
let innerTouchFrame = resizableCropView.cropBorderView.frame.insetBy(dx: 30, dy: 30)
if innerTouchFrame.contains(point) {
return self.scrollView
}

let outBorderTouchFrame = CGRectInset(resizableCropView.cropBorderView.frame, -10, -10)
if CGRectContainsPoint(outBorderTouchFrame, point) {
return super.hitTest(point, withEvent: event)
let outBorderTouchFrame = resizableCropView.cropBorderView.frame.insetBy(dx: -10, dy: -10)
if outBorderTouchFrame.contains(point) {
return super.hitTest(point, with: event)
}

return super.hitTest(point, withEvent: event)
return super.hitTest(point, with: event)
}

return self.scrollView
Expand All @@ -145,9 +146,9 @@ internal class WDImageCropView: UIView, UIScrollViewDelegate {
super.layoutSubviews()

let size = self.cropSize;
let toolbarSize = CGFloat(UIDevice.currentDevice().userInterfaceIdiom == .Pad ? 0 : 54)
self.xOffset = floor((CGRectGetWidth(self.bounds) - size.width) * 0.5)
self.yOffset = floor((CGRectGetHeight(self.bounds) - toolbarSize - size.height) * 0.5)
let toolbarSize = CGFloat(UIDevice.current.userInterfaceIdiom == .pad ? 0 : 54)
self.xOffset = floor((self.bounds.width - size.width) * 0.5)
self.yOffset = floor((self.bounds.height - toolbarSize - size.height) * 0.5)

let height = self.imageToCrop!.size.height
let width = self.imageToCrop!.size.width
Expand All @@ -167,31 +168,26 @@ internal class WDImageCropView: UIView, UIScrollViewDelegate {
}

self.cropOverlayView.frame = self.bounds
self.scrollView.frame = CGRectMake(xOffset, yOffset, size.width, size.height)
self.scrollView.contentSize = CGSizeMake(size.width, size.height)
self.imageView.frame = CGRectMake(0, floor((size.height - factoredHeight) * 0.5),
factoredWidth, factoredHeight)
self.scrollView.frame = CGRect(x: xOffset, y: yOffset, width: size.width, height: size.height)
self.scrollView.contentSize = CGSize(width: size.width, height: size.height)
self.imageView.frame = CGRect(x: 0, y: floor((size.height - factoredHeight) * 0.5),
width: factoredWidth, height: factoredHeight)
}

func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return self.imageView
}

func croppedImage() -> UIImage {
func croppedImage() -> CGRect {
// Calculate rect that needs to be cropped
var visibleRect = resizableCropArea ?
calcVisibleRectForResizeableCropArea() : calcVisibleRectForCropArea()

// transform visible rect to image orientation
let rectTransform = orientationTransformedRectOfImage(imageToCrop!)
visibleRect = CGRectApplyAffineTransform(visibleRect, rectTransform);
visibleRect = visibleRect.applying(rectTransform);

// finally crop image
let imageRef = CGImageCreateWithImageInRect(imageToCrop!.CGImage, visibleRect)
let result = UIImage(CGImage: imageRef!, scale: imageToCrop!.scale,
orientation: imageToCrop!.imageOrientation)

return result
return visibleRect
}

private func calcVisibleRectForResizeableCropArea() -> CGRect {
Expand All @@ -204,8 +200,8 @@ internal class WDImageCropView: UIView, UIScrollViewDelegate {
sizeScale *= self.scrollView.zoomScale

// then get the postion of the cropping rect inside the image
var visibleRect = resizableView.contentView.convertRect(resizableView.contentView.bounds,
toView: imageView)
var visibleRect = resizableView.contentView.convert(resizableView.contentView.bounds,
to: imageView)
visibleRect = WDImageCropView.scaleRect(visibleRect, scale: sizeScale)

return visibleRect
Expand All @@ -230,30 +226,26 @@ internal class WDImageCropView: UIView, UIScrollViewDelegate {
}

// extract visible rect from scrollview and scale it
var visibleRect = scrollView.convertRect(scrollView.bounds, toView:imageView)
var visibleRect = scrollView.convert(scrollView.bounds, to:imageView)
visibleRect = WDImageCropView.scaleRect(visibleRect, scale: scale)

return visibleRect
}

private func orientationTransformedRectOfImage(image: UIImage) -> CGAffineTransform {
private func orientationTransformedRectOfImage(_ image: UIImage) -> CGAffineTransform {
var rectTransform: CGAffineTransform!

switch image.imageOrientation {
case .Left:
rectTransform = CGAffineTransformTranslate(
CGAffineTransformMakeRotation(CGFloat(M_PI_2)), 0, -image.size.height)
case .Right:
rectTransform = CGAffineTransformTranslate(
CGAffineTransformMakeRotation(CGFloat(-M_PI_2)),-image.size.width, 0)
case .Down:
rectTransform = CGAffineTransformTranslate(
CGAffineTransformMakeRotation(CGFloat(-M_PI)),
-image.size.width, -image.size.height)
case .left:
rectTransform = CGAffineTransform(rotationAngle: CGFloat(M_PI_2)).translatedBy(x: 0, y: -image.size.height)
case .right:
rectTransform = CGAffineTransform(rotationAngle: CGFloat(-M_PI_2)).translatedBy(x: -image.size.width, y: 0)
case .down:
rectTransform = CGAffineTransform(rotationAngle: CGFloat(-M_PI)).translatedBy(x: -image.size.width, y: -image.size.height)
default:
rectTransform = CGAffineTransformIdentity
rectTransform = CGAffineTransform.identity
}

return CGAffineTransformScale(rectTransform, image.scale, image.scale)
return rectTransform.scaledBy(x: image.scale, y: image.scale)
}
}
}
Loading