master 3436f26c9da5 cached
47 files
197.2 KB
51.0k tokens
1 requests
Download .txt
Showing preview only (213K chars total). Download the full file or copy to clipboard to get everything.
Repository: artemkrachulov/AKImageCropperView
Branch: master
Commit: 3436f26c9da5
Files: 47
Total size: 197.2 KB

Directory structure:
gitextract_x4b46xu8/

├── .gitignore
├── AKImageCropperView/
│   ├── AKImageCropperOverlayView.swift
│   ├── AKImageCropperOverlayViewConfiguration.swift
│   ├── AKImageCropperOverlayViewConfigurationCorner.swift
│   ├── AKImageCropperOverlayViewConfigurationEdge.swift
│   ├── AKImageCropperOverlayViewConfigurationGrid.swift
│   ├── AKImageCropperOverlayViewConfigurationOverlay.swift
│   ├── AKImageCropperOverlayViewTouchState.swift
│   ├── AKImageCropperScrollView.swift
│   ├── AKImageCropperView.h
│   ├── AKImageCropperView.swift
│   ├── IC_CGFloatExtension.swift
│   ├── IC_CGPointExtension.swift
│   ├── IC_CGSizeExtensions.swift
│   ├── IC_UIImageExtensions.swift
│   ├── Info.plist
│   └── PrimaryFilledButton.swift
├── AKImageCropperView.podspec
├── AKImageCropperView.xcodeproj/
│   ├── project.pbxproj
│   ├── project.xcworkspace/
│   │   ├── contents.xcworkspacedata
│   │   └── xcshareddata/
│   │       ├── AKImageCropperDemo.xcscmblueprint
│   │       └── Demo.xcscmblueprint
│   └── xcshareddata/
│       └── xcschemes/
│           └── AKImageCropperView.xcscheme
├── AKImageCropperViewExample/
│   ├── AppDelegate.swift
│   ├── Base.lproj/
│   │   ├── LaunchScreen.xib
│   │   └── Main.storyboard
│   ├── Constants.swift
│   ├── CropperViewController.swift
│   ├── CustomImageCropperOverlayView.swift
│   ├── HomeViewController.swift
│   ├── ImageViewController.swift
│   ├── Images.xcassets/
│   │   ├── AppIcon.appiconset/
│   │   │   └── Contents.json
│   │   ├── Attractive-girl.imageset/
│   │   │   └── Contents.json
│   │   ├── Autumn-background.imageset/
│   │   │   └── Contents.json
│   │   ├── Colorful-pillows.imageset/
│   │   │   └── Contents.json
│   │   ├── Contents.json
│   │   ├── Cupcakes.imageset/
│   │   │   └── Contents.json
│   │   ├── Funnel-cake-stand.imageset/
│   │   │   └── Contents.json
│   │   ├── Icons/
│   │   │   ├── Contents.json
│   │   │   ├── overlay.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── random.imageset/
│   │   │   │   └── Contents.json
│   │   │   └── rotate.imageset/
│   │   │       └── Contents.json
│   │   └── Image-of-earth.imageset/
│   │       └── Contents.json
│   ├── ImagesTableViewController.swift
│   └── Info.plist
├── LICENSE
└── README.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Xcode
.DS_Store
*/build/*
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
profile
*.moved-aside
DerivedData
.idea/
*.hmap

#CocoaPods
Pods
Podfile.lock

================================================
FILE: AKImageCropperView/AKImageCropperOverlayView.swift
================================================
//
//  AKImageCropperOverlayView.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

import UIKit

protocol AKImageCropperOverlayViewDelegate : class {
    func cropperOverlayViewDidChangeCropRect(_ view: AKImageCropperOverlayView, _ cropRect: CGRect)
}

open class AKImageCropperOverlayView: UIView {
    
    // MARK: -
    // MARK: ** Properties **

    /** Configuration structure for the Overlay View appearance and behavior. */

    open var configuraiton = AKImageCropperCropViewConfiguration()
    
    /** Crop rectangle */
    
    internal var cropRect: CGRect = .zero
    
    /** Saved crop rectangle state */
    
    fileprivate var touchesBegan: (touch: CGPoint, cropRect: CGRect)!

    /** Current active crop area part */
    
    fileprivate var activeCropAreaPart: AKCropAreaPart = .none {
        didSet { layoutSubviews() }
    }
    
    fileprivate struct AKCropAreaPart: OptionSet {
        
        public let rawValue: Int
        
        public init(rawValue: Int) {
            self.rawValue = rawValue
        }
        
        static let none                 = AKCropAreaPart(rawValue: 1 << 0)
        static let topEdge              = AKCropAreaPart(rawValue: 1 << 1)
        static let leftEdge             = AKCropAreaPart(rawValue: 1 << 2)
        static let bottomEdge           = AKCropAreaPart(rawValue: 1 << 3)
        static let rightEdge            = AKCropAreaPart(rawValue: 1 << 4)

        static let all: AKCropAreaPart = [.topEdge, .rightEdge, .bottomEdge, .leftEdge]
        
        static let topLeftCorner: AKCropAreaPart        = [.topEdge, .leftEdge]
        static let topRightCorner: AKCropAreaPart       = [.topEdge, .rightEdge]
        static let bottomRightCorner: AKCropAreaPart    = [.bottomEdge, .rightEdge]
        static let bottomLeftCorner: AKCropAreaPart     = [.bottomEdge, .leftEdge]
    }
    
    //  MARK: Managing the Delegate

    weak var delegate: AKImageCropperOverlayViewDelegate?
    
    //  MARK: Touch & Parts views
    
    fileprivate var topcropView: UIView!
    fileprivate var rightcropView: UIView!
    fileprivate var bottomcropView: UIView!
    fileprivate var leftcropView: UIView!
    fileprivate var topEdgeTouchView: UIView!
    fileprivate var topEdgeView: UIView!
    fileprivate var rightEdgeTouchView: UIView!
    fileprivate var rightEdgeView: UIView!
    fileprivate var bottomEdgeTouchView: UIView!
    fileprivate var bottomEdgeView: UIView!
    fileprivate var leftEdgeTouchView: UIView!
    fileprivate var leftEdgeView: UIView!
    fileprivate var topLeftCornerTouchView: UIView!
    fileprivate var topLeftCornerView: UIView!
    fileprivate var topRightCornerTouchView: UIView!
    fileprivate var topRightCornerView: UIView!
    fileprivate var bottomRightCornerTouchView: UIView!
    fileprivate var bottomRightCornerView: UIView!
    fileprivate var bottomLeftCornerTouchView: UIView!
    fileprivate var bottomLeftCornerView: UIView!
    fileprivate var gridView: UIView!
    fileprivate var gridViewVerticalLines: [UIView]!
    fileprivate var gridViewHorizontalLines: [UIView]!
    
    // MARK: -
    // MARK: ** Initialization OBJECTS(VIEWS) & theirs parameters **
    
    /** Parent (main) class to translate some properties and objects. */
    
    weak var cropperView: AKImageCropperView!

    fileprivate (set) lazy var overlayView: UIView! = {
        let view = UIView()
        view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        view.clipsToBounds = true
        return view
    }()
    
    fileprivate lazy var containerImageView: UIView! = {
        let view = UIView()
        view.backgroundColor = UIColor.clear
        view.clipsToBounds = true
        view.isUserInteractionEnabled = false
        return view
    }()
    
    fileprivate lazy var imageView: UIImageView! = {
        let view = UIImageView()
        view.backgroundColor = UIColor.clear
        return view
    }()
    
    open var image: UIImage! {
        didSet {
            imageView.image = image
        }
    }
    
    //  MARK: - Initialization

    /**
     Returns an overlay view initialized with the specified configuraiton.
     
     - Parameter configuraiton: Configuration structure for the Overlay View appearance and behavior.
     */
    
    init() {
        super.init(frame: .zero)
        
        backgroundColor = .clear
        alpha = 0
        
        initialize()
    }
    
    public init(configuraiton: AKImageCropperCropViewConfiguration? = nil) {
        super.init(frame: CGRect.zero)
        
        if configuraiton != nil {
            self.configuraiton = configuraiton!
        }
        
        backgroundColor = UIColor.clear
        alpha = 0
        
        initialize()
    }
    
    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - Draving Crop rect frame
    
    fileprivate func initialize() {
        
        /*
         Create views layout.
         Step by step
         
         1. OverlayView
         */
        
        addSubview(overlayView)
        
        let blurEffect = UIBlurEffect(style: configuraiton.overlay.blurStyle)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        blurEffectView.alpha = self.configuraiton.overlay.blurAlpha
        
        blurEffectView.frame = overlayView.bounds
        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        overlayView.addSubview(blurEffectView)
        
        /* 2. Container view ‹‹ Image view */
        
        containerImageView.addSubview(imageView)
        addSubview(containerImageView)
        
        /* 3. Crop rectangle */
        
        //  Edges
        
        topEdgeTouchView = UIView()
        addSubview(topEdgeTouchView)
        
        topEdgeView = UIView()
        topEdgeTouchView.addSubview(topEdgeView)
        
        rightEdgeTouchView = UIView()
        addSubview(rightEdgeTouchView)
        
        rightEdgeView = UIView()
        rightEdgeTouchView.addSubview(rightEdgeView)
        
        bottomEdgeTouchView = UIView()
        addSubview(bottomEdgeTouchView)
        
        bottomEdgeView = UIView()
        bottomEdgeTouchView.addSubview(bottomEdgeView)
        
        leftEdgeTouchView = UIView()
        addSubview(leftEdgeTouchView)
        
        leftEdgeView = UIView()
        leftEdgeTouchView.addSubview(leftEdgeView)
        
        if configuraiton.edge.isHidden {
            topEdgeView.isHidden = true
            rightEdgeView.isHidden = true
            bottomEdgeView.isHidden = true
            leftEdgeView.isHidden = true
        }
        
        //  Corners
        
        topLeftCornerTouchView  = UIView()
        addSubview(topLeftCornerTouchView)
        
        topLeftCornerView = UIView()
        topLeftCornerView.layer.addSublayer(CAShapeLayer())
        topLeftCornerTouchView.addSubview(topLeftCornerView)
        
        topRightCornerTouchView  = UIView()
        addSubview(topRightCornerTouchView)
        
        topRightCornerView = UIView()
        topRightCornerView.layer.addSublayer(CAShapeLayer())
        topRightCornerTouchView.addSubview(topRightCornerView)
        
        bottomRightCornerTouchView  = UIView()
        addSubview(bottomRightCornerTouchView)
        
        bottomRightCornerView = UIView()
        bottomRightCornerView.layer.addSublayer(CAShapeLayer())
        bottomRightCornerTouchView.addSubview(bottomRightCornerView)
        
        bottomLeftCornerTouchView  = UIView()
        addSubview(bottomLeftCornerTouchView)
        
        bottomLeftCornerView = UIView()
        bottomLeftCornerView.layer.addSublayer(CAShapeLayer())
        bottomLeftCornerTouchView.addSubview(bottomLeftCornerView)
        
        if configuraiton.corner.isHidden {
            topLeftCornerView.isHidden = true
            topRightCornerView.isHidden = true
            bottomRightCornerView.isHidden = true
            bottomLeftCornerView.isHidden = true
        }
        
        //  Grid
        
        gridView = UIView()
        
        gridViewVerticalLines = []
        gridViewHorizontalLines = []
        
        for _ in 0..<configuraiton.grid.linesCount.vertical {
            
            let view = UIView()
            
            view.frame.size.width = configuraiton.grid.linesWidth
            view.backgroundColor = configuraiton.grid.linesColor
            
            gridViewVerticalLines.append(view)
            gridView.addSubview(view)
        }
        
        for _ in 0..<configuraiton.grid.linesCount.horizontal {
            
            let view = UIView()
            
            view.frame.size.height = configuraiton.grid.linesWidth
            view.backgroundColor = configuraiton.grid.linesColor
            
            gridViewHorizontalLines.append(view)
            gridView.addSubview(view)
        }
        
        addSubview(gridView)
        
        gridView.isHidden = configuraiton.grid.isHidden
        
        if configuraiton.grid.alwaysShowGrid {
            gridView.alpha = 1
        } else {
            gridView.alpha = 0
        }

    }
    
    //  MARK: - Life cycle
    
    override open func layoutSubviews() {
        super.layoutSubviews()
        
        overlayView.frame = frame
        containerImageView.frame = cropRect
        matchForegroundToBackgroundScrollViewOffset()
        matchForegroundToBackgroundScrollViewSize()
        
        topEdgeTouchView.frame = cropAreaTopEdgeFrame
        layoutTopEdgeView(topEdgeView,
                          inTouchView: topEdgeTouchView,
                          forState: activeCropAreaPart == .topEdge
                            ? .highlighted
                            : .normal)
        
        rightEdgeTouchView.frame = cropAreaRightEdgeFrame
        layoutRightEdgeView(rightEdgeView,
                            inTouchView: rightEdgeTouchView,
                            forState: activeCropAreaPart == .rightEdge
                                ? .highlighted
                                : .normal)
        
        bottomEdgeTouchView.frame = cropAreaBottomEdgeFrame
        layoutBottomEdgeView(bottomEdgeView,
                             inTouchView: bottomEdgeTouchView,
                             forState: activeCropAreaPart == .bottomEdge
                                ? .highlighted
                                : .normal)
        
        leftEdgeTouchView.frame = cropAreaLeftEdgeFrame
        layoutLeftEdgeView(leftEdgeView,
                           inTouchView: leftEdgeTouchView,
                           forState: activeCropAreaPart == .leftEdge
                            ? .highlighted
                            : .normal)
        
        topLeftCornerTouchView.frame = cropAreaTopLeftCornerFrame
        layoutTopLeftCornerView(topLeftCornerView,
                                inTouchView: topLeftCornerTouchView,
                                forState: activeCropAreaPart == .topLeftCorner
                                    ? .highlighted
                                    : .normal)
        
        topRightCornerTouchView.frame = cropAreaTopRightCornerFrame
        layoutTopRightCornerView(topRightCornerView,
                                 inTouchView: topRightCornerTouchView,
                                 forState: activeCropAreaPart == .topRightCorner
                                    ? .highlighted
                                    : .normal)
        
        bottomRightCornerTouchView.frame = cropAreaBottomRightCornerFrame
        layoutBottomRightCornerView(bottomRightCornerView,
                                    inTouchView: bottomRightCornerTouchView,
                                    forState: activeCropAreaPart == .bottomRightCorner
                                        ? .highlighted
                                        : .normal)
        
        bottomLeftCornerTouchView.frame = cropAreaBottomLeftCornerFrame
        layoutBottomLeftCornerView(bottomLeftCornerView,
                                   inTouchView: bottomLeftCornerTouchView,
                                   forState: activeCropAreaPart == .bottomLeftCorner
                                    ? .highlighted
                                    : .normal)
        
        gridView.frame = cropRect
        layoutGridView(gridView, gridViewHorizontalLines: gridViewHorizontalLines, gridViewVerticalLines: gridViewVerticalLines)
    }
    
    //  MARK: Crop rectangle parts rects

    fileprivate var cropAreaTopLeftCornerFrame: CGRect {
        return CGRect(
            origin: CGPoint(
                x: cropRect.origin.x - configuraiton.cornerTouchSize.width / 2,
                y: cropRect.origin.y - configuraiton.cornerTouchSize.height / 2),
            size: configuraiton.cornerTouchSize)
    }
    
    fileprivate var cropAreaTopRightCornerFrame: CGRect {
        return CGRect(
            origin: CGPoint(
                x: cropRect.maxX - configuraiton.cornerTouchSize.width / 2,
                y: cropRect.minY - configuraiton.cornerTouchSize.height / 2),
            size: configuraiton.cornerTouchSize)
    }
    
    fileprivate var cropAreaBottomLeftCornerFrame: CGRect {
        return CGRect(
            origin: CGPoint(
                x: cropRect.origin.x - configuraiton.cornerTouchSize.width / 2,
                y: cropRect.maxY - configuraiton.cornerTouchSize.height / 2),
            size: configuraiton.cornerTouchSize)
    }
    
    fileprivate var cropAreaBottomRightCornerFrame: CGRect {
        return CGRect(
            origin: CGPoint(
                x: cropRect.maxX - configuraiton.cornerTouchSize.width / 2,
                y: cropRect.maxY - configuraiton.cornerTouchSize.height / 2),
            size: configuraiton.cornerTouchSize)
    }
    
    fileprivate var cropAreaTopEdgeFrame: CGRect{
        return CGRect(
            x       : cropAreaTopLeftCornerFrame.maxX,
            y       : cropRect.origin.y - configuraiton.edgeTouchThickness.horizontal / 2,
            width   : cropRect.size.width - (cropAreaTopLeftCornerFrame.size.width / 2 + cropAreaTopRightCornerFrame.size.width / 2),
            height  : configuraiton.edgeTouchThickness.horizontal)
    }
    
    fileprivate var cropAreaBottomEdgeFrame: CGRect {
        return CGRect(
            x       : cropAreaBottomLeftCornerFrame.maxX,
            y       : cropRect.maxY - configuraiton.edgeTouchThickness.horizontal / 2,
            width   : cropRect.size.width - (cropAreaBottomLeftCornerFrame.size.width / 2 + cropAreaBottomRightCornerFrame.size.width / 2),
            height  : configuraiton.edgeTouchThickness.horizontal)
    }
    
    fileprivate var cropAreaRightEdgeFrame: CGRect {
        return CGRect(
            x       : cropRect.maxX - configuraiton.edgeTouchThickness.vertical / 2,
            y       : cropAreaTopLeftCornerFrame.maxY,
            width   : configuraiton.edgeTouchThickness.vertical,
            height  : cropRect.size.height - (cropAreaTopRightCornerFrame.size.height / 2 + cropAreaBottomRightCornerFrame.size.height / 2))
    }
    
    fileprivate var cropAreaLeftEdgeFrame: CGRect {
        return CGRect(
            x       : cropRect.origin.x - configuraiton.edgeTouchThickness.vertical / 2,
            y       : cropAreaTopLeftCornerFrame.maxY,
            width   : configuraiton.edgeTouchThickness.vertical,
            height  : cropRect.size.height - (cropAreaTopLeftCornerFrame.size.height / 2 + cropAreaBottomLeftCornerFrame.size.height / 2))
    }
    
    fileprivate func getCropAreaPartContainsPoint(_ point: CGPoint) -> AKCropAreaPart {
        if cropAreaTopEdgeFrame.contains(point) {
            return .topEdge
        } else if cropAreaBottomEdgeFrame.contains(point) {
            return .bottomEdge
        } else if cropAreaRightEdgeFrame.contains(point) {
            return .rightEdge
        } else if cropAreaLeftEdgeFrame.contains(point) {
            return .leftEdge
        } else if cropAreaTopLeftCornerFrame.contains(point) {
            return .topLeftCorner
        } else if cropAreaTopRightCornerFrame.contains(point) {
            return .topRightCorner
        } else if cropAreaBottomLeftCornerFrame.contains(point) {
            return .bottomLeftCorner
        } else if cropAreaBottomRightCornerFrame.contains(point) {
            return .bottomRightCorner
        } else {
            return .none
        }
    }
    
    // MARK: Other methods
    
    final func showOverlayBlur(_ show: Bool, completion: ((Bool) -> Void)? = nil) {

        UIView.animate(withDuration: configuraiton.animation.duration, delay: 0, options: [], animations: {
           
                self.overlayView.subviews.first?.alpha = show ? self.configuraiton.overlay.blurAlpha : 0.0

        }, completion: { isComplete in
            completion?(isComplete)
        })
    }
    
    final func showGrid(_ show: Bool, completion: ((Bool) -> Void)? = nil) {
        
        if configuraiton.grid.alwaysShowGrid {
             completion?(true)
            return
        }
        
        let animations: () -> Void = { _ in
            self.gridView.alpha = show ? 1 : 0
        }
        
        if configuraiton.animation.duration == 0 {
            
            animations()
            
        } else {
        
            UIView.animate(withDuration: configuraiton.animation.duration, delay: 0, options: [], animations: animations, completion: { isComplete in
                completion?(isComplete)
            })
        }
    }
    
    /**
     Visual representation for top edge view in current user interaction state.
     
     - Parameter view: Top edge view.
     
     - Parameter touchView: Touch area view where added top edge view.
     
     - Parameter state: User interaction state.
     */
    
    open func layoutTopEdgeView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        
        var color: UIColor
        var width: CGFloat
        
        if state == .normal {
            color = configuraiton.edge.normalLineColor
            width = configuraiton.edge.normalLineWidth
        } else {
            color = configuraiton.edge.highlightedLineColor
            width = configuraiton.edge.highlightedLineWidth
        }
        
        view.backgroundColor = color
        view.frame = CGRect(
            x       : touchView.bounds.origin.x - configuraiton.cornerTouchSize.width / 2 - configuraiton.edge.normalLineWidth,
            y       : touchView.bounds.midY - width,
            width   : touchView.bounds.size.width + configuraiton.cornerTouchSize.width + configuraiton.edge.normalLineWidth * 2,
            height  : width)
    }
    
    /**
     Visual representation for right edge view in current user interaction state.
     
     - Parameter view: Right edge view.
     
     - Parameter touchView: Touch area view where added right edge view.
     
     - Parameter state: User interaction state.
     */
    
    open func layoutRightEdgeView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        
        var color: UIColor
        var width: CGFloat
        
        if state == .normal {
            color = configuraiton.edge.normalLineColor
            width = configuraiton.edge.normalLineWidth
        } else {
            color = configuraiton.edge.highlightedLineColor
            width = configuraiton.edge.highlightedLineWidth
        }
        
        view.backgroundColor = color
        view.frame = CGRect(
            x       : touchView.bounds.midX,
            y       : touchView.bounds.origin.y - configuraiton.cornerTouchSize.height / 2 - configuraiton.edge.normalLineWidth,
            width   : width,
            height  : touchView.bounds.size.height + configuraiton.cornerTouchSize.height + configuraiton.edge.normalLineWidth * 2)
    }
    
    /**
     Visual representation for bottom edge view in current user interaction state.
     
     - Parameter view: Bottom edge view.
     
     - Parameter touchView: Touch area view where added bottom edge view.
     
     - Parameter state: User interaction state.
     */
    
    open func layoutBottomEdgeView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        
        var color: UIColor
        var width: CGFloat
        
        if state == .normal {
            color = configuraiton.edge.normalLineColor
            width = configuraiton.edge.normalLineWidth
        } else {
            color = configuraiton.edge.highlightedLineColor
            width = configuraiton.edge.highlightedLineWidth
        }
      
        view.backgroundColor = color
        view.frame = CGRect(
            x       : touchView.bounds.origin.x - configuraiton.cornerTouchSize.width / 2 - configuraiton.edge.normalLineWidth,
            y       : touchView.bounds.midY,
            width   : touchView.bounds.size.width + configuraiton.cornerTouchSize.width + configuraiton.edge.normalLineWidth * 2,
            height  : width)
    }
    
    /**
     Visual representation for left edge view in current user interaction state.
     
     - Parameter view: Left edge view.
     
     - Parameter touchView: Touch area view where added left edge view.
     
     - Parameter state: User interaction state.
     */
    
    open func layoutLeftEdgeView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        
        var color: UIColor
        var width: CGFloat
        
        if state == .normal {
            color = configuraiton.edge.normalLineColor
            width = configuraiton.edge.normalLineWidth
        } else {
            color = configuraiton.edge.highlightedLineColor
            width = configuraiton.edge.highlightedLineWidth
        }
        
        view.backgroundColor = color
        view.frame = CGRect(
            x       : touchView.bounds.midX - width,
            y       : touchView.bounds.origin.y - configuraiton.cornerTouchSize.height / 2 - configuraiton.edge.normalLineWidth,
            width   : width,
            height  : touchView.bounds.size.height + configuraiton.cornerTouchSize.height + configuraiton.edge.normalLineWidth * 2)
    }
    
    /**
     Visual representation for top left corner view in current user interaction state. Drawing going with added shape layer.
     
     - Parameter view: Top left corner view.
     
     - Parameter touchView: Touch area view where added top left edge view.
     
     - Parameter state: User interaction state.
     */
    
    open func layoutTopLeftCornerView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        
        var lineWidth: CGFloat
        let layer: CAShapeLayer = view.layer.sublayers!.first as! CAShapeLayer
        
        if state == .normal {
            
            layer.fillColor = configuraiton.corner.normalLineColor.cgColor
            view.frame.size = configuraiton.corner.normaSize
            lineWidth = configuraiton.corner.normalLineWidth
            
        } else {
            
            layer.fillColor = configuraiton.edge.highlightedLineColor.cgColor
            view.frame.size = configuraiton.corner.highlightedSize
            lineWidth = configuraiton.corner.highlightedLineWidth
        }
        
        view.center = CGPoint(x: touchView.bounds.midX, y: touchView.bounds.midY)
        
        let rect = CGRect(origin: CGPoint(x: view.bounds.midX - lineWidth, y: view.bounds.midY - lineWidth), size: view.frame.size)
        
        let substractRect = CGRect(
            x       : rect.origin.x + lineWidth,
            y       : rect.origin.y + lineWidth,
            width   : rect.size.width - lineWidth,
            height  : rect.size.height - lineWidth)
        
        let path = UIBezierPath(rect: rect)
        path.append(UIBezierPath(rect: substractRect).reversing())
        
        layer.path = path.cgPath
    }
    
    /**
     Visual representation for top right corner view in current user interaction state. Drawing going with added shape layer.
     
     - Parameter view: Top right corner view.
     
     - Parameter touchView: Touch area view where added top right edge view.
     
     - Parameter state: User interaction state.
     */
    
    open func layoutTopRightCornerView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        
        var lineWidth: CGFloat
        let layer: CAShapeLayer = view.layer.sublayers!.first as! CAShapeLayer
        
        if state == .normal {
            
            layer.fillColor = configuraiton.corner.normalLineColor.cgColor
            view.frame.size = configuraiton.corner.normaSize
            lineWidth = configuraiton.corner.normalLineWidth
            
        } else {
            
            layer.fillColor = configuraiton.edge.highlightedLineColor.cgColor
            view.frame.size = configuraiton.corner.highlightedSize
            lineWidth = configuraiton.corner.highlightedLineWidth
        }
        
        view.center = CGPoint(x: touchView.bounds.midX, y: touchView.bounds.midY)
        
        let rect = CGRect(origin: CGPoint(x: -view.bounds.midX + lineWidth, y: view.bounds.midY - lineWidth), size: view.frame.size)
        
        let substractRect = CGRect(
            x       : rect.origin.x,
            y       : rect.origin.y + lineWidth,
            width   : rect.size.width - lineWidth,
            height  : rect.size.height - lineWidth)
        
        let path = UIBezierPath(rect: rect)
        
        path.append(UIBezierPath(rect: substractRect).reversing())
        layer.path = path.cgPath
    }
    
    /**
     Visual representation for bottom right corner view in current user interaction state. Drawing going with added shape layer.
     
     - Parameter view: Bottom right corner view.
     
     - Parameter touchView: Touch area view where added bottom right edge view.
     
     - Parameter state: User interaction state.
     */
    
    open func layoutBottomRightCornerView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        
        var lineWidth: CGFloat
        let layer: CAShapeLayer = view.layer.sublayers!.first as! CAShapeLayer
        
        if state == .normal {
            
            layer.fillColor = configuraiton.corner.normalLineColor.cgColor
            view.frame.size = configuraiton.corner.normaSize
            lineWidth = configuraiton.corner.normalLineWidth
            
        } else {
            
            layer.fillColor = configuraiton.edge.highlightedLineColor.cgColor
            view.frame.size = configuraiton.corner.highlightedSize
            lineWidth = configuraiton.corner.highlightedLineWidth
        }
        
        view.center = CGPoint(x: touchView.bounds.midX, y: touchView.bounds.midY)
        
        let rect = CGRect(origin: CGPoint(x: -view.bounds.midX + lineWidth, y: -view.bounds.midY + lineWidth), size: view.frame.size)
        
        let substractRect = CGRect(
            x       : rect.origin.x,
            y       : rect.origin.y,
            width   : rect.size.width - lineWidth,
            height  : rect.size.height - lineWidth)
        
        let path = UIBezierPath(rect: rect)
        
        path.append(UIBezierPath(rect: substractRect).reversing())
        layer.path = path.cgPath
    }
    
    /**
     Visual representation for bottom left corner view in current user interaction state. Drawing going with added shape layer.
     
     - Parameter view: Bottom left corner view.
     
     - Parameter touchView: Touch area view where added bottom left edge view.
     
     - Parameter state: User interaction state.
     */
    
    open func layoutBottomLeftCornerView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        
        var lineWidth: CGFloat
        let layer: CAShapeLayer = view.layer.sublayers!.first as! CAShapeLayer
        
        if state == .normal {
            
            layer.fillColor = configuraiton.corner.normalLineColor.cgColor
            view.frame.size = configuraiton.corner.normaSize
            lineWidth = configuraiton.corner.normalLineWidth
            
        } else {
            
            layer.fillColor = configuraiton.edge.highlightedLineColor.cgColor
            view.frame.size = configuraiton.corner.highlightedSize
            lineWidth = configuraiton.corner.highlightedLineWidth
        }
        
        view.center = CGPoint(x: touchView.bounds.midX, y: touchView.bounds.midY)
        
        let rect = CGRect(origin: CGPoint(x: view.bounds.midX - lineWidth, y: -view.bounds.midY + lineWidth), size: view.frame.size)
        
        let substractRect = CGRect(
            x       : rect.origin.x + lineWidth,
            y       : rect.origin.y,
            width   : rect.size.width - lineWidth,
            height  : rect.size.height - lineWidth)
        
        let path = UIBezierPath(rect: rect)
        
        path.append(UIBezierPath(rect: substractRect).reversing())
        layer.path = path.cgPath
    }
    
    /**
     
     Visual representation for grid view.
     
     - Parameter view: Grid view.
     
     - Parameter gridViewHorizontalLines: Horizontal line view`s array.
     
     - Parameter gridViewVerticalLines: Vertical line view`s array.
     */
    
    open func layoutGridView(_ view: UIView, gridViewHorizontalLines: [UIView], gridViewVerticalLines: [UIView]) {
        
        for (i, line) in gridViewHorizontalLines.enumerated() {
            
            line.frame.origin = CGPoint(x: 0, y: view.frame.height * CGFloat(i + 1) / CGFloat(gridViewHorizontalLines.count + 1))
            line.frame.size.width = view.frame.width
        }
        
        for (i, line) in gridViewVerticalLines.enumerated() {
            
            line.frame.origin = CGPoint(x: view.frame.width * CGFloat(i + 1) / CGFloat(gridViewVerticalLines.count + 1), y: 0)
            line.frame.size.height = view.frame.height
        }
    }
    
    // MARK: - Touches
    
    override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        guard let touch = touches.first else {  return }
        
        /* Save */
        
        touchesBegan = (touch.location(in: self), cropRect)

        /* Active part */
        
        activeCropAreaPart = getCropAreaPartContainsPoint(touchesBegan.touch)
    }
    
    override open func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
  
        guard let touch = touches.first else { return }

        /* GET TRANSLATION POINT */
   
        let point = touch.location(in: self)
        let previousPoint = touch.previousLocation(in: self)
        
        let translationPoint = CGPoint(x: point.x - previousPoint.x, y: point.y - previousPoint.y)
        
        /* MOVE FRAME */
        
        let cropRectMaxFrame = cropperView.reversedFrameWithInsets
        
        if activeCropAreaPart.contains(.topEdge) {
            
            cropRect.origin.y += translationPoint.y
            cropRect.size.height -= translationPoint.y
            
            let pointInEdge = touchesBegan.touch.y - touchesBegan.cropRect.minY
            let minStickPoint = pointInEdge + cropRectMaxFrame.minY
            let maxStickPoint = pointInEdge + touchesBegan.cropRect.maxY - configuraiton.minCropRectSize.height
            
            if point.y > maxStickPoint || cropRect.height < configuraiton.minCropRectSize.height {
                cropRect.origin.y = touchesBegan.cropRect.maxY - configuraiton.minCropRectSize.height
                cropRect.size.height = configuraiton.minCropRectSize.height
            }
            
            if point.y < minStickPoint {
                cropRect.origin.y = cropRectMaxFrame.minY
                cropRect.size.height = touchesBegan.cropRect.maxY - cropRectMaxFrame.minY
            }
        }
        
        if activeCropAreaPart.contains(.rightEdge) {
            
            cropRect.size.width += translationPoint.x
            
            let pointInEdge = touchesBegan.touch.x - touchesBegan.cropRect.maxX
            let minStickPoint = pointInEdge + touchesBegan.cropRect.minX + configuraiton.minCropRectSize.width
            let maxStickPoint = pointInEdge + cropRectMaxFrame.maxX
            
            if  point.x > maxStickPoint {
                cropRect.size.width =  cropRectMaxFrame.maxX - cropRect.origin.x
            }
            
            if point.x < minStickPoint || cropRect.width < configuraiton.minCropRectSize.width {
                cropRect.size.width = configuraiton.minCropRectSize.width
            }
        }
        
        if activeCropAreaPart.contains(.bottomEdge) {

            cropRect.size.height += translationPoint.y
            
            let pointInEdge = touchesBegan.touch.y - touchesBegan.cropRect.maxY
            let minStickPoint = pointInEdge + touchesBegan.cropRect.minY + configuraiton.minCropRectSize.height
            let maxStickPoint = pointInEdge + cropRectMaxFrame.maxY
            
            if  point.y > maxStickPoint {
                cropRect.size.height = cropRectMaxFrame.maxY - cropRect.origin.y
            }
            
            if point.y < minStickPoint || cropRect.height < configuraiton.minCropRectSize.height {
                cropRect.size.height = configuraiton.minCropRectSize.height
            }
        }
        
        if activeCropAreaPart.contains(.leftEdge) {
            
            cropRect.origin.x += translationPoint.x
            cropRect.size.width -= translationPoint.x
            
            let pointInEdge = touchesBegan.touch.x - touchesBegan.cropRect.minX
            let minStickPoint = pointInEdge + cropRectMaxFrame.minX
            let maxStickPoint = pointInEdge + touchesBegan.cropRect.maxX - configuraiton.minCropRectSize.width
            
            if  point.x > maxStickPoint || cropRect.width < configuraiton.minCropRectSize.width {
                cropRect.origin.x = touchesBegan.cropRect.maxX - configuraiton.minCropRectSize.width
                cropRect.size.width = configuraiton.minCropRectSize.width
            }
            
            if point.x < minStickPoint {
                cropRect.origin.x = cropRectMaxFrame.minX
                cropRect.size.width = touchesBegan.cropRect.maxX - cropRectMaxFrame.minX
            }
        }

        /* Update UI for the crop rectange */
        
        layoutSubviews()
        
        /* Delegates */
        
        delegate?.cropperOverlayViewDidChangeCropRect(self, cropRect)
    }
    
    override open func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        /* Active part */
        
        activeCropAreaPart = .none
    }
    
    // MARK: - Instance Method
    
    override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
                
        guard alpha == 1 else { return cropperView.scrollView }
        
        return self.point(inside: point, with: event) && getCropAreaPartContainsPoint(point) != .none
            ? self
            : cropperView.scrollView
    }
    
    // MARK: - Match Foreground To Background
    
    func matchForegroundToBackgroundScrollViewOffset() {
        imageView.frame.origin = CGPoint(
            x: -(cropperView.scrollView.contentOffset.x + containerImageView.frame.origin.x),
            y: -(cropperView.scrollView.contentOffset.y + containerImageView.frame.origin.y))
    }
    
    func matchForegroundToBackgroundScrollViewSize() {
        imageView.frame.size = cropperView.scrollView.contentSize
    }
}


================================================
FILE: AKImageCropperView/AKImageCropperOverlayViewConfiguration.swift
================================================
//
//  AKImageCropperCropViewConfiguration.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

import UIKit

/// Overlay view configuration struct.
public struct AKImageCropperCropViewConfiguration {
    
    public init() {}
    
    //  MARK: Crop rectangle
    
    /// Delay before the crop rectangle will scale to fit cropper view frame edges.
    public var zoomingToFitDelay: TimeInterval = 1.0

    /**
     Animation options for layout transitions.
     
     -  duration: The duration of the transition animation, measured in seconds.     
     -  options: Specifies the supported animation curves.
     */
    public var animation: (duration: TimeInterval, options: UIViewAnimationOptions) = (duration: 0.3, options: .curveEaseInOut)

    /// Edges insets for crop rectangle. Static values for programmatically rotation.
    
    public var cropRectInsets = UIEdgeInsetsMake(20, 20, 20, 20)
    
    /// The smallest value for the crop rectangle sizes. Initial value of this property is 60 pixels width and 60 pixels height.
    public var minCropRectSize: CGSize = CGSize(width: 60, height: 60)
    
    /// Touch view where will be drawn the corner.
    public var cornerTouchSize: CGSize = CGSize(width: 30.0, height: 30.0)
    
    /**
     Thickness for edges touch area. This touch view is centered on the edge line.
     
     -  vertical: Thickness for vertical edges: Left, Right.
     -  horizontal: Thickness for horizontal edges: Top, Bottom.
     */
    public var edgeTouchThickness: (vertical: CGFloat, horizontal: CGFloat) = (vertical: 20.0, horizontal: 20.0)

    //  MARK: Visual Appearance
    
    /// Overlay visual configuration.
    public var overlay = AKImageCropperCropViewConfigurationOverlay()
    
    /// Edges visual configuration.
    public var edge = AKImageCropperCropViewConfigurationEdge()
    
    /// Corners visual configuration.
    public var corner = AKImageCropperCropViewConfigurationCorner()
    
    /// Grid visual configuration.    
    public var grid = AKImageCropperCropViewConfigurationGrid()
}


================================================
FILE: AKImageCropperView/AKImageCropperOverlayViewConfigurationCorner.swift
================================================
//
//  AKImageCropperCropViewConfigurationCorner.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

import UIKit

/// Corners configuration struct.
public struct AKImageCropperCropViewConfigurationCorner {

    /// A Boolean value that determines whether the corner view is hidden.
    public var isHidden: Bool = false

    /// Line width for normal corner state.
    public var normalLineWidth: CGFloat = 3.0
     
    /// Line width for highlighted corner state.
    public var highlightedLineWidth: CGFloat = 3.0
    
    /// Size for normal corner state.
    public var normaSize: CGSize = CGSize(width: 20, height: 20)
    
    /// Size for highlighted corner state.
    public var highlightedSize: CGSize = CGSize(width: 30, height: 30)
    
    /// Line color for normal corner state.
    public var normalLineColor: UIColor = .white
    
    /// Line color for highlighted corner state.    
    public var highlightedLineColor: UIColor = .white
}


================================================
FILE: AKImageCropperView/AKImageCropperOverlayViewConfigurationEdge.swift
================================================
//
//  AKImageCropperCropViewConfigurationEdge.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

import UIKit

/// Edges configuration struct.
public struct AKImageCropperCropViewConfigurationEdge {
   
    /// A Boolean value that determines whether the edge view is hidden.
    public var isHidden: Bool = false
    
    /// Line width for normal edge state.
    public var normalLineWidth: CGFloat = 1.0
    
    /// Line width for highlighted edge state.
    public var highlightedLineWidth: CGFloat = 3.0
    
    /// Line color for normal edge state.
    public var normalLineColor: UIColor = .white
   
    /// Line color for highlighted edge state.
    public var highlightedLineColor: UIColor = .white
}


================================================
FILE: AKImageCropperView/AKImageCropperOverlayViewConfigurationGrid.swift
================================================
//
//  AKImageCropperCropViewConfigurationGrid.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

import UIKit

/// Grid visual configuration struct.
public struct AKImageCropperCropViewConfigurationGrid {
    
    /// A Boolean value that determines whether the edge view is hidden.
    public var isHidden: Bool = false
    
    /// Hide grid after user interaction.
    public var alwaysShowGrid: Bool = false
    
    /**
     The number of vertical and horizontal lines inside the crop rectangle.
     
     -  vertical: Vertical lines count.     
     -  horizontal: Horizontal lines count.
     */    
    public var linesCount: (vertical: Int, horizontal: Int) = (vertical: 2, horizontal: 2)
    
    /// Vertical and horizontal lines width.
    public var linesWidth: CGFloat = 1.0
   
    /// Vertical and horizontal lines color.
    public var linesColor: UIColor = UIColor.white.withAlphaComponent(0.5)
}


================================================
FILE: AKImageCropperView/AKImageCropperOverlayViewConfigurationOverlay.swift
================================================
//
//  AKImageCropperCropViewConfigurationOverlay.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

import UIKit

/// Overlay configuration struct.
public struct AKImageCropperCropViewConfigurationOverlay {
    
    /// The view’s background color.
    public var backgroundColor: UIColor = UIColor.black.withAlphaComponent(0.5)
    
    /// A Boolean value that determines whether the blur effect is enable.
    ///
    /// The blur effect added over overlay view. The effect will disappear before user interaction will start. After manipulations, the effect will revert to the initial state.
    public var isBlurEnabled: Bool = true
    
    /// The intensity of the blur effect.
    public var blurStyle: UIBlurEffectStyle = .dark
    
    /// The blur effect alpha value.
    public var blurAlpha: CGFloat = 0.6
}


================================================
FILE: AKImageCropperView/AKImageCropperOverlayViewTouchState.swift
================================================
//
//  AKImageCropperCropViewTouchState.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

/// User interaction state for edge or corner.
public enum AKImageCropperCropViewTouchState {

    /// Default, relase
    case normal

    /// Press, touch, etc.    
    case highlighted
}


================================================
FILE: AKImageCropperView/AKImageCropperScrollView.swift
================================================
//
//  AKImageCropperScrollView.swift
//  AKImageCropperView
//
//  Created by Artem Krachulov on 12/17/16.
//  Copyright © 2016 Artem Krachulov. All rights reserved.
//

import UIKit

final class AKImageCropperScrollView: UIScrollView {
    
    // MARK: -
    // MARK: ** Properties **
    
    /** Return visible rect of an UIScrollView's content */
    
    open var visibleRect: CGRect {
        return CGRect(
            x       : contentInset.left,
            y       : contentInset.top,
            width   : frame.size.width  - contentInset.left - contentInset.right,
            height  : frame.size.height - contentInset.top - contentInset.bottom)
    }
    
    /** Returns scaled visible rect of an UIScrollView's content  */
    
    open var scaledVisibleRect: CGRect {
        return CGRect(
            x       : (contentOffset.x + contentInset.left) / zoomScale,
            y       : (contentOffset.y + contentInset.top) / zoomScale,
            width   : visibleRect.size.width / zoomScale,
            height  : visibleRect.size.height / zoomScale)
    }
    
    // MARK: -
    // MARK: ** Initialization OBJECTS(VIEWS) & theirs parameters **
    
    fileprivate lazy var imageView: UIImageView! = {
        let view = UIImageView()
        return view
    }()
    
    open var image: UIImage! {
        didSet {
            
            /* Prepare scroll view to changing the image */
            
            maximumZoomScale = 1
            minimumZoomScale = 1
            zoomScale = 1
            
            /* Update an image view */
            
            imageView.image = image
            imageView.frame.size = image.size
            
            contentSize = image.size
        }
    }
    
    //  MARK: - Initialization
    
    /** Returns an scroll view initialized object. */
    
    init() {
        super.init(frame: .zero)
        
        alwaysBounceVertical = true
        alwaysBounceHorizontal = true
        showsVerticalScrollIndicator = false
        showsHorizontalScrollIndicator = false
        
        addSubview(imageView)
    }
    
    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


================================================
FILE: AKImageCropperView/AKImageCropperView.h
================================================
//
//  AKImageCropperView.h
//  AKImageCropperView
//
//  Created by Artem Krachulov on 12/13/16.
//  Copyright © 2016 Artem Krachulov. All rights reserved.
//

#import <UIKit/UIKit.h>

//! Project version number for AKImageCropperView.
FOUNDATION_EXPORT double AKImageCropperViewVersionNumber;

//! Project version string for AKImageCropperView.
FOUNDATION_EXPORT const unsigned char AKImageCropperViewVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <AKImageCropperView/PublicHeader.h>




================================================
FILE: AKImageCropperView/AKImageCropperView.swift
================================================
//
//  AKImageCropperView.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

import UIKit

typealias CGPointPercentage = CGPoint

open class AKImageCropperView: UIView, UIScrollViewDelegate, UIGestureRecognizerDelegate, AKImageCropperOverlayViewDelegate {
    
    /** Current rotation angle */
    
    fileprivate var angle: Double = 0.0
    
    /** Scroll view minimum edge insets (current value) */
    
    fileprivate var minEdgeInsets: UIEdgeInsets = .zero
    
    /** Reversed frame direct to current rotation angle */
    
    fileprivate var reversedRect: CGRect {
        return CGRect(
            origin  : .zero,
            size    : ((angle / M_PI_2).truncatingRemainder(dividingBy: 2)) == 1
                ? CGSize(width: frame.size.height, height: frame.size.width)
                : frame.size)
    }
    
    /** Reversed minimum edge insets direct to current rotation angle */
    
    fileprivate var reversedEdgeInsets: UIEdgeInsets {
        
        var newEdgeInsets: UIEdgeInsets
        
        switch angle {
        case M_PI_2:
            newEdgeInsets = UIEdgeInsetsMake(
                minEdgeInsets.right,
                minEdgeInsets.top,
                minEdgeInsets.left,
                minEdgeInsets.bottom)
        case M_PI:
            newEdgeInsets = UIEdgeInsetsMake(
                minEdgeInsets.bottom,
                minEdgeInsets.right,
                minEdgeInsets.top,
                minEdgeInsets.left)
        case M_PI_2 * 3:
            newEdgeInsets = UIEdgeInsetsMake(
                minEdgeInsets.left,
                minEdgeInsets.bottom,
                minEdgeInsets.right,
                minEdgeInsets.top)
        default:
            newEdgeInsets = minEdgeInsets
        }
        
        return newEdgeInsets
    }
    
    /** Reversed frame + edgeInsets direct to current rotation angle */
    
    var reversedFrameWithInsets: CGRect {
        return UIEdgeInsetsInsetRect(reversedRect, reversedEdgeInsets)
    }
    
    // MARK: -
    // MARK: ** Saved properties **
    
    fileprivate struct SavedProperty {
        
        var scaleAspectRatio: CGFloat!
        var contentOffset: CGPoint!
        var contentOffsetPercentage: CGPoint!
        var cropRectSize: CGSize!
        
        init() {
            scaleAspectRatio = 1.0
            contentOffset = .zero
            contentOffsetPercentage = .zero
            cropRectSize = .zero
        }
        
        mutating func save(scrollView: AKImageCropperScrollView) {
            
            scaleAspectRatio = scrollView.zoomScale / scrollView.minimumZoomScale
            
            contentOffset = CGPoint(
                x: scrollView.contentOffset.x + scrollView.contentInset.left,
                y: scrollView.contentOffset.y + scrollView.contentInset.top)

            let contentSize = CGSize(
                width   : (scrollView.contentSize.width - scrollView.visibleRect.width).ic_roundTo(precision: 3),
                height  : (scrollView.contentSize.height - scrollView.visibleRect.height).ic_roundTo(precision: 3))

            contentOffsetPercentage = CGPointPercentage(
                x: (contentOffset.x > 0 && contentSize.width != 0)
                    ? ic_round(x: contentOffset.x / contentSize.width, multiplier: 0.005)
                    : 0,
                y: (contentOffset.y > 0 && contentSize.height != 0)
                    ? ic_round(x: contentOffset.y / contentSize.height, multiplier: 0.005)
                    : 0)
            
            cropRectSize = scrollView.visibleRect.size
        }
    }
    
    /** Saved Scroll View parameters before complex layout animation */
    
    fileprivate var savedProperty = SavedProperty()
    
    // MARK: Accessing the Displayed Images
    
    /** The image displayed in the image cropper view. Default is nil. */
    
    open var image: UIImage? {
        didSet {
            
            guard let image = image else {
                return
            }
            
            scrollView.image = image
            overlayView?.image = image
            
            reset()
        }
    }
    
    /** Cropperd image in the specified crop rectangle */
    
    open var croppedImage: UIImage? {
        return image?.ic_imageInRect(scrollView.scaledVisibleRect)?.ic_rotateByAngle(angle)
    }
    
    // MARK: States
    
    /** Returns the image edited state flag. */
    
    open var isEdited: Bool {
        
        guard let image = image else {
            return false
        }

        let fitScaleMultiplier = ic_CGSizeFitScaleMultiplier(image.size, relativeToSize: reversedFrameWithInsets.size)
        
        return angle != 0 || fitScaleMultiplier != scrollView.minimumZoomScale || fitScaleMultiplier != scrollView.zoomScale
    }
    
    /** Determines the overlay view current state. Default is false. */
    
    open private(set) var isOverlayViewActive: Bool = false
    
    fileprivate var layoutByImage: Bool = true
    
    /** Сompletion blocker. */
    
    fileprivate var isAnimation: Bool = false
    
    // MARK: Managing the Delegate
    
    /** The delegate of the cropper view object. */
    
    weak open var delegate: AKImageCropperViewDelegate?

    // MARK: - 
    // MARK: ** Initialization OBJECTS(VIEWS) & theirs parameters **
    
    // MARK: Rotate view
    
    fileprivate lazy var rotateView: UIView! = {
        let view = UIView()
        view.clipsToBounds = true
        return view
    }()
    
    // MARK: Scroll view

    var scrollView: AKImageCropperScrollView!
    
    // MARK: Overlay Crop view
    
    open var overlayView: AKImageCropperOverlayView? {
        willSet  {
            
            if overlayView != nil {
                overlayView?.removeFromSuperview()
            }
            
            if newValue != nil {
                newValue?.delegate = self
                newValue?.cropperView = self
                rotateView.addSubview(newValue!)
            }
            
            layoutSubviews()
        }
    }
    
    // MARK: - Initializing an Image Cropper View
    
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        initialize()
    }
    
    override public init(frame: CGRect) {
        super.init(frame: frame)
        
        initialize()
    }
    
    /**
     Returns an image cropper view initialized with the specified image.
     
     - Parameter image: The initial image to display in the image cropper view.
     */
    
    public init(image: UIImage?) {
        super.init(frame:CGRect.zero)
        
        initialize()
        
        self.image = image
    }
    
    fileprivate func initialize() {
        
        /*
         Create views layout.
         Step by step
         
         1. Scroll view ‹‹ Image view
         */

        scrollView = AKImageCropperScrollView()
        scrollView.delegate = self
        rotateView.addSubview(scrollView)
        
        /* 2. Overlay view with crop rectangle */
        
        overlayView = AKImageCropperOverlayView()
        
        /* 3. Rotate view */
        
        addSubview(rotateView)
        
        /**
         Add Observers
         To controll all parameters changing and pass them to foreground image view
         */
        
        initObservers()
        
        let pressGesture = UILongPressGestureRecognizer(target: self, action: #selector(pressGestureAction(_ :)))
        pressGesture.minimumPressDuration = 0
        pressGesture.cancelsTouchesInView = false
        pressGesture.delegate = self
        addGestureRecognizer(pressGesture)
    }
    
    @objc fileprivate func pressGestureAction(_ gesture: UITapGestureRecognizer) {
        if gesture.state == .began {
            beforeInteraction()
        } else if gesture.state == .cancelled || gesture.state == .ended {
            afterInteraction()
        }
    }
    
    // MARK: - UIGestureRecognizerDelegate
    
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
 
    deinit {
        removeObservers()
        
        #if AKImageCropperViewDEBUG
            print("deinit AKImageCropperView")
        #endif
    }
    
    // MARK: - Observe Scroll view values
    
    fileprivate func initObservers() {
        for forKeyPath in ["contentOffset", "contentSize"] {
            scrollView.addObserver(self, forKeyPath: forKeyPath, options: [.new, .old], context: nil)
        }
    }
    
    open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        guard let keyPath = keyPath else {
            return
        }
        
        switch keyPath {
        case "contentOffset":
            if let _ = change![NSKeyValueChangeKey.newKey] {
                 overlayView?.matchForegroundToBackgroundScrollViewOffset()
            }
        case "contentSize":
            if let _ = change![NSKeyValueChangeKey.newKey] {
                overlayView?.matchForegroundToBackgroundScrollViewSize()
            }
        default: ()
        }
    }
    
    fileprivate func removeObservers() {
        for forKeyPath in ["contentOffset", "contentSize"] {
            scrollView.removeObserver(self, forKeyPath: forKeyPath)
        }
    }
    
    // MARK: - Life cycle
    
    override open func layoutSubviews() {
        super.layoutSubviews()
     
        layoutSubviews(byImage: layoutByImage)
    }
    
    func layoutSubviews(byImage: Bool) {
        
        rotateView.frame = CGRect(origin: .zero, size: self.frame.size)
        
        let frame = reversedRect
        
        let reversedFrameWithInsetsSize = reversedFrameWithInsets.size
        
        if byImage {
            
            /* Zoom */
            
            let fitScaleMultiplier = image == nil
                ? 1
                : ic_CGSizeFitScaleMultiplier(image!.size, relativeToSize: reversedFrameWithInsetsSize)
            
            
            scrollView.maximumZoomScale = fitScaleMultiplier * 1000
            scrollView.minimumZoomScale = fitScaleMultiplier
            scrollView.zoomScale = fitScaleMultiplier * savedProperty.scaleAspectRatio
            
        } else {
            
            /* Zoom */
            
            let fitScaleMultiplier = ic_CGSizeFitScaleMultiplier(scrollView.visibleRect.size, relativeToSize: reversedFrameWithInsetsSize)
            
            scrollView.maximumZoomScale *= fitScaleMultiplier
            scrollView.minimumZoomScale *= fitScaleMultiplier
            scrollView.zoomScale *= fitScaleMultiplier
            
            /* Content inset */
            
            var size: CGSize
            
            if overlayView?.alpha == 1 {
                
                size = CGSize(
                    width   : scrollView.visibleRect.size.width * fitScaleMultiplier,
                    height  : scrollView.visibleRect.size.height * fitScaleMultiplier)
                
            } else {
                
                size = ic_CGSizeFits(scrollView.contentSize, minSize: .zero, maxSize: reversedFrameWithInsetsSize)
            }
            
            scrollView.contentInset = centeredInsets(from: size, to: reversedFrameWithInsetsSize)
            
            /* Content offset */
            
            let savedFitScaleMultiplier = ic_CGSizeFitScaleMultiplier(savedProperty.cropRectSize, relativeToSize: reversedFrameWithInsetsSize)
            
            var contentOffset = CGPoint(
                x: savedProperty.contentOffset.x * savedFitScaleMultiplier,
                y: savedProperty.contentOffset.y * savedFitScaleMultiplier)
            
            contentOffset.x -= scrollView.contentInset.left
            contentOffset.y -= scrollView.contentInset.top
            
            scrollView.contentOffset = contentOffset
        }
        
        scrollView.frame = frame
        
        overlayView?.frame = frame
        overlayView?.cropRect = scrollView.visibleRect
        overlayView?.layoutSubviews()
    }

    // MARK: -
    // MARK: ** Actions **
    
    // MARK: Overlay actions
    
    /**
     Show the overlay view with crop rectangle.
     
     - Parameter duration: The total duration of the animations, measured in seconds. If you specify a negative value or 0, the changes are made without animating them. Default value is 0.
     
     - Parameter options: A mask of options indicating how you want to perform the animations. For a list of valid constants, see UIViewAnimationOptions. Default value is .curveEaseInOut.
     
     - Parameter completion: A block object to be executed when the animation sequence ends. This block has no return value and takes a single Boolean argument that indicates whether or not the animations actually finished before the completion handler was called. If the duration of the animation is 0, this block is performed at the beginning of the next run loop cycle. This parameter may be NULL.
     */
    
    open func showOverlayView(animationDuration duration: TimeInterval = 0, options: UIViewAnimationOptions = .curveEaseInOut, completion: ((Bool) -> Void)? = nil) {
        
        guard let image = image, let overlayView = overlayView, !isOverlayViewActive && !isAnimation else {
            return
        }
        
        minEdgeInsets = overlayView.configuraiton.cropRectInsets
        savedProperty.save(scrollView: scrollView)
        cancelZoomingTimer()
        
        let _animations: () -> Void = { _ in
            
            self.layoutSubviews()
            
            // Update scroll view content offsets using active zooming scale and insets.
            
            self.scrollView.contentOffset = self.contentOffset(from: self.savedProperty.contentOffsetPercentage)
        }
        
        let _completion: (Bool) -> Void = { isFinished in
            
            // Update zoom relative to crop rext
            
            let fillScaleMultiplier = ic_CGSizeFillScaleMultiplier(image.size, relativeToSize: overlayView.cropRect.size)
            
            self.scrollView.maximumZoomScale = fillScaleMultiplier * 1000
            self.scrollView.minimumZoomScale = fillScaleMultiplier
            
            /* */
            
            self.isAnimation = false
            self.isOverlayViewActive = true
            
            completion?(isFinished)
        }
        
        /* Show */
        
        layoutByImage = false
        
        isAnimation = true
        
        if duration == 0 {
            _animations()
            overlayView.alpha = 1
            _completion(true)
        } else {
            UIView.animate(withDuration: duration, delay: 0, options: options, animations: _animations, completion: { _ in
                UIView.animate(withDuration: duration, delay: 0, options: options, animations: {
                    overlayView.alpha = 1
                }, completion: _completion)
            })
        }
    }
    
    /**
     Hide the overlay view with crop rectangle.
     
     - Parameter duration: The total duration of the animations, measured in seconds. If you specify a negative value or 0, the changes are made without animating them. Default value is 0.
     
     - Parameter options: A mask of options indicating how you want to perform the animations. For a list of valid constants, see UIViewAnimationOptions. Default value is .curveEaseInOut.
     
     - Parameter completion: A block object to be executed when the animation sequence ends. This block has no return value and takes a single Boolean argument that indicates whether or not the animations actually finished before the completion handler was called. If the duration of the animation is 0, this block is performed at the beginning of the next run loop cycle. This parameter may be NULL.
     */
    
    open func hideOverlayView(animationDuration duration: TimeInterval = 0, options: UIViewAnimationOptions = .curveEaseInOut, completion: ((Bool) -> Void)? = nil) {
        
        guard let image = image, let overlayView = overlayView, isOverlayViewActive && !isAnimation else {
            return
        }
        
        minEdgeInsets = .zero
        savedProperty.save(scrollView: scrollView)
        cancelZoomingTimer()
   
        isAnimation = true
        
        let _animations: () -> Void = { _ in
            
            self.layoutSubviews()
            
            /**
             Update scroll view content offsets
             using active zooming scale and insets.
             */
            
            self.scrollView.contentOffset = self.contentOffset(from: self.savedProperty.contentOffsetPercentage)
        }
        
        let _completion: (Bool) -> Void = { isFinished in

            // Update zoom relative to crop rext
            
            let fitScaleMultiplier = ic_CGSizeFitScaleMultiplier(image.size, relativeToSize: self.reversedFrameWithInsets.size)
 
            self.scrollView.maximumZoomScale = fitScaleMultiplier * 1000
            self.scrollView.minimumZoomScale = fitScaleMultiplier
            
            /* */
            
            self.isAnimation = false
            self.isOverlayViewActive = false
            self.layoutByImage = false
            
            completion?(isFinished)
        }
        
        if duration == 0 {
            overlayView.alpha = 0
            _animations()
            _completion(true)
        } else {
            UIView.animate(withDuration: duration, delay: 0, options: options, animations: {
                overlayView.alpha = 0
            }, completion: { _ in
                UIView.animate(withDuration: duration, delay: 0, options: options, animations: _animations, completion: _completion)
            })
        }
    }
    
    // MARK: Rotate
    
    /**
     Rotate the image on the angle in multiples of 90 degrees (M_PI_2).
     
     - Parameter angle: Rotation angle. The angle a multiple of 90 degrees (M_PI_2).
     
     - Parameter duration: The total duration of the animations, measured in seconds. If you specify a negative value or 0, the changes are made without animating them. Default value is 0.
     
     - Parameter options: A mask of options indicating how you want to perform the animations. For a list of valid constants, see UIViewAnimationOptions. Default value is .curveEaseInOut.
     
     - Parameter completion: A block object to be executed when the animation sequence ends. This block has no return value and takes a single Boolean argument that indicates whether or not the animations actually finished before the completion handler was called. If the duration of the animation is 0, this block is performed at the beginning of the next run loop cycle. This parameter may be NULL.
     */
    
    open func rotate(_ angle: Double, withDuration duration: TimeInterval = 0, options: UIViewAnimationOptions = .curveEaseInOut, completion: ((Bool) -> Void)? = nil) {
        
        guard angle.truncatingRemainder(dividingBy: M_PI_2) == 0 else {
            return
        }
        
        self.angle = angle
        savedProperty.save(scrollView: scrollView)
        
        let _animations: () -> Void = { _ in
            
            self.rotateView.transform = CGAffineTransform(rotationAngle: CGFloat(angle))
            self.layoutSubviews()
        }
        
        let _completion: (Bool) -> Void = { isFinished in
            completion?(isFinished)
        }
        
        if duration == 0 {
            _animations()
            _completion(true)
        } else {
            UIView.animate(withDuration: duration, delay: 0, options: options, animations: _animations, completion: _completion)
        }
    }
    
    // MARK: Reset
    
    /**
     Return Cropper view to the initial state.
     
     - Parameter duration: The total duration of the animations, measured in seconds. If you specify a negative value or 0, the changes are made without animating them. Default value is 0.
     
     - Parameter options: A mask of options indicating how you want to perform the animations. For a list of valid constants, see UIViewAnimationOptions. Default value is .curveEaseInOut.
     
     - Parameter completion: A block object to be executed when the animation sequence ends. This block has no return value and takes a single Boolean argument that indicates whether or not the animations actually finished before the completion handler was called. If the duration of the animation is 0, this block is performed at the beginning of the next run loop cycle. This parameter may be NULL.
     */
    
    open func reset(animationDuration duration: TimeInterval = 0, options: UIViewAnimationOptions = .curveEaseInOut, completion: ((Bool) -> Void)? = nil) {
        
        guard !isAnimation else {
            return
        }

        savedProperty = SavedProperty()
        angle = 0
        cancelZoomingTimer()
        
        let _animations: () -> Void = { _ in
            
            self.rotateView.transform = CGAffineTransform.identity
            
            let _layoutByImage = self.layoutByImage
            self.layoutByImage = true
            self.layoutSubviews()
            self.layoutByImage = _layoutByImage
            
        }
        
        let _completion: (Bool) -> Void = { isFinished in
            
            self.isAnimation = false
            completion?(isFinished)
        }
        
        isAnimation = true
        if duration == 0 {
            _animations()
            _completion(true)
        } else {
            UIView.animate(withDuration: duration, delay: 0, options: options, animations: _animations, completion: _completion)
        }
    }

    // MARK: - Edge insets zooming
    
    fileprivate var zoomingTimer: Timer?
    
    fileprivate func startZoomingTimer() {
        
        guard let overlayView = overlayView else {
            return
        }

        cancelZoomingTimer()
        
        zoomingTimer = Timer.scheduledTimer(timeInterval: overlayView.configuraiton.zoomingToFitDelay, target: self, selector: #selector(zoomAction), userInfo: nil, repeats: false)
    }
    
    @objc fileprivate func zoomAction() {
        
        guard let overlayView = overlayView else {
            return
        }
        
        savedProperty.save(scrollView: scrollView)
        
        overlayView.showGrid(false)
        overlayView.showOverlayBlur(true)

        UIView.animate(withDuration: overlayView.configuraiton.animation.duration, delay: 0, options: overlayView.configuraiton.animation.options, animations: {
            self.layoutSubviews()
        })
    }
    
    fileprivate func cancelZoomingTimer() {
        zoomingTimer?.invalidate()
        zoomingTimer = nil
    }
    
    // MARK: - After interaction actions    
    
    fileprivate func beforeInteraction() {
        
        guard let overlayView = overlayView, overlayView.alpha == 1.0  else {
            return
        }
        
        cancelZoomingTimer()
        
        overlayView.showGrid(true)
        overlayView.showOverlayBlur(false)
    }
    
    fileprivate func afterInteraction() {
        
        guard let overlayView = overlayView, overlayView.alpha == 1.0  else {
            return
        }
        
        startZoomingTimer()

        savedProperty.save(scrollView: scrollView)
    }
    
    // MARK: - Helper methods
    
    private func centeredInsets(from size: CGSize, to relativeSize: CGSize) -> UIEdgeInsets {
        
        let center = ic_CGPointCenters(size, relativeToSize: relativeSize)
        
        // Fix insets direct to orientation
        
        return UIEdgeInsetsMake(
            center.y + minEdgeInsets.top,
            center.x + minEdgeInsets.left,
            center.y + minEdgeInsets.bottom,
            center.x + minEdgeInsets.right)
    }
    
    private func contentOffset(from savedContentOffsetPercentage: CGPointPercentage) -> CGPoint {

        var contentOffset = CGPoint(
            x: scrollView.contentInset.left > minEdgeInsets.left
                ? 0
                : ((scrollView.contentSize.width - reversedFrameWithInsets.size.width) * savedContentOffsetPercentage.x),
            y: scrollView.contentInset.top > minEdgeInsets.left
                ? 0
                : ((scrollView.contentSize.height - reversedFrameWithInsets.size.height) * savedContentOffsetPercentage.y))
        
        contentOffset.x -= scrollView.contentInset.left
        contentOffset.y -= scrollView.contentInset.top
        
        return contentOffset
    }
    
    //  MARK: - AKImageCropperOverlayViewDelegate
    
    func cropperOverlayViewDidChangeCropRect(_ view: AKImageCropperOverlayView, _ cropRect: CGRect) {
        
        scrollView.contentInset = UIEdgeInsetsMake(
            cropRect.origin.y,
            cropRect.origin.x,
            view.frame.size.height - cropRect.size.height - cropRect.origin.y,
            view.frame.size.width - cropRect.size.width - cropRect.origin.x)
        
        if cropRect.size.height > scrollView.contentSize.height || cropRect.size.width > scrollView.contentSize.width {
            
            let fillScaleMultiplier = ic_CGSizeFillScaleMultiplier(scrollView.contentSize, relativeToSize: cropRect.size)
            
            scrollView.maximumZoomScale *= fillScaleMultiplier
            scrollView.minimumZoomScale *= fillScaleMultiplier
            scrollView.zoomScale        *= fillScaleMultiplier
        }
    }
    
    // MARK: - UIScrollViewDelegate
    
    public func viewForZooming(in scrollView: UIScrollView) -> UIView? {        
        return scrollView.subviews.first
    }
    
    public func scrollViewDidZoom(_ scrollView: UIScrollView) {
        
        guard layoutByImage else {
            return
        }
  
        let size = ic_CGSizeFits(scrollView.contentSize, minSize: .zero, maxSize: reversedFrameWithInsets.size)
        
        scrollView.contentInset = centeredInsets(from: size, to: reversedFrameWithInsets.size)
    }
    
    public func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
        beforeInteraction()
    }
    
    public func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
        afterInteraction()
    }
    
    public func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
        beforeInteraction()
    }
    
    public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        afterInteraction()
    }
}

//  MARK: - AKImageCropperViewDelegate

public protocol AKImageCropperViewDelegate : class {
    
    /**
     Tells the delegate that crop frame was changed.
     
     - Parameter view : The image cropper view.
     - Parameter rect : New crop rectangle origin and size.
     */
    
    func imageCropperViewDidChangeCropRect(view: AKImageCropperView, cropRect rect: CGRect)
}

public extension AKImageCropperViewDelegate {    
    func imageCropperViewDidChangeCropRect(view: AKImageCropperView, cropRect rect: CGRect) {}
}


================================================
FILE: AKImageCropperView/IC_CGFloatExtension.swift
================================================
//
//  ic_CGFloatExtension.swift
//  AKImageCropperView
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//

import UIKit

extension CGFloat {
    
    /** Rounds the value to the nearest with precision. */

    public func ic_roundTo(precision: Int) -> CGFloat {
        let divisor = pow(10.0, CGFloat(precision))
        return (self * divisor).rounded() / divisor
    }
}

/** Rounds the value to the nearest with multiplier. */

public func ic_round(x: CGFloat, multiplier: CGFloat) -> CGFloat {
    return multiplier * round(x / multiplier)
}


================================================
FILE: AKImageCropperView/IC_CGPointExtension.swift
================================================
//
//  IC_CGPointExtension.swift
//  AKImageCropperView
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//

import Foundation

/** Return centered origin value relative to other size . */

func ic_CGPointCenters(_ size1: CGSize, relativeToSize size2: CGSize) -> CGPoint {
    return CGPoint(x: size2.width / 2 - size1.width / 2, y: size2.height / 2 - size1.height / 2)
}



================================================
FILE: AKImageCropperView/IC_CGSizeExtensions.swift
================================================
//
//  IC_CGSizeExtensions.swift
//  AKImageCropperView
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//

import Foundation

/** Returns fill scale value relative to target size with aspect ratio. */

func ic_CGSizeFitScaleMultiplier(_ size1: CGSize, relativeToSize size2: CGSize) -> CGFloat {
    
    guard size1.width != 0 && size1.height != 0 else { return 1.0 }
    
    return min(size2.height / size1.height, size2.width / size1.width)
}

/** Returns fill scale value relative to target size with aspect ratio. */

func ic_CGSizeFillScaleMultiplier(_ size1: CGSize, relativeToSize size2: CGSize) -> CGFloat {
    
    guard size1.width != 0 && size1.height != 0 else { return 1.0 }
    
    return max(size2.height / size1.height, size2.width / size1.width)
}

/** Returns size that fits min and max sizes. */

func ic_CGSizeFits(_ size: CGSize, minSize: CGSize, maxSize: CGSize) -> CGSize {
    
    var size = size
    
    if size.width > maxSize.width {
        size.width = maxSize.width
    }
    
    if size.height > maxSize.height {
        size.height = maxSize.height
    }
    
    if size.width < minSize.width {
        size.width = minSize.width
    }
    
    if size.height < minSize.height {
        size.height = minSize.height
    }
    
    return size
}


================================================
FILE: AKImageCropperView/IC_UIImageExtensions.swift
================================================
//
//  IC_UIImageExtensions.swift
//  AKImageCropperView
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//

import Foundation

extension UIImage {
    
    /** Returns image cropped from selected rectangle. */
    
    func ic_imageInRect(_ rect: CGRect) -> UIImage? {
        
        UIGraphicsBeginImageContext(rect.size)
        
        // Create the bitmap context
        
        guard let context = UIGraphicsGetCurrentContext() else {
            return nil
        }
        
        // Sets the clipping path to the intersection of the current clipping path with the area defined by the specified rectangle.
        
        context.clip(to: CGRect(origin: .zero, size: rect.size))
        
        self.draw(in: CGRect(origin: CGPoint(x: -rect.origin.x, y: -rect.origin.y), size: self.size))
        
        // Returns an image based on the contents of the current bitmap-based graphics context.
        
        let contextImage = UIGraphicsGetImageFromCurrentImageContext()
        
        UIGraphicsEndImageContext()
        
        return contextImage
    }
    
    /** Returns image rotated by specified angle. */
    
    func ic_rotateByAngle(_ angle: Double) -> UIImage? {
        
        // Calculate the size of the rotated view's containing box for our drawing space
        
        let rotatedViewBox = UIView(frame: CGRect(origin: .zero, size: self.size))
        rotatedViewBox.transform = CGAffineTransform(rotationAngle: CGFloat(angle))
        
        let rotatedSize = rotatedViewBox.frame.size
        
        UIGraphicsBeginImageContext(rotatedSize)
        
        // Create the bitmap context
        
        guard let context = UIGraphicsGetCurrentContext() else {
            return nil
        }
        
        context.translateBy(x: rotatedSize.width / 2.0, y: rotatedSize.height / 2.0)
        context.rotate(by: CGFloat(angle))
        
        self.draw(in: CGRect(origin: CGPoint(x: -self.size.width / 2, y: -self.size.height / 2), size: self.size))
        
        // Returns an image based on the contents of the current bitmap-based graphics context.
        let contextImage = UIGraphicsGetImageFromCurrentImageContext()
        
        UIGraphicsEndImageContext()
        
        return contextImage
    }
}


================================================
FILE: AKImageCropperView/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>en</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>FMWK</string>
	<key>CFBundleShortVersionString</key>
	<string>2.0.0</string>
	<key>CFBundleVersion</key>
	<string>$(CURRENT_PROJECT_VERSION)</string>
	<key>NSPrincipalClass</key>
	<string></string>
</dict>
</plist>


================================================
FILE: AKImageCropperView/PrimaryFilledButton.swift
================================================
//
//  PrimaryFilledButton.swift
//  Visitor
//
//  Created by Artem Krachulov on 1/16/17.
//  Copyright © 2017 VZPass. All rights reserved.
//

import Foundation


================================================
FILE: AKImageCropperView.podspec
================================================
Pod::Spec.new do |s|

  s.name         = "AKImageCropperView"
  s.version      = "2.0.0"
  s.homepage     = "https://github.com/artemkrachulov/AKImageCropperView"
  s.summary      = "Responsive image cropper"
  s.description  = <<-DESC
                   Image cropping plugin which supported different devices orientation. Easy to set up and configure. Has many settings for flexible integration into your project. Behavior is similar to native iOS photo cropper.
                   DESC

  s.license      = { :type => "MIT", :file => "LICENSE" }
  s.author       = { "Artem Krachulov" => "artem.krachulov@gmail.com"  }

  # Source Info

  s.ios.deployment_target = "8.0"

  s.source        = { 
    :git => "https://github.com/artemkrachulov/AKImageCropperView.git", 
    :tag => 'v'+s.version.to_s 
  }

  s.source_files  = "AKImageCropperView/*.{swift}"
  s.pod_target_xcconfig = { 'SWIFT_VERSION' => '3.0' }
end

================================================
FILE: AKImageCropperView.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 46;
	objects = {

/* Begin PBXBuildFile section */
		011028AB1DFFDD24002AA94E /* AKImageCropperView.h in Headers */ = {isa = PBXBuildFile; fileRef = 011028A91DFFDD24002AA94E /* AKImageCropperView.h */; settings = {ATTRIBUTES = (Public, ); }; };
		0141AF1D1E052BF6007C5672 /* AKImageCropperScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0141AF1C1E052BF6007C5672 /* AKImageCropperScrollView.swift */; };
		0155304A1E28F2C500961922 /* IC_UIImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 015530491E28F2C500961922 /* IC_UIImageExtensions.swift */; };
		0155304C1E28FDB800961922 /* IC_CGSizeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0155304B1E28FDB800961922 /* IC_CGSizeExtensions.swift */; };
		0155304E1E28FEC600961922 /* IC_CGPointExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0155304D1E28FEC600961922 /* IC_CGPointExtension.swift */; };
		0166B68F1E03E1560081B751 /* AKImageCropperOverlayViewConfigurationOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0166B68E1E03E1560081B751 /* AKImageCropperOverlayViewConfigurationOverlay.swift */; };
		016E5EF21DFFDD8300662D31 /* AKImageCropperOverlayViewTouchState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016E5EE71DFFDD8300662D31 /* AKImageCropperOverlayViewTouchState.swift */; };
		016E5EF31DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationCorner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016E5EE81DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationCorner.swift */; };
		016E5EF41DFFDD8300662D31 /* AKImageCropperOverlayViewConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016E5EE91DFFDD8300662D31 /* AKImageCropperOverlayViewConfiguration.swift */; };
		016E5EF61DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationEdge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016E5EEB1DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationEdge.swift */; };
		016E5EF71DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016E5EEC1DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationGrid.swift */; };
		016E5EF81DFFDD8300662D31 /* AKImageCropperOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016E5EED1DFFDD8300662D31 /* AKImageCropperOverlayView.swift */; };
		016E5EFB1DFFDD8300662D31 /* AKImageCropperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016E5EF01DFFDD8300662D31 /* AKImageCropperView.swift */; };
		016E5EFE1DFFE77400662D31 /* AKImageCropperView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 011028A71DFFDD24002AA94E /* AKImageCropperView.framework */; };
		016E5EFF1DFFE77400662D31 /* AKImageCropperView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 011028A71DFFDD24002AA94E /* AKImageCropperView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
		01C48FBC1DEC250100FBBE34 /* CustomImageCropperOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01C48FBB1DEC250100FBBE34 /* CustomImageCropperOverlayView.swift */; };
		01F61BE51E4DC7B800977E33 /* IC_CGFloatExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F61BE41E4DC7B800977E33 /* IC_CGFloatExtension.swift */; };
		01FA13EF1DDF0C6E006B8C3A /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FA13EE1DDF0C6E006B8C3A /* Constants.swift */; };
		4356D6141B8F3DE90033FDBD /* ImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4356D6131B8F3DE90033FDBD /* ImageViewController.swift */; };
		43CBB4031B870EBC00C8F9AE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CBB4021B870EBC00C8F9AE /* AppDelegate.swift */; };
		43CBB4051B870EBC00C8F9AE /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CBB4041B870EBC00C8F9AE /* HomeViewController.swift */; };
		43CBB4081B870EBC00C8F9AE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43CBB4061B870EBC00C8F9AE /* Main.storyboard */; };
		43CBB40A1B870EBC00C8F9AE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 43CBB4091B870EBC00C8F9AE /* Images.xcassets */; };
		43CBB40D1B870EBC00C8F9AE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43CBB40B1B870EBC00C8F9AE /* LaunchScreen.xib */; };
		43CBB4241B8716EA00C8F9AE /* CropperViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CBB4231B8716EA00C8F9AE /* CropperViewController.swift */; };
		43CBB4401B8739B100C8F9AE /* ImagesTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CBB43F1B8739B100C8F9AE /* ImagesTableViewController.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
		016E5F001DFFE77400662D31 /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = 43CBB3F51B870EBC00C8F9AE /* Project object */;
			proxyType = 1;
			remoteGlobalIDString = 011028A61DFFDD24002AA94E;
			remoteInfo = AKImageCropperView;
		};
/* End PBXContainerItemProxy section */

/* Begin PBXCopyFilesBuildPhase section */
		016E5F021DFFE77400662D31 /* Embed Frameworks */ = {
			isa = PBXCopyFilesBuildPhase;
			buildActionMask = 2147483647;
			dstPath = "";
			dstSubfolderSpec = 10;
			files = (
				016E5EFF1DFFE77400662D31 /* AKImageCropperView.framework in Embed Frameworks */,
			);
			name = "Embed Frameworks";
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
		011028A71DFFDD24002AA94E /* AKImageCropperView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AKImageCropperView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
		011028A91DFFDD24002AA94E /* AKImageCropperView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AKImageCropperView.h; sourceTree = "<group>"; };
		011028AA1DFFDD24002AA94E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		0141AF1C1E052BF6007C5672 /* AKImageCropperScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AKImageCropperScrollView.swift; sourceTree = "<group>"; };
		015530491E28F2C500961922 /* IC_UIImageExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IC_UIImageExtensions.swift; sourceTree = "<group>"; };
		0155304B1E28FDB800961922 /* IC_CGSizeExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IC_CGSizeExtensions.swift; sourceTree = "<group>"; };
		0155304D1E28FEC600961922 /* IC_CGPointExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IC_CGPointExtension.swift; sourceTree = "<group>"; };
		0166B68E1E03E1560081B751 /* AKImageCropperOverlayViewConfigurationOverlay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AKImageCropperOverlayViewConfigurationOverlay.swift; sourceTree = "<group>"; };
		016E5EE71DFFDD8300662D31 /* AKImageCropperOverlayViewTouchState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AKImageCropperOverlayViewTouchState.swift; sourceTree = "<group>"; };
		016E5EE81DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationCorner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AKImageCropperOverlayViewConfigurationCorner.swift; sourceTree = "<group>"; };
		016E5EE91DFFDD8300662D31 /* AKImageCropperOverlayViewConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AKImageCropperOverlayViewConfiguration.swift; sourceTree = "<group>"; };
		016E5EEB1DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationEdge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AKImageCropperOverlayViewConfigurationEdge.swift; sourceTree = "<group>"; };
		016E5EEC1DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationGrid.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AKImageCropperOverlayViewConfigurationGrid.swift; sourceTree = "<group>"; };
		016E5EED1DFFDD8300662D31 /* AKImageCropperOverlayView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AKImageCropperOverlayView.swift; sourceTree = "<group>"; };
		016E5EF01DFFDD8300662D31 /* AKImageCropperView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AKImageCropperView.swift; sourceTree = "<group>"; };
		01C48FBB1DEC250100FBBE34 /* CustomImageCropperOverlayView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomImageCropperOverlayView.swift; sourceTree = "<group>"; };
		01F61BE41E4DC7B800977E33 /* IC_CGFloatExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IC_CGFloatExtension.swift; sourceTree = "<group>"; };
		01FA13EE1DDF0C6E006B8C3A /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
		4356D6131B8F3DE90033FDBD /* ImageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageViewController.swift; sourceTree = "<group>"; };
		43CBB3FD1B870EBC00C8F9AE /* AKImageCropperViewExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AKImageCropperViewExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
		43CBB4011B870EBC00C8F9AE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		43CBB4021B870EBC00C8F9AE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
		43CBB4041B870EBC00C8F9AE /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = "<group>"; };
		43CBB4071B870EBC00C8F9AE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
		43CBB4091B870EBC00C8F9AE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
		43CBB40C1B870EBC00C8F9AE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
		43CBB4231B8716EA00C8F9AE /* CropperViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CropperViewController.swift; sourceTree = "<group>"; };
		43CBB43F1B8739B100C8F9AE /* ImagesTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagesTableViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		011028A31DFFDD24002AA94E /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		43CBB3FA1B870EBC00C8F9AE /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
				016E5EFE1DFFE77400662D31 /* AKImageCropperView.framework in Frameworks */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		011028A81DFFDD24002AA94E /* AKImageCropperView */ = {
			isa = PBXGroup;
			children = (
				011028A91DFFDD24002AA94E /* AKImageCropperView.h */,
				011028AA1DFFDD24002AA94E /* Info.plist */,
				016E5EF01DFFDD8300662D31 /* AKImageCropperView.swift */,
				0141AF1C1E052BF6007C5672 /* AKImageCropperScrollView.swift */,
				016E5EED1DFFDD8300662D31 /* AKImageCropperOverlayView.swift */,
				016E5EE71DFFDD8300662D31 /* AKImageCropperOverlayViewTouchState.swift */,
				01F61BE61E4DC89300977E33 /* configuration */,
				015530461E28EF5A00961922 /* extensions */,
			);
			path = AKImageCropperView;
			sourceTree = "<group>";
		};
		015530461E28EF5A00961922 /* extensions */ = {
			isa = PBXGroup;
			children = (
				015530491E28F2C500961922 /* IC_UIImageExtensions.swift */,
				0155304B1E28FDB800961922 /* IC_CGSizeExtensions.swift */,
				0155304D1E28FEC600961922 /* IC_CGPointExtension.swift */,
				01F61BE41E4DC7B800977E33 /* IC_CGFloatExtension.swift */,
			);
			name = extensions;
			sourceTree = "<group>";
		};
		01F61BE61E4DC89300977E33 /* configuration */ = {
			isa = PBXGroup;
			children = (
				016E5EE91DFFDD8300662D31 /* AKImageCropperOverlayViewConfiguration.swift */,
				0166B68E1E03E1560081B751 /* AKImageCropperOverlayViewConfigurationOverlay.swift */,
				016E5EEB1DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationEdge.swift */,
				016E5EE81DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationCorner.swift */,
				016E5EEC1DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationGrid.swift */,
			);
			name = configuration;
			sourceTree = "<group>";
		};
		43CBB3F41B870EBC00C8F9AE = {
			isa = PBXGroup;
			children = (
				011028A81DFFDD24002AA94E /* AKImageCropperView */,
				43CBB3FF1B870EBC00C8F9AE /* AKImageCropperViewExample */,
				43CBB3FE1B870EBC00C8F9AE /* Products */,
			);
			sourceTree = "<group>";
		};
		43CBB3FE1B870EBC00C8F9AE /* Products */ = {
			isa = PBXGroup;
			children = (
				43CBB3FD1B870EBC00C8F9AE /* AKImageCropperViewExample.app */,
				011028A71DFFDD24002AA94E /* AKImageCropperView.framework */,
			);
			name = Products;
			sourceTree = "<group>";
		};
		43CBB3FF1B870EBC00C8F9AE /* AKImageCropperViewExample */ = {
			isa = PBXGroup;
			children = (
				43CBB4011B870EBC00C8F9AE /* Info.plist */,
				43CBB4021B870EBC00C8F9AE /* AppDelegate.swift */,
				01FA13EE1DDF0C6E006B8C3A /* Constants.swift */,
				43CBB4091B870EBC00C8F9AE /* Images.xcassets */,
				43CBB40B1B870EBC00C8F9AE /* LaunchScreen.xib */,
				43CBB4061B870EBC00C8F9AE /* Main.storyboard */,
				43CBB4041B870EBC00C8F9AE /* HomeViewController.swift */,
				43CBB43F1B8739B100C8F9AE /* ImagesTableViewController.swift */,
				43CBB4231B8716EA00C8F9AE /* CropperViewController.swift */,
				4356D6131B8F3DE90033FDBD /* ImageViewController.swift */,
				01C48FBB1DEC250100FBBE34 /* CustomImageCropperOverlayView.swift */,
			);
			path = AKImageCropperViewExample;
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
		011028A41DFFDD24002AA94E /* Headers */ = {
			isa = PBXHeadersBuildPhase;
			buildActionMask = 2147483647;
			files = (
				011028AB1DFFDD24002AA94E /* AKImageCropperView.h in Headers */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXHeadersBuildPhase section */

/* Begin PBXNativeTarget section */
		011028A61DFFDD24002AA94E /* AKImageCropperView */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 011028B01DFFDD24002AA94E /* Build configuration list for PBXNativeTarget "AKImageCropperView" */;
			buildPhases = (
				011028A21DFFDD24002AA94E /* Sources */,
				011028A31DFFDD24002AA94E /* Frameworks */,
				011028A41DFFDD24002AA94E /* Headers */,
				011028A51DFFDD24002AA94E /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = AKImageCropperView;
			productName = AKImageCropperView;
			productReference = 011028A71DFFDD24002AA94E /* AKImageCropperView.framework */;
			productType = "com.apple.product-type.framework";
		};
		43CBB3FC1B870EBC00C8F9AE /* AKImageCropperViewExample */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 43CBB41C1B870EBC00C8F9AE /* Build configuration list for PBXNativeTarget "AKImageCropperViewExample" */;
			buildPhases = (
				43CBB3F91B870EBC00C8F9AE /* Sources */,
				43CBB3FA1B870EBC00C8F9AE /* Frameworks */,
				43CBB3FB1B870EBC00C8F9AE /* Resources */,
				016E5F021DFFE77400662D31 /* Embed Frameworks */,
			);
			buildRules = (
			);
			dependencies = (
				016E5F011DFFE77400662D31 /* PBXTargetDependency */,
			);
			name = AKImageCropperViewExample;
			productName = AKImageCropperDemo;
			productReference = 43CBB3FD1B870EBC00C8F9AE /* AKImageCropperViewExample.app */;
			productType = "com.apple.product-type.application";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		43CBB3F51B870EBC00C8F9AE /* Project object */ = {
			isa = PBXProject;
			attributes = {
				LastSwiftMigration = 0700;
				LastSwiftUpdateCheck = 0700;
				LastUpgradeCheck = 0820;
				ORGANIZATIONNAME = "Artem Krachulov";
				TargetAttributes = {
					011028A61DFFDD24002AA94E = {
						CreatedOnToolsVersion = 8.1;
						LastSwiftMigration = 0810;
						ProvisioningStyle = Manual;
					};
					43CBB3FC1B870EBC00C8F9AE = {
						CreatedOnToolsVersion = 6.4;
						DevelopmentTeam = 5JV4U8LEZ8;
						LastSwiftMigration = 0810;
					};
				};
			};
			buildConfigurationList = 43CBB3F81B870EBC00C8F9AE /* Build configuration list for PBXProject "AKImageCropperView" */;
			compatibilityVersion = "Xcode 3.2";
			developmentRegion = English;
			hasScannedForEncodings = 0;
			knownRegions = (
				en,
				Base,
			);
			mainGroup = 43CBB3F41B870EBC00C8F9AE;
			productRefGroup = 43CBB3FE1B870EBC00C8F9AE /* Products */;
			projectDirPath = "";
			projectRoot = "";
			targets = (
				011028A61DFFDD24002AA94E /* AKImageCropperView */,
				43CBB3FC1B870EBC00C8F9AE /* AKImageCropperViewExample */,
			);
		};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
		011028A51DFFDD24002AA94E /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		43CBB3FB1B870EBC00C8F9AE /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				43CBB4081B870EBC00C8F9AE /* Main.storyboard in Resources */,
				43CBB40D1B870EBC00C8F9AE /* LaunchScreen.xib in Resources */,
				43CBB40A1B870EBC00C8F9AE /* Images.xcassets in Resources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
		011028A21DFFDD24002AA94E /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				016E5EF41DFFDD8300662D31 /* AKImageCropperOverlayViewConfiguration.swift in Sources */,
				0166B68F1E03E1560081B751 /* AKImageCropperOverlayViewConfigurationOverlay.swift in Sources */,
				0155304C1E28FDB800961922 /* IC_CGSizeExtensions.swift in Sources */,
				016E5EF81DFFDD8300662D31 /* AKImageCropperOverlayView.swift in Sources */,
				0155304A1E28F2C500961922 /* IC_UIImageExtensions.swift in Sources */,
				016E5EFB1DFFDD8300662D31 /* AKImageCropperView.swift in Sources */,
				016E5EF31DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationCorner.swift in Sources */,
				01F61BE51E4DC7B800977E33 /* IC_CGFloatExtension.swift in Sources */,
				0155304E1E28FEC600961922 /* IC_CGPointExtension.swift in Sources */,
				016E5EF21DFFDD8300662D31 /* AKImageCropperOverlayViewTouchState.swift in Sources */,
				0141AF1D1E052BF6007C5672 /* AKImageCropperScrollView.swift in Sources */,
				016E5EF71DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationGrid.swift in Sources */,
				016E5EF61DFFDD8300662D31 /* AKImageCropperOverlayViewConfigurationEdge.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		43CBB3F91B870EBC00C8F9AE /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				43CBB4051B870EBC00C8F9AE /* HomeViewController.swift in Sources */,
				01C48FBC1DEC250100FBBE34 /* CustomImageCropperOverlayView.swift in Sources */,
				43CBB4241B8716EA00C8F9AE /* CropperViewController.swift in Sources */,
				01FA13EF1DDF0C6E006B8C3A /* Constants.swift in Sources */,
				43CBB4031B870EBC00C8F9AE /* AppDelegate.swift in Sources */,
				4356D6141B8F3DE90033FDBD /* ImageViewController.swift in Sources */,
				43CBB4401B8739B100C8F9AE /* ImagesTableViewController.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
		016E5F011DFFE77400662D31 /* PBXTargetDependency */ = {
			isa = PBXTargetDependency;
			target = 011028A61DFFDD24002AA94E /* AKImageCropperView */;
			targetProxy = 016E5F001DFFE77400662D31 /* PBXContainerItemProxy */;
		};
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */
		43CBB4061B870EBC00C8F9AE /* Main.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				43CBB4071B870EBC00C8F9AE /* Base */,
			);
			name = Main.storyboard;
			sourceTree = "<group>";
		};
		43CBB40B1B870EBC00C8F9AE /* LaunchScreen.xib */ = {
			isa = PBXVariantGroup;
			children = (
				43CBB40C1B870EBC00C8F9AE /* Base */,
			);
			name = LaunchScreen.xib;
			sourceTree = "<group>";
		};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
		011028B11DFFDD24002AA94E /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				APPLICATION_EXTENSION_API_ONLY = YES;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ENABLE_MODULES = YES;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_SUSPICIOUS_MOVES = YES;
				CODE_SIGN_IDENTITY = "";
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
				CURRENT_PROJECT_VERSION = 1;
				DEBUG_INFORMATION_FORMAT = dwarf;
				DEFINES_MODULE = YES;
				DEVELOPMENT_TEAM = "";
				DYLIB_COMPATIBILITY_VERSION = 1;
				DYLIB_CURRENT_VERSION = 1;
				DYLIB_INSTALL_NAME_BASE = "@rpath";
				INFOPLIST_FILE = AKImageCropperView/Info.plist;
				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
				PRODUCT_BUNDLE_IDENTIFIER = com.artemkrachulov.AKImageCropperView;
				PRODUCT_NAME = "$(TARGET_NAME)";
				SKIP_INSTALL = YES;
				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
				SWIFT_VERSION = 3.0;
				VERSIONING_SYSTEM = "apple-generic";
				VERSION_INFO_PREFIX = "";
			};
			name = Debug;
		};
		011028B21DFFDD24002AA94E /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				APPLICATION_EXTENSION_API_ONLY = YES;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ENABLE_MODULES = YES;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_SUSPICIOUS_MOVES = YES;
				CODE_SIGN_IDENTITY = "";
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
				CURRENT_PROJECT_VERSION = 1;
				DEFINES_MODULE = YES;
				DEVELOPMENT_TEAM = "";
				DYLIB_COMPATIBILITY_VERSION = 1;
				DYLIB_CURRENT_VERSION = 1;
				DYLIB_INSTALL_NAME_BASE = "@rpath";
				INFOPLIST_FILE = AKImageCropperView/Info.plist;
				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
				PRODUCT_BUNDLE_IDENTIFIER = com.artemkrachulov.AKImageCropperView;
				PRODUCT_NAME = "$(TARGET_NAME)";
				SKIP_INSTALL = YES;
				SWIFT_VERSION = 3.0;
				VERSIONING_SYSTEM = "apple-generic";
				VERSION_INFO_PREFIX = "";
			};
			name = Release;
		};
		43CBB41A1B870EBC00C8F9AE /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				ENABLE_TESTABILITY = YES;
				GCC_C_LANGUAGE_STANDARD = gnu99;
				GCC_DYNAMIC_NO_PIC = NO;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_OPTIMIZATION_LEVEL = 0;
				GCC_PREPROCESSOR_DEFINITIONS = (
					"DEBUG=1",
					"$(inherited)",
				);
				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				MTL_ENABLE_DEBUG_INFO = YES;
				ONLY_ACTIVE_ARCH = YES;
				SDKROOT = iphoneos;
				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Debug;
		};
		43CBB41B1B870EBC00C8F9AE /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
				ENABLE_NS_ASSERTIONS = NO;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				GCC_C_LANGUAGE_STANDARD = gnu99;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				MTL_ENABLE_DEBUG_INFO = NO;
				SDKROOT = iphoneos;
				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
				TARGETED_DEVICE_FAMILY = "1,2";
				VALIDATE_PRODUCT = YES;
			};
			name = Release;
		};
		43CBB41D1B870EBC00C8F9AE /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				DEVELOPMENT_TEAM = 5JV4U8LEZ8;
				INFOPLIST_FILE = AKImageCropperViewExample/Info.plist;
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				OTHER_SWIFT_FLAGS = "-D AKImageCropperViewDEBUG";
				PRODUCT_BUNDLE_IDENTIFIER = artem.krachulov.AKImageCropper;
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_VERSION = 3.0;
			};
			name = Debug;
		};
		43CBB41E1B870EBC00C8F9AE /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				DEVELOPMENT_TEAM = 5JV4U8LEZ8;
				INFOPLIST_FILE = AKImageCropperViewExample/Info.plist;
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				MTL_ENABLE_DEBUG_INFO = No;
				PRODUCT_BUNDLE_IDENTIFIER = artem.krachulov.AKImageCropper;
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
				SWIFT_VERSION = 3.0;
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
		011028B01DFFDD24002AA94E /* Build configuration list for PBXNativeTarget "AKImageCropperView" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				011028B11DFFDD24002AA94E /* Debug */,
				011028B21DFFDD24002AA94E /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		43CBB3F81B870EBC00C8F9AE /* Build configuration list for PBXProject "AKImageCropperView" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				43CBB41A1B870EBC00C8F9AE /* Debug */,
				43CBB41B1B870EBC00C8F9AE /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		43CBB41C1B870EBC00C8F9AE /* Build configuration list for PBXNativeTarget "AKImageCropperViewExample" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				43CBB41D1B870EBC00C8F9AE /* Debug */,
				43CBB41E1B870EBC00C8F9AE /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */
	};
	rootObject = 43CBB3F51B870EBC00C8F9AE /* Project object */;
}


================================================
FILE: AKImageCropperView.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "self:/Users/artemkrachulov/Repos/AKImageCropper/AKImageCropperView.xcodeproj">
   </FileRef>
</Workspace>


================================================
FILE: AKImageCropperView.xcodeproj/project.xcworkspace/xcshareddata/AKImageCropperDemo.xcscmblueprint
================================================
{
  "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "74FC6B16832EDE035AC047E84A01E2F0C9097FE9",
  "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {

  },
  "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
    "74FC6B16832EDE035AC047E84A01E2F0C9097FE9" : 0,
    "F0D98E582FA112BC083159DA5B51E17128CD38B4" : 0,
    "B234E04AE2BC64FD278418F0B83A3F07C2F904DB" : 0,
    "78558585540D6A03C4B47C1A04640D7B2BD34C66" : 0,
    "EAD4BE7C3980137405ECAE8A71597A264DEE9FD1" : 0
  },
  "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "CACF0744-A1D3-4BA8-8481-EB16E6A7A6C0",
  "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
    "74FC6B16832EDE035AC047E84A01E2F0C9097FE9" : "AKImageCropper\/",
    "F0D98E582FA112BC083159DA5B51E17128CD38B4" : "AKImageCropper\/Demo\/Vendor\/Extensions\/Double-Float\/",
    "B234E04AE2BC64FD278418F0B83A3F07C2F904DB" : "AKImageCropper\/Demo\/Vendor\/Extensions\/CGRect-CGSize\/",
    "78558585540D6A03C4B47C1A04640D7B2BD34C66" : "AKImageCropper\/Demo\/Vendor\/Extensions\/Range\/",
    "EAD4BE7C3980137405ECAE8A71597A264DEE9FD1" : "AKImageCropper\/Demo\/Vendor\/Extensions\/UIImage\/"
  },
  "DVTSourceControlWorkspaceBlueprintNameKey" : "AKImageCropperDemo",
  "DVTSourceControlWorkspaceBlueprintVersion" : 204,
  "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Demo\/AKImageCropperDemo.xcodeproj",
  "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
    {
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:artemkrachulov\/AKImageCropper.git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "74FC6B16832EDE035AC047E84A01E2F0C9097FE9"
    },
    {
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/artemkrachulov\/Range-Extension.git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "78558585540D6A03C4B47C1A04640D7B2BD34C66"
    },
    {
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/artemkrachulov\/CGRect-CGSize-Extensions.git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "B234E04AE2BC64FD278418F0B83A3F07C2F904DB"
    },
    {
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/artemkrachulov\/UIImage-Extension.git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "EAD4BE7C3980137405ECAE8A71597A264DEE9FD1"
    },
    {
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/artemkrachulov\/Double-Float-Extensions.git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "F0D98E582FA112BC083159DA5B51E17128CD38B4"
    }
  ]
}

================================================
FILE: AKImageCropperView.xcodeproj/project.xcworkspace/xcshareddata/Demo.xcscmblueprint
================================================
{
  "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "74FC6B16832EDE035AC047E84A01E2F0C9097FE9",
  "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {

  },
  "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
    "74FC6B16832EDE035AC047E84A01E2F0C9097FE9" : 0,
    "F0D98E582FA112BC083159DA5B51E17128CD38B4" : 0,
    "B234E04AE2BC64FD278418F0B83A3F07C2F904DB" : 0,
    "78558585540D6A03C4B47C1A04640D7B2BD34C66" : 0,
    "EAD4BE7C3980137405ECAE8A71597A264DEE9FD1" : 0
  },
  "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "349E57B7-4D5D-430B-958A-5768311D2060",
  "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
    "74FC6B16832EDE035AC047E84A01E2F0C9097FE9" : "AKImageCropper\/",
    "F0D98E582FA112BC083159DA5B51E17128CD38B4" : "AKImageCropper\/Demo\/Vendor\/Extensions\/Double-Float\/",
    "B234E04AE2BC64FD278418F0B83A3F07C2F904DB" : "AKImageCropper\/Demo\/Vendor\/Extensions\/CGRect-CGSize\/",
    "78558585540D6A03C4B47C1A04640D7B2BD34C66" : "AKImageCropper\/Demo\/Vendor\/Extensions\/Range\/",
    "EAD4BE7C3980137405ECAE8A71597A264DEE9FD1" : "AKImageCropper\/Demo\/Vendor\/Extensions\/UIImage\/"
  },
  "DVTSourceControlWorkspaceBlueprintNameKey" : "Demo",
  "DVTSourceControlWorkspaceBlueprintVersion" : 204,
  "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Demo\/Demo.xcodeproj",
  "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
    {
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:artemkrachulov\/AKImageCropper.git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "74FC6B16832EDE035AC047E84A01E2F0C9097FE9"
    },
    {
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/artemkrachulov\/Range-Extension.git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "78558585540D6A03C4B47C1A04640D7B2BD34C66"
    },
    {
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/artemkrachulov\/CGRect-CGSize-Extensions.git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "B234E04AE2BC64FD278418F0B83A3F07C2F904DB"
    },
    {
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/artemkrachulov\/UIImage-Extension.git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "EAD4BE7C3980137405ECAE8A71597A264DEE9FD1"
    },
    {
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/artemkrachulov\/Double-Float-Extensions.git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "F0D98E582FA112BC083159DA5B51E17128CD38B4"
    }
  ]
}

================================================
FILE: AKImageCropperView.xcodeproj/xcshareddata/xcschemes/AKImageCropperView.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "0820"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "011028A61DFFDD24002AA94E"
               BuildableName = "AKImageCropperView.framework"
               BlueprintName = "AKImageCropperView"
               ReferencedContainer = "container:AKImageCropperView.xcodeproj">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES">
      <Testables>
      </Testables>
      <AdditionalOptions>
      </AdditionalOptions>
   </TestAction>
   <LaunchAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      allowLocationSimulation = "YES">
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "011028A61DFFDD24002AA94E"
            BuildableName = "AKImageCropperView.framework"
            BlueprintName = "AKImageCropperView"
            ReferencedContainer = "container:AKImageCropperView.xcodeproj">
         </BuildableReference>
      </MacroExpansion>
      <AdditionalOptions>
      </AdditionalOptions>
   </LaunchAction>
   <ProfileAction
      buildConfiguration = "Release"
      shouldUseLaunchSchemeArgsEnv = "YES"
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES">
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "011028A61DFFDD24002AA94E"
            BuildableName = "AKImageCropperView.framework"
            BlueprintName = "AKImageCropperView"
            ReferencedContainer = "container:AKImageCropperView.xcodeproj">
         </BuildableReference>
      </MacroExpansion>
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>


================================================
FILE: AKImageCropperViewExample/AppDelegate.swift
================================================
//
//  AppDelegate.swift
//  AKImageCropperDemo
//  GitHub: https://github.com/artemkrachulov/AKImageCropper
//
//  Created by Krachulov Artem
//  Copyright (c) 2015 Krachulov Artem. All rights reserved.
//  Website: http://www.artemkrachulov.com/
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }
}



================================================
FILE: AKImageCropperViewExample/Base.lproj/LaunchScreen.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <view contentMode="scaleToFill" id="OND-g9-1i5">
            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <simulatedStatusBarMetrics key="simulatedStatusBarMetrics"/>
            <point key="canvasLocation" x="589" y="579"/>
        </view>
    </objects>
</document>


================================================
FILE: AKImageCropperViewExample/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="wQk-zT-bng">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Demo folder-->
        <scene sceneID="R06-je-7kK">
            <objects>
                <tableViewController id="dCy-DU-1gs" customClass="ImagesTableViewController" customModule="AKImageCropperViewExample" customModuleProvider="target" sceneMemberID="viewController">
                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="80" sectionHeaderHeight="10" sectionFooterHeight="10" id="8Qw-gW-rSq">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <prototypes>
                            <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="image" textLabel="PAT-oO-2hL" detailTextLabel="mnx-Mm-eqW" style="IBUITableViewCellStyleSubtitle" id="uS4-ET-v3L">
                                <rect key="frame" x="0.0" y="56" width="375" height="80"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uS4-ET-v3L" id="pRa-pE-0iP">
                                    <rect key="frame" x="0.0" y="0.0" width="342" height="79"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="PAT-oO-2hL">
                                            <rect key="frame" x="15" y="20" width="34" height="21"/>
                                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                            <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <nil key="highlightedColor"/>
                                        </label>
                                        <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Detail" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="mnx-Mm-eqW">
                                            <rect key="frame" x="15" y="41" width="40" height="18"/>
                                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                            <fontDescription key="fontDescription" type="system" pointSize="15"/>
                                            <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <nil key="highlightedColor"/>
                                        </label>
                                    </subviews>
                                </tableViewCellContentView>
                                <connections>
                                    <segue destination="Rdn-7Y-KLl" kind="show" id="awS-AO-qOC"/>
                                </connections>
                            </tableViewCell>
                        </prototypes>
                        <connections>
                            <outlet property="dataSource" destination="dCy-DU-1gs" id="AGP-R5-LfS"/>
                            <outlet property="delegate" destination="dCy-DU-1gs" id="Nx1-yp-dHE"/>
                        </connections>
                    </tableView>
                    <navigationItem key="navigationItem" title="Demo folder" id="7Is-JM-HRz"/>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="7Ef-Cy-a8G" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1220" y="618"/>
        </scene>
        <!--Crop View-->
        <scene sceneID="knG-at-evs">
            <objects>
                <viewController storyboardIdentifier="cropperViewController" automaticallyAdjustsScrollViewInsets="NO" id="Rdn-7Y-KLl" customClass="CropperViewController" customModule="AKImageCropperViewExample" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="Qt6-f6-NMs"/>
                        <viewControllerLayoutGuide type="bottom" id="aDG-WU-S8J"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="yhB-g2-lKN">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NNR-8r-Iig" customClass="AKImageCropperView" customModule="AKImageCropperView">
                                <rect key="frame" x="0.0" y="20" width="375" height="607"/>
                                <color key="backgroundColor" white="1" alpha="0.10000000000000001" colorSpace="calibratedWhite"/>
                            </view>
                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yeD-f2-GC0">
                                <rect key="frame" x="0.0" y="577" width="375" height="50"/>
                                <subviews>
                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OcE-Cr-oaV">
                                        <rect key="frame" x="8" y="14" width="22" height="22"/>
                                        <constraints>
                                            <constraint firstAttribute="height" constant="22" id="0kW-xk-M2d"/>
                                            <constraint firstAttribute="width" constant="22" id="nt9-AI-Qkr"/>
                                        </constraints>
                                        <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <state key="normal" image="rotate"/>
                                        <connections>
                                            <action selector="rotateAction:" destination="Rdn-7Y-KLl" eventType="touchUpInside" id="uFB-UV-6jK"/>
                                        </connections>
                                    </button>
                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aDm-Fl-m9C">
                                        <rect key="frame" x="164.5" y="10" width="46" height="30"/>
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                                        <color key="tintColor" red="1" green="0.40000000600000002" blue="0.40000000600000002" alpha="1" colorSpace="calibratedRGB"/>
                                        <state key="normal" title="RESET"/>
                                        <connections>
                                            <action selector="resetAction:" destination="Rdn-7Y-KLl" eventType="touchUpInside" id="iyC-RF-aoB"/>
                                        </connections>
                                    </button>
                                </subviews>
                                <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
                                <constraints>
                                    <constraint firstAttribute="height" constant="50" id="1uM-rd-DUd"/>
                                    <constraint firstItem="OcE-Cr-oaV" firstAttribute="centerY" secondItem="yeD-f2-GC0" secondAttribute="centerY" id="227-80-ud3"/>
                                    <constraint firstItem="OcE-Cr-oaV" firstAttribute="leading" secondItem="yeD-f2-GC0" secondAttribute="leading" constant="8" id="Yxu-MS-NnN"/>
                                    <constraint firstItem="aDm-Fl-m9C" firstAttribute="centerX" secondItem="yeD-f2-GC0" secondAttribute="centerX" id="lrf-sz-2JO"/>
                                    <constraint firstItem="aDm-Fl-m9C" firstAttribute="centerY" secondItem="yeD-f2-GC0" secondAttribute="centerY" id="saC-mg-X6V"/>
                                </constraints>
                            </view>
                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wMD-3V-hUT">
                                <rect key="frame" x="0.0" y="627" width="375" height="40"/>
                                <subviews>
                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Xik-3z-UDc">
                                        <rect key="frame" x="8" y="4" width="38" height="33"/>
                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                        <color key="tintColor" red="0.0" green="0.50196081400000003" blue="1" alpha="1" colorSpace="calibratedRGB"/>
                                        <state key="normal" title="Back">
                                            <color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        </state>
                                        <connections>
                                            <action selector="backAction:" destination="Rdn-7Y-KLl" eventType="touchUpInside" id="Wkj-3h-8yo"/>
                                        </connections>
                                    </button>
                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AAk-pb-8ob">
                                        <rect key="frame" x="329" y="4" width="38" height="33"/>
                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                        <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <state key="normal" title="Crop">
                                            <color key="titleColor" red="1" green="1" blue="0.40000000600000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        </state>
                                        <connections>
                                            <action selector="cropImageAction:" destination="Rdn-7Y-KLl" eventType="touchUpInside" id="h04-VG-mda"/>
                                        </connections>
                                    </button>
                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vLm-vA-Gov">
                                        <rect key="frame" x="176.5" y="9" width="22" height="22"/>
                                        <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <state key="normal" image="overlay"/>
                                        <connections>
                                            <action selector="showHideOverlayAction:" destination="Rdn-7Y-KLl" eventType="touchUpInside" id="tff-m1-bAb"/>
                                        </connections>
                                    </button>
                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qcw-Wp-RWG">
                                        <rect key="frame" x="254" y="3" width="67" height="34"/>
                                        <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <state key="normal" title="Random"/>
                                        <connections>
                                            <action selector="randomImageAction:" destination="Rdn-7Y-KLl" eventType="touchUpInside" id="XVg-Cw-aoJ"/>
                                        </connections>
                                    </button>
                                </subviews>
                                <color key="backgroundColor" red="1" green="1" blue="1" alpha="0.10000000000000001" colorSpace="custom" customColorSpace="sRGB"/>
                                <constraints>
                                    <constraint firstItem="Xik-3z-UDc" firstAttribute="leading" secondItem="wMD-3V-hUT" secondAttribute="leading" constant="8" id="6rD-QV-lr8"/>
                                    <constraint firstAttribute="trailing" secondItem="AAk-pb-8ob" secondAttribute="trailing" constant="8" id="9ig-1u-DSl"/>
                                    <constraint firstItem="vLm-vA-Gov" firstAttribute="centerX" secondItem="wMD-3V-hUT" secondAttribute="centerX" id="MEl-vD-dqU"/>
                                    <constraint firstItem="vLm-vA-Gov" firstAttribute="centerY" secondItem="wMD-3V-hUT" secondAttribute="centerY" id="cSm-Zo-lKa"/>
                                    <constraint firstItem="qcw-Wp-RWG" firstAttribute="centerY" secondItem="AAk-pb-8ob" secondAttribute="centerY" id="cpp-Ph-nL5"/>
                                    <constraint firstItem="AAk-pb-8ob" firstAttribute="leading" secondItem="qcw-Wp-RWG" secondAttribute="trailing" constant="8" id="k4D-Pz-J3X"/>
                                    <constraint firstItem="AAk-pb-8ob" firstAttribute="centerY" secondItem="wMD-3V-hUT" secondAttribute="centerY" id="lp9-6a-Wrt"/>
                                    <constraint firstItem="Xik-3z-UDc" firstAttribute="centerY" secondItem="wMD-3V-hUT" secondAttribute="centerY" id="qtX-gn-NoI"/>
                                    <constraint firstAttribute="height" constant="40" id="rSL-W9-EEC"/>
                                </constraints>
                            </view>
                        </subviews>
                        <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstAttribute="trailing" secondItem="NNR-8r-Iig" secondAttribute="trailing" id="4m8-EW-rOa"/>
                            <constraint firstAttribute="trailing" secondItem="wMD-3V-hUT" secondAttribute="trailing" id="5mI-PE-xbj"/>
                            <constraint firstItem="yeD-f2-GC0" firstAttribute="leading" secondItem="yhB-g2-lKN" secondAttribute="leading" id="IqO-nt-y3G"/>
                            <constraint firstItem="wMD-3V-hUT" firstAttribute="leading" secondItem="yhB-g2-lKN" secondAttribute="leading" id="PZz-n2-ppW"/>
                            <constraint firstItem="wMD-3V-hUT" firstAttribute="top" secondItem="NNR-8r-Iig" secondAttribute="bottom" id="SAb-zF-ExQ"/>
                            <constraint firstItem="NNR-8r-Iig" firstAttribute="top" secondItem="Qt6-f6-NMs" secondAttribute="bottom" id="XIq-wp-GCF"/>
                            <constraint firstAttribute="trailing" secondItem="yeD-f2-GC0" secondAttribute="trailing" id="bQg-Xe-T56"/>
                            <constraint firstItem="aDG-WU-S8J" firstAttribute="top" secondItem="wMD-3V-hUT" secondAttribute="bottom" id="hZW-cD-Y7S"/>
                            <constraint firstAttribute="leading" secondItem="NNR-8r-Iig" secondAttribute="leading" id="jbS-cc-pHL"/>
                            <constraint firstItem="wMD-3V-hUT" firstAttribute="top" secondItem="yeD-f2-GC0" secondAttribute="bottom" id="zDw-ek-9hi"/>
                        </constraints>
                    </view>
                    <navigationItem key="navigationItem" title="Crop View" id="Dch-T8-hoF"/>
                    <simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
                    <nil key="simulatedTopBarMetrics"/>
                    <connections>
                        <outlet property="cropViewStoryboard" destination="NNR-8r-Iig" id="3tD-2Q-b5A"/>
                        <outlet property="navigationView" destination="wMD-3V-hUT" id="Tmh-Sx-tyS"/>
                        <outlet property="overlayActionView" destination="yeD-f2-GC0" id="ONk-aH-Jyg"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="vfa-Bq-aJk" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="2038" y="619"/>
        </scene>
        <!--Cropped Image-->
        <scene sceneID="uND-rV-bwv">
            <objects>
                <viewController storyboardIdentifier="ImageViewController" id="RKe-5g-3sC" customClass="ImageViewController" customModule="AKImageCropperViewExample" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="3wc-Wp-Jyx"/>
                        <viewControllerLayoutGuide type="bottom" id="f21-mp-caw"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="s9k-zV-KY6">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="qUK-T2-uUb">
                                <rect key="frame" x="0.0" y="20" width="375" height="607"/>
                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                            </imageView>
                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="VWe-jo-ncG">
                                <rect key="frame" x="0.0" y="627" width="375" height="40"/>
                                <subviews>
                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nW8-ls-VF7">
                                        <rect key="frame" x="8" y="4" width="38" height="33"/>
                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                        <color key="tintColor" red="0.0" green="0.50196081400000003" blue="1" alpha="1" colorSpace="calibratedRGB"/>
                                        <state key="normal" title="Back">
                                            <color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        </state>
                                        <connections>
                                            <action selector="backAction:" destination="RKe-5g-3sC" eventType="touchUpInside" id="jKH-Ia-TmZ"/>
                                        </connections>
                                    </button>
                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GZk-pK-z6H">
                                        <rect key="frame" x="277" y="4" width="90" height="33"/>
                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                        <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <state key="normal" title="IMAGE LIST">
                                            <color key="titleColor" red="1" green="0.40000000600000002" blue="0.40000000600000002" alpha="1" colorSpace="calibratedRGB"/>
                                            <color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        </state>
                                        <connections>
                                            <action selector="showListAction:" destination="RKe-5g-3sC" eventType="touchUpInside" id="UiD-hZ-odJ"/>
                                        </connections>
                                    </button>
                                </subviews>
                                <color key="backgroundColor" red="1" green="1" blue="1" alpha="0.10000000000000001" colorSpace="custom" customColorSpace="sRGB"/>
                                <constraints>
                                    <constraint firstItem="GZk-pK-z6H" firstAttribute="centerY" secondItem="VWe-jo-ncG" secondAttribute="centerY" id="5IT-pI-LBa"/>
                                    <constraint firstAttribute="trailing" secondItem="GZk-pK-z6H" secondAttribute="trailing" constant="8" id="Gtt-0A-EXc"/>
                                    <constraint firstItem="nW8-ls-VF7" firstAttribute="centerY" secondItem="VWe-jo-ncG" secondAttribute="centerY" id="aWr-jl-pAG"/>
                                    <constraint firstItem="nW8-ls-VF7" firstAttribute="leading" secondItem="VWe-jo-ncG" secondAttribute="leading" constant="8" id="azT-mA-Kh1"/>
                                    <constraint firstAttribute="height" constant="40" id="xdG-80-VrU"/>
                                </constraints>
                            </view>
                        </subviews>
                        <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstAttribute="trailing" secondItem="VWe-jo-ncG" secondAttribute="trailing" id="66d-L6-YFi"/>
                            <constraint firstItem="VWe-jo-ncG" firstAttribute="leading" secondItem="s9k-zV-KY6" secondAttribute="leading" id="If3-9n-nK3"/>
                            <constraint firstAttribute="trailing" secondItem="qUK-T2-uUb" secondAttribute="trailing" id="Umf-7n-wRw"/>
                            <constraint firstItem="f21-mp-caw" firstAttribute="top" secondItem="VWe-jo-ncG" secondAttribute="bottom" id="mLj-uD-q29"/>
                            <constraint firstItem="qUK-T2-uUb" firstAttribute="leading" secondItem="s9k-zV-KY6" secondAttribute="leading" id="nY3-UT-vp5"/>
                            <constraint firstItem="qUK-T2-uUb" firstAttribute="top" secondItem="3wc-Wp-Jyx" secondAttribute="bottom" id="x7h-gf-TAm"/>
                            <constraint firstItem="VWe-jo-ncG" firstAttribute="top" secondItem="qUK-T2-uUb" secondAttribute="bottom" id="xCs-wi-5cg"/>
                        </constraints>
                    </view>
                    <navigationItem key="navigationItem" title="Cropped Image" id="vfd-Eq-99c"/>
                    <connections>
                        <outlet property="imageView" destination="qUK-T2-uUb" id="XRf-oF-d9n"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="ZVo-Oy-Yc0" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="2887" y="618"/>
        </scene>
        <!--AKLocationManager-->
        <scene sceneID="mR8-El-N3M">
            <objects>
                <viewController id="o8A-Qi-PEH" userLabel="AKLocationManager" customClass="HomeViewController" customModule="AKImageCropperViewExample" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="ICs-CR-drR"/>
                        <viewControllerLayoutGuide type="bottom" id="QFS-sv-RYa"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="D8c-Xa-Pec">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Zeo-Cv-xbz">
                                <rect key="frame" x="171.5" y="249" width="32" height="1"/>
                                <color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <constraints>
                                    <constraint firstAttribute="height" constant="1" id="70Z-Eo-lef"/>
                                    <constraint firstAttribute="width" constant="32" id="yKr-PU-ZjI"/>
                                </constraints>
                            </view>
                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="uBf-yH-pWL">
                                <rect key="frame" x="99" y="282" width="177" height="30"/>
                                <state key="normal" title="Select Image from Gallery">
                                    <color key="titleColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                </state>
                                <connections>
                                    <action selector="galleryAction" destination="o8A-Qi-PEH" eventType="touchUpInside" id="W7k-Kv-Dkl"/>
                                </connections>
                            </button>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Responsive image cropper" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Cm5-TZ-NK7">
                                <rect key="frame" x="16" y="96" width="343" height="21"/>
                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                <color key="textColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Demos" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RnQ-Uu-Fqe">
                                <rect key="frame" x="16" y="214" width="343" height="27"/>
                                <fontDescription key="fontDescription" style="UICTFontTextStyleTitle2"/>
                                <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WB8-2V-Rsz">
                                <rect key="frame" x="79" y="344" width="217" height="30"/>
                                <state key="normal" title="Select Image from Demo Folder"/>
                                <connections>
                                    <segue destination="dCy-DU-1gs" kind="show" id="8va-bh-mBB"/>
                                </connections>
                            </button>
                        </subviews>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstAttribute="trailingMargin" secondItem="Cm5-TZ-NK7" secondAttribute="trailing" id="16w-U8-opa"/>
                            <constraint firstItem="Cm5-TZ-NK7" firstAttribute="top" secondItem="ICs-CR-drR" secondAttribute="bottom" constant="32" id="8a3-A9-iMG"/>
                            <constraint firstItem="Zeo-Cv-xbz" firstAttribute="centerX" secondItem="D8c-Xa-Pec" secondAttribute="centerX" id="B0r-iN-c8g"/>
                            <constraint firstItem="RnQ-Uu-Fqe" firstAttribute="top" secondItem="ICs-CR-drR" secondAttribute="bottom" constant="150" id="DLc-Rl-yrZ"/>
                            <constraint firstItem="Cm5-TZ-NK7" firstAttribute="leading" secondItem="D8c-Xa-Pec" secondAttribute="leadingMargin" id="Ewe-Hk-hDu"/>
                            <constraint firstItem="WB8-2V-Rsz" firstAttribute="centerX" secondItem="D8c-Xa-Pec" secondAttribute="centerX" id="GXe-fv-L7v"/>
                            <constraint firstItem="WB8-2V-Rsz" firstAttribute="top" secondItem="uBf-yH-pWL" secondAttribute="bottom" constant="32" id="Ihd-Ot-wYi"/>
                            <constraint firstItem="uBf-yH-pWL" firstAttribute="centerX" secondItem="D8c-Xa-Pec" secondAttribute="centerX" id="Pgv-SQ-HUN"/>
                            <constraint firstItem="uBf-yH-pWL" firstAttribute="top" secondItem="Zeo-Cv-xbz" secondAttribute="bottom" constant="32" id="XeJ-EB-beG"/>
                            <constraint firstItem="Zeo-Cv-xbz" firstAttribute="top" secondItem="RnQ-Uu-Fqe" secondAttribute="bottom" constant="8" id="hmX-w8-wSI"/>
                            <constraint firstItem="RnQ-Uu-Fqe" firstAttribute="leading" secondItem="D8c-Xa-Pec" secondAttribute="leadingMargin" id="rTj-hc-eRg"/>
                            <constraint firstAttribute="trailingMargin" secondItem="RnQ-Uu-Fqe" secondAttribute="trailing" id="yWP-7s-GtS"/>
                        </constraints>
                    </view>
                    <navigationItem key="navigationItem" title="AKImageCropperView" id="Qt3-o7-Xus"/>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="Qjw-UL-ejc" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="414" y="619"/>
        </scene>
        <!--Navigation Controller-->
        <scene sceneID="khx-1F-DYa">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="wQk-zT-bng" sceneMemberID="viewController">
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" id="MxY-Fx-TEB">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="o8A-Qi-PEH" kind="relationship" relationship="rootViewController" id="52B-Rg-ppu"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="JuF-T7-bWT" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-377" y="618"/>
        </scene>
    </scenes>
    <resources>
        <image name="overlay" width="22" height="22"/>
        <image name="rotate" width="22" height="22"/>
    </resources>
</document>


================================================
FILE: AKImageCropperViewExample/Constants.swift
================================================
//
//  Constants.swift
//  Demo
//
//  Created by Artem Krachulov on 11/18/16.
//  Copyright © 2016 Artem Krachulov. All rights reserved.
//

import Foundation

struct Constants {
    
    static let images = [
        ["Attractive-girl", "Autumn-background", "Colorful-pillows"],
        ["Cupcakes", "Funnel-cake-stand", "Image-of-earth"]
    ]
}


================================================
FILE: AKImageCropperViewExample/CropperViewController.swift
================================================
//
//  CropperViewController.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//  Website: http://www.artemkrachulov.com/
//

import UIKit
import AKImageCropperView

final class CropperViewController: UIViewController {
    
    //  MARK: - Properties
    
    var image: UIImage!
    
    // MARK: - Connections:
    
    // MARK: -- Outlets
    
    private var cropView: AKImageCropperView {
        return cropViewProgrammatically ?? cropViewStoryboard
    }
    
    @IBOutlet weak var cropViewStoryboard: AKImageCropperView!
    private var cropViewProgrammatically: AKImageCropperView!
    
    @IBOutlet weak var overlayActionView: UIView!
    
    @IBOutlet weak var navigationView: UIView!
    
    // MARK: -- Actions
    
    @IBAction func backAction(_ sender: AnyObject) {
        
        guard !cropView.isEdited else {
            
            let alertController = UIAlertController(title: "Warning!", message:
                "All changes will be lost.", preferredStyle: UIAlertControllerStyle.alert)
            
            alertController.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.cancel, handler: { _ in
                
                _ = self.navigationController?.popViewController(animated: true)
            }))
            
            alertController.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default, handler: nil))
            
            present(alertController, animated: true, completion: nil)
            return
        }
        
        _ = navigationController?.popViewController(animated: true)
    }
    
    @IBAction func cropRandomAction(_ sender: AnyObject) {
        
//        cropView.setCropRectAnin(CGRect(x: 50, y: 200, width: 100, height: 100))
        
        
        /*
         let randomWidth = max(UInt32(cropView.configuration.cropRect.minimumSize.width), arc4random_uniform(UInt32(cropView.scrollView.frame.size.width)))
         let randomHeight = max(UInt32(cropView.configuration.cropRect.minimumSize.height), arc4random_uniform(UInt32(cropView.scrollView.frame.size.height)))
         let offsetX = CGFloat(arc4random_uniform(UInt32(cropView.scrollView.frame.size.width) - randomWidth))
         let offsetY = CGFloat(arc4random_uniform(UInt32(cropView.scrollView.frame.size.height) - randomHeight))
         
         cropView.cropRect(CGRectMake(offsetX, offsetY, CGFloat(randomWidth), CGFloat(randomHeight)))*/
    }
    
    @IBAction func randomImageAction(_ sender: AnyObject) {
        let images = Constants.images.flatMap { $0 }
        cropView.image = UIImage(named: images[Int(arc4random_uniform(UInt32(images.count)))])        
        angle = 0.0
    }
    
    @IBAction func cropImageAction(_ sender: AnyObject) {
        
         guard let image = cropView.croppedImage else {
            return
         }
         
         let imageViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ImageViewController") as! ImageViewController
         imageViewController.image = image
         navigationController?.pushViewController(imageViewController, animated: true)
    }
    
    @IBAction func showHideOverlayAction(_ sender: AnyObject) {
        
        if cropView.isoverlayViewActive {
            
            cropView.hideOverlayView(animationDuration: 0.3)
            
            UIView.animate(withDuration: 0.3, delay: 0, options: UIViewAnimationOptions.curveLinear, animations: {
                self.overlayActionView.alpha = 0
                
            }, completion: nil)
            
        } else {
            
            cropView.showOverlayView(animationDuration: 0.3)
            
            UIView.animate(withDuration: 0.3, delay: 0.3, options: UIViewAnimationOptions.curveLinear, animations: {
                self.overlayActionView.alpha = 1
                
            }, completion: nil)
            
        }
    }
    
    var angle: Double = 0.0
    
    @IBAction func rotateAction(_ sender: AnyObject) {

        angle += M_PI_2
        
        cropView.rotate(angle, withDuration: 0.3, completion: { _ in
            
            if self.angle == 2 * M_PI {
                self.angle = 0.0
            }
        })
    }
    
    @IBAction func resetAction(_ sender: AnyObject) {
        
        cropView.reset(animationDuration: 0.3)
        angle = 0.0
    }
    
    // MARK: -  Life Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        navigationController?.isNavigationBarHidden = true

        // Programmatically initialization
        
        /*
        cropViewProgrammatically = AKImageCropperView()
        */
        
        // iPhone 4.7"
        
        /*
        cropViewProgrammatically = AKImageCropperView(frame: CGRect(x: 0, y: 20.0, width: 375.0, height: 607.0))
        view.addSubview(cropViewProgrammatically)
        */
        
        // with constraints
        
        /*
        cropViewProgrammatically = AKImageCropperView()
        cropViewProgrammatically.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(cropViewProgrammatically)
        
        if #available(iOS 9.0, *) {
            
            cropViewProgrammatically.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            cropViewProgrammatically.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
            topLayoutGuide.bottomAnchor.constraint(equalTo: cropViewProgrammatically.topAnchor).isActive = true
            cropViewProgrammatically.bottomAnchor.constraint(equalTo: navigationView.topAnchor).isActive = true
            
        } else {
            
            for attribute: NSLayoutAttribute in [.top, .left, .bottom, .right] {
                
                var toItem: Any?
                var toAttribute: NSLayoutAttribute!
                
                if attribute == .top {
                    
                    toItem = topLayoutGuide
                    toAttribute = .bottom
                    
                } else if attribute == .bottom {
                    
                    toItem = navigationView
                    toAttribute = .top
                } else {
                    toItem = view
                    toAttribute = attribute
                }
                
                view.addConstraint(
                    NSLayoutConstraint(
                        item: cropViewProgrammatically,
                        attribute: attribute,
                        relatedBy: NSLayoutRelation.equal,
                        toItem: toItem,
                        attribute: toAttribute,
                        multiplier: 1.0, constant: 0))
            }
        }
        */
        

        // Inset for overlay action view
        
        /*
        cropView.overlayView?.configuraiton.cropRectInsets.bottom = 50
        */
        
        // Custom overlay view configuration
        
        /*
        var customConfiguraiton = AKImageCropperCropViewConfiguration()
            customConfiguraiton.cropRectInsets.bottom = 50
        cropView.overlayView = CustomImageCropperOverlayView(configuraiton: customConfiguraiton)
        */
        
        cropView.delegate = self
        cropView.image = image
    }
}

//  MARK: - AKImageCropperViewDelegate

extension CropperViewController: AKImageCropperViewDelegate {
    
    func imageCropperViewDidChangeCropRect(view: AKImageCropperView, cropRect rect: CGRect) {
//        print("New crop rectangle: \(rect)")
    }

}


================================================
FILE: AKImageCropperViewExample/CustomImageCropperOverlayView.swift
================================================
//
//  CustomImageCropperOverlayView.swift
//  Demo
//
//  Created by Artem Krachulov on 11/28/16.
//  Copyright © 2016 Artem Krachulov. All rights reserved.
//

import Foundation
import AKImageCropperView

final class CustomImageCropperOverlayView: AKImageCropperOverlayView {
    
    private func drawCycleInCornerView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        
        var color: UIColor
        var width: CGFloat
        
        if state == .normal {
            color = configuraiton.corner.normalLineColor
            width = configuraiton.corner.normalLineWidth
        } else {
            color = configuraiton.corner.highlightedLineColor
            width = configuraiton.corner.highlightedLineWidth
        }
        
        let layer: CAShapeLayer = view.layer.sublayers!.first as! CAShapeLayer
        
        let circlePath = UIBezierPath(
            arcCenter:  CGPoint(x: touchView.bounds.midX, y: touchView.bounds.midY),
            radius: width,
            startAngle: 0.0,
            endAngle: CGFloat(M_PI * 2),
            clockwise: true)

        layer.path = circlePath.cgPath
        layer.fillColor = color.cgColor
        layer.strokeColor = color.cgColor
    }
    
    override func layoutTopLeftCornerView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        drawCycleInCornerView(view, inTouchView: touchView, forState: state)
    }
    
    override func layoutTopRightCornerView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        drawCycleInCornerView(view, inTouchView: touchView, forState: state)
    }
    override func layoutBottomLeftCornerView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        drawCycleInCornerView(view, inTouchView: touchView, forState: state)
    }
    
    override func layoutBottomRightCornerView(_ view: UIView, inTouchView touchView: UIView, forState state: AKImageCropperCropViewTouchState) {
        drawCycleInCornerView(view, inTouchView: touchView, forState: state)
    }
}


================================================
FILE: AKImageCropperViewExample/HomeViewController.swift
================================================
//
//  HomeViewController.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//  Website: http://www.artemkrachulov.com/
//

import UIKit

final class HomeViewController: UIViewController {
    
    // MARK: - Connections:
    
    // MARK: -- Actions
    
    @IBAction func galleryAction() {
        
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.savedPhotosAlbum) {
            
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.sourceType = UIImagePickerControllerSourceType.savedPhotosAlbum
            imagePicker.allowsEditing = false
            
            present(imagePicker, animated: true, completion: nil)
        }
    }
    
    // MARK: - Life Cycle
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        navigationController?.isNavigationBarHidden = false
    }
}

// MARK: - UIImagePickerControllerDelegate

extension HomeViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        
        if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
            
            let cropperViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "cropperViewController") as! CropperViewController
            cropperViewController.image = pickedImage
            
            picker.pushViewController(cropperViewController, animated: true)
        }
    }
}


================================================
FILE: AKImageCropperViewExample/ImageViewController.swift
================================================
//
//  ImageViewController.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//  Website: http://www.artemkrachulov.com/
//

import UIKit

final class ImageViewController: UIViewController {
    
    // MARK: - Properties
    
    var image: UIImage!
    
    // MARK: - Connections:
    
    // MARK: -- Outlets
    
    @IBOutlet weak var imageView: UIImageView!
    
    // MARK: -- Actions
    
    @IBAction func backAction(_ sender: UIButton) {
        
        _ = navigationController?.popViewController(animated: true)
    }
    
    @IBAction func showListAction(_ sender: UIButton) {
        
        if presentingViewController != nil {
            
            _ = navigationController?.popToRootViewController(animated: true)

        } else {
        
            _ = navigationController?.popToViewController(navigationController!.viewControllers[1], animated: true)
        }
    }
    
    // MARK: - Life Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        imageView.image = image
    }
}


================================================
FILE: AKImageCropperViewExample/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "iphone",
      "size" : "20x20",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "20x20",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "29x29",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "29x29",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "40x40",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "40x40",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "60x60",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "60x60",
      "scale" : "3x"
    },
    {
      "idiom" : "ipad",
      "size" : "20x20",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "20x20",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "29x29",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "29x29",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "40x40",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "40x40",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "76x76",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "76x76",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "83.5x83.5",
      "scale" : "2x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Attractive-girl.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x",
      "filename" : "Attractive-girl-on-a-yacht-at-summer-day.jpg"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Autumn-background.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x",
      "filename" : "Autumn-background.jpg"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Colorful-pillows.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x",
      "filename" : "Colorful-pillows-on-a-sofa-with-white-brick-wall-in-background.jpg"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Contents.json
================================================
{
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Cupcakes.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x",
      "filename" : "Cupcakes.jpg"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Funnel-cake-stand.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x",
      "filename" : "Funnel-cake-stand-at-a-fair.jpg"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Icons/Contents.json
================================================
{
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Icons/overlay.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "overlay.pdf"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  },
  "properties" : {
    "template-rendering-intent" : "template"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Icons/random.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "random.pdf"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  },
  "properties" : {
    "template-rendering-intent" : "template"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Icons/rotate.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "rotate.pdf"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  },
  "properties" : {
    "template-rendering-intent" : "template"
  }
}

================================================
FILE: AKImageCropperViewExample/Images.xcassets/Image-of-earth.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x",
      "filename" : "Image-of-earth-planet.-Elements-of-this-image-are-furnished-by-NASA.jpg"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AKImageCropperViewExample/ImagesTableViewController.swift
================================================
//
//  ImagesTableViewController.swift
//
//  Created by Artem Krachulov.
//  Copyright (c) 2016 Artem Krachulov. All rights reserved.
//  Website: http://www.artemkrachulov.com/
//

import UIKit

final class ImagesTableViewController: UITableViewController {
    
    // MARK: - Life Cycle
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        navigationController?.isNavigationBarHidden = false
    }
    
    // MARK: - Navigation
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        
        let selectedPath = tableView.indexPathForSelectedRow!
        
        (segue.destination as! CropperViewController).image = UIImage(named: Constants.images[selectedPath.section][selectedPath.row])
    }
}

// MARK: - Table view data source

extension ImagesTableViewController {
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        
        return section == 0 ? "Large" : "Small"
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        
        return Constants.images.count
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        return Constants.images[section].count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "image", for: indexPath)
        
        let name = Constants.images[indexPath.section][indexPath.row]
        let image = UIImage(named: name)
        
        // Configure the cell...
        
        cell.textLabel!.text = name.components(separatedBy: "-").joined(separator: " ")
        cell.detailTextLabel?.text = String(format: "Size %0.1f x %0.1f", image?.size.width as CGFloat!, image?.size.height as CGFloat!)
        
        return cell
    }
}


================================================
FILE: AKImageCropperViewExample/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>en</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0.0</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>NSCameraUsageDescription</key>
	<string>$(PRODUCT_NAME) camera use</string>
	<key>NSPhotoLibraryUsageDescription</key>
	<string>$(PRODUCT_NAME) photo use</string>
	<key>UILaunchStoryboardName</key>
	<string>LaunchScreen</string>
	<key>UIMainStoryboardFile</key>
	<string>Main</string>
	<key>UIRequiredDeviceCapabilities</key>
	<array>
		<string>armv7</string>
	</array>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
</dict>
</plist>


================================================
FILE: LICENSE
================================================
Copyright (c) 2015-2016 Artem Krachulov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
# AKImageCropper

> Responsive image cropper

[![Carthage compatible][carthage-bage]][carthage-bage] 
[![CocoaPods Compatible][pods-bage]][pods-bage]

[![Platform][platform-bage]][platform-bage]
[![Swift Version][swift-bage]][swift-url]
[![Build Status][travis-bage]][travis-url]
[![License][license-bage]][license-url]

[pods-bage]: https://img.shields.io/badge/COCOAPODS-compatible-fb0006.svg
[pods-url]: https://cocoapods.org/
[carthage-bage]: https://img.shields.io/badge/Carthage-compatible-brightgreen.svg
[carthage-url]: https://github.com/Carthage/Carthage
[platform-bage]: https://img.shields.io/cocoapods/p/LFAlertController.svg
[platform-url]: http://cocoapods.org/pods/LFAlertController
[swift-bage]:https://img.shields.io/badge/swift-3.0-orange.svg
[swift-url]: https://swift.org/
[license-bage]: https://img.shields.io/badge/License-MIT-blue.svg
[license-url]: LICENSE
[travis-bage]: https://img.shields.io/travis/dbader/node-datadog-metrics/master.svg
[travis-url]: https://travis-ci.org/dbader/node-datadog-metrics

Image cropping plugin which supported different devices orientation. Easy to set up and configure. Has many settings for flexible integration into your project. Behavior is similar to native iOS photo cropper.

![](header.gif)

## Features

- [x] Overlay view & Crop rectangle full customization
- [x] Flexible settings
- [x] Image rotation
- [x] Infinite "Zoom To Fit"
- [x] Full image resolution
- [x] Ability to draw custom crop rectangle

## Requirements

- iOS 8.0+
- Xcode 7.3

## Installation

### CocoaPods

[CocoaPods][] is a dependency manager for Cocoa projects. To install **AKImageCropperView** with CocoaPods:

 1. Make sure CocoaPods is [installed][CocoaPods Installation].

 2. Update your Podfile to include the following:

``` ruby
use_frameworks!
pod 'AKImageCropperView'
```

 3. Run `pod install`.

[CocoaPods]: https://cocoapods.org
[CocoaPods Installation]: https://guides.cocoapods.org/using/getting-started.html#getting-started
 
 4. In your code import **AKImageCropperView** like so: `import AKImageCropperView`

### Carthage

[Carthage][] is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
To install **AKImageCropperView** with Carthage:

1. Install Carthage via [Homebrew][]

	```bash
	$ brew update
	$ brew install carthage
	```

2. Add `github "artemkrachulov/AKImageCropperView"` to your Cartfile.

3. Run `carthage update`.

4. Drag `AKMaskField.framework ` from the `Carthage/Build/iOS/` directory to the `Linked Frameworks and Libraries` section of your Xcode project’s `General` settings.

5. Add `$(SRCROOT)/Carthage/Build/iOS/AKImageCropperView.framework ` to `Input Files` of Run Script Phase for Carthage.

[Carthage]: https://github.com/Carthage/Carthage
[Homebrew]: http://brew.sh

### Manual

If you prefer not to use either of the aforementioned dependency managers, you can integrate **AKImageCropperView** into your project manually.

1. Download and drop **AKImageCropperView** folder in your project.
2. Done!

## Usage example

### Storyboard

```swift
@IBOutlet weak var cropView: AKImageCropperView!

override func viewDidLoad() {
    super.viewDidLoad()

    cropView.image = UIImage(named: "yourImage")
}
```

### Programmatically

```swift
var cropView: AKImageCropperView!

override func viewDidLoad() {
    super.viewDidLoad()

    cropView = AKImageCropperView(frame: CGRect(x: 0, y: 20.0, width: 375.0, height: 607.0))
    cropView.image = UIImage(named: "yourImage")
    view.addSubview(cropViewProgrammatically)
}
```

> Full examples with constraint, delegates and Overlay view configuration check in demo project.
> 
> **NOTE**: If after cropper view initialization your image has top inset. Go to storyboard with your scene and in the attributes inspector, uncheck 'Adjust Scrollview Insets'.

## Initializing an Image Cropper View

```swift
func init(image: UIImage?)
```

Returns an image cropper view initialized with the specified image.

**Parameters**

- `image` : The initial image to display in the image cropper view.
	
## Accessing the Displayed Images

```swift
var image: UIImage? { get set }
```	

The image displayed in the image cropper view. 
Default value of this property is `nil`.

```swift
var croppedImage: UIImage? { get }
```	

Cropperd image in the specified crop rectangle.

## Instance Properties

```swift
var isEdited: UIImage? { get }
```	

Returns the image edited state flag.

## Managing the Delegate

```swift
weak var delegate: AKImageCropperViewDelegate? { get set }
```	

The delegate of the cropper view object.

### Delegate methods

```swift
optional func imageCropperViewDidChangeCropRect(view: AKImageCropperView, cropRect rect: CGRect)
```	

Tells the delegate that crop frame was changed.

Parameters:

- **`view`**: The image cropper view.
- **`rect`**: New crop rectangle origin and size.

## Customizing an Overlay View

```swift
var overlayView: AKImageCropperOverlayView? { get set }
```	

Overlay view represented as AKImageCropperOverlayView open class. 

Base configuration and behavior can 
Download .txt
gitextract_x4b46xu8/

├── .gitignore
├── AKImageCropperView/
│   ├── AKImageCropperOverlayView.swift
│   ├── AKImageCropperOverlayViewConfiguration.swift
│   ├── AKImageCropperOverlayViewConfigurationCorner.swift
│   ├── AKImageCropperOverlayViewConfigurationEdge.swift
│   ├── AKImageCropperOverlayViewConfigurationGrid.swift
│   ├── AKImageCropperOverlayViewConfigurationOverlay.swift
│   ├── AKImageCropperOverlayViewTouchState.swift
│   ├── AKImageCropperScrollView.swift
│   ├── AKImageCropperView.h
│   ├── AKImageCropperView.swift
│   ├── IC_CGFloatExtension.swift
│   ├── IC_CGPointExtension.swift
│   ├── IC_CGSizeExtensions.swift
│   ├── IC_UIImageExtensions.swift
│   ├── Info.plist
│   └── PrimaryFilledButton.swift
├── AKImageCropperView.podspec
├── AKImageCropperView.xcodeproj/
│   ├── project.pbxproj
│   ├── project.xcworkspace/
│   │   ├── contents.xcworkspacedata
│   │   └── xcshareddata/
│   │       ├── AKImageCropperDemo.xcscmblueprint
│   │       └── Demo.xcscmblueprint
│   └── xcshareddata/
│       └── xcschemes/
│           └── AKImageCropperView.xcscheme
├── AKImageCropperViewExample/
│   ├── AppDelegate.swift
│   ├── Base.lproj/
│   │   ├── LaunchScreen.xib
│   │   └── Main.storyboard
│   ├── Constants.swift
│   ├── CropperViewController.swift
│   ├── CustomImageCropperOverlayView.swift
│   ├── HomeViewController.swift
│   ├── ImageViewController.swift
│   ├── Images.xcassets/
│   │   ├── AppIcon.appiconset/
│   │   │   └── Contents.json
│   │   ├── Attractive-girl.imageset/
│   │   │   └── Contents.json
│   │   ├── Autumn-background.imageset/
│   │   │   └── Contents.json
│   │   ├── Colorful-pillows.imageset/
│   │   │   └── Contents.json
│   │   ├── Contents.json
│   │   ├── Cupcakes.imageset/
│   │   │   └── Contents.json
│   │   ├── Funnel-cake-stand.imageset/
│   │   │   └── Contents.json
│   │   ├── Icons/
│   │   │   ├── Contents.json
│   │   │   ├── overlay.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── random.imageset/
│   │   │   │   └── Contents.json
│   │   │   └── rotate.imageset/
│   │   │       └── Contents.json
│   │   └── Image-of-earth.imageset/
│   │       └── Contents.json
│   ├── ImagesTableViewController.swift
│   └── Info.plist
├── LICENSE
└── README.md
Condensed preview — 47 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (216K chars).
[
  {
    "path": ".gitignore",
    "chars": 249,
    "preview": "# Xcode\n.DS_Store\n*/build/*\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspecti"
  },
  {
    "path": "AKImageCropperView/AKImageCropperOverlayView.swift",
    "chars": 37103,
    "preview": "//\n//  AKImageCropperOverlayView.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem Krachulov. All ri"
  },
  {
    "path": "AKImageCropperView/AKImageCropperOverlayViewConfiguration.swift",
    "chars": 3182,
    "preview": "//\n//  AKImageCropperCropViewConfiguration.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem Krachul"
  },
  {
    "path": "AKImageCropperView/AKImageCropperOverlayViewConfigurationCorner.swift",
    "chars": 2080,
    "preview": "//\n//  AKImageCropperCropViewConfigurationCorner.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem K"
  },
  {
    "path": "AKImageCropperView/AKImageCropperOverlayViewConfigurationEdge.swift",
    "chars": 1838,
    "preview": "//\n//  AKImageCropperCropViewConfigurationEdge.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem Kra"
  },
  {
    "path": "AKImageCropperView/AKImageCropperOverlayViewConfigurationGrid.swift",
    "chars": 2041,
    "preview": "//\n//  AKImageCropperCropViewConfigurationGrid.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem Kra"
  },
  {
    "path": "AKImageCropperView/AKImageCropperOverlayViewConfigurationOverlay.swift",
    "chars": 1944,
    "preview": "//\n//  AKImageCropperCropViewConfigurationOverlay.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem "
  },
  {
    "path": "AKImageCropperView/AKImageCropperOverlayViewTouchState.swift",
    "chars": 1405,
    "preview": "//\n//  AKImageCropperCropViewTouchState.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem Krachulov."
  },
  {
    "path": "AKImageCropperView/AKImageCropperScrollView.swift",
    "chars": 2222,
    "preview": "//\n//  AKImageCropperScrollView.swift\n//  AKImageCropperView\n//\n//  Created by Artem Krachulov on 12/17/16.\n//  Copyrigh"
  },
  {
    "path": "AKImageCropperView/AKImageCropperView.h",
    "chars": 567,
    "preview": "//\n//  AKImageCropperView.h\n//  AKImageCropperView\n//\n//  Created by Artem Krachulov on 12/13/16.\n//  Copyright © 2016 A"
  },
  {
    "path": "AKImageCropperView/AKImageCropperView.swift",
    "chars": 28443,
    "preview": "//\n//  AKImageCropperView.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem Krachulov. All rights re"
  },
  {
    "path": "AKImageCropperView/IC_CGFloatExtension.swift",
    "chars": 596,
    "preview": "//\n//  ic_CGFloatExtension.swift\n//  AKImageCropperView\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem "
  },
  {
    "path": "AKImageCropperView/IC_CGPointExtension.swift",
    "chars": 420,
    "preview": "//\n//  IC_CGPointExtension.swift\n//  AKImageCropperView\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem "
  },
  {
    "path": "AKImageCropperView/IC_CGSizeExtensions.swift",
    "chars": 1333,
    "preview": "//\n//  IC_CGSizeExtensions.swift\n//  AKImageCropperView\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem "
  },
  {
    "path": "AKImageCropperView/IC_UIImageExtensions.swift",
    "chars": 2320,
    "preview": "//\n//  IC_UIImageExtensions.swift\n//  AKImageCropperView\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem"
  },
  {
    "path": "AKImageCropperView/Info.plist",
    "chars": 755,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "AKImageCropperView/PrimaryFilledButton.swift",
    "chars": 163,
    "preview": "//\n//  PrimaryFilledButton.swift\n//  Visitor\n//\n//  Created by Artem Krachulov on 1/16/17.\n//  Copyright © 2017 VZPass. "
  },
  {
    "path": "AKImageCropperView.podspec",
    "chars": 916,
    "preview": "Pod::Spec.new do |s|\n\n  s.name         = \"AKImageCropperView\"\n  s.version      = \"2.0.0\"\n  s.homepage     = \"https://git"
  },
  {
    "path": "AKImageCropperView.xcodeproj/project.pbxproj",
    "chars": 29224,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "AKImageCropperView.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "chars": 206,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:/Users/artemkra"
  },
  {
    "path": "AKImageCropperView.xcodeproj/project.xcworkspace/xcshareddata/AKImageCropperDemo.xcscmblueprint",
    "chars": 3317,
    "preview": "{\n  \"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey\" : \"74FC6B16832EDE035AC047E84A01E2F0C9097FE9\",\n  \"DVTS"
  },
  {
    "path": "AKImageCropperView.xcodeproj/project.xcworkspace/xcshareddata/Demo.xcscmblueprint",
    "chars": 3289,
    "preview": "{\n  \"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey\" : \"74FC6B16832EDE035AC047E84A01E2F0C9097FE9\",\n  \"DVTS"
  },
  {
    "path": "AKImageCropperView.xcodeproj/xcshareddata/xcschemes/AKImageCropperView.xcscheme",
    "chars": 2949,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0820\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "AKImageCropperViewExample/AppDelegate.swift",
    "chars": 2279,
    "preview": "//\n//  AppDelegate.swift\n//  AKImageCropperDemo\n//  GitHub: https://github.com/artemkrachulov/AKImageCropper\n//\n//  Crea"
  },
  {
    "path": "AKImageCropperViewExample/Base.lproj/LaunchScreen.xib",
    "chars": 1269,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
  },
  {
    "path": "AKImageCropperViewExample/Base.lproj/Main.storyboard",
    "chars": 35143,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
  },
  {
    "path": "AKImageCropperViewExample/Constants.swift",
    "chars": 349,
    "preview": "//\n//  Constants.swift\n//  Demo\n//\n//  Created by Artem Krachulov on 11/18/16.\n//  Copyright © 2016 Artem Krachulov. All"
  },
  {
    "path": "AKImageCropperViewExample/CropperViewController.swift",
    "chars": 7622,
    "preview": "//\n//  CropperViewController.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem Krachulov. All rights"
  },
  {
    "path": "AKImageCropperViewExample/CustomImageCropperOverlayView.swift",
    "chars": 2184,
    "preview": "//\n//  CustomImageCropperOverlayView.swift\n//  Demo\n//\n//  Created by Artem Krachulov on 11/28/16.\n//  Copyright © 2016 "
  },
  {
    "path": "AKImageCropperViewExample/HomeViewController.swift",
    "chars": 1717,
    "preview": "//\n//  HomeViewController.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem Krachulov. All rights re"
  },
  {
    "path": "AKImageCropperViewExample/ImageViewController.swift",
    "chars": 1098,
    "preview": "//\n//  ImageViewController.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem Krachulov. All rights r"
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 1495,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\""
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Attractive-girl.imageset/Contents.json",
    "chars": 337,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Attractive-girl-on-a-yacht"
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Autumn-background.imageset/Contents.json",
    "chars": 314,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Autumn-background.jpg\"\n   "
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Colorful-pillows.imageset/Contents.json",
    "chars": 359,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Colorful-pillows-on-a-sofa"
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Cupcakes.imageset/Contents.json",
    "chars": 305,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Cupcakes.jpg\"\n    },\n    {"
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Funnel-cake-stand.imageset/Contents.json",
    "chars": 324,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Funnel-cake-stand-at-a-fai"
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Icons/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Icons/overlay.imageset/Contents.json",
    "chars": 225,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"overlay.pdf\"\n    }\n  ],\n  \"info\" : {\n    \"versio"
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Icons/random.imageset/Contents.json",
    "chars": 224,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"random.pdf\"\n    }\n  ],\n  \"info\" : {\n    \"version"
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Icons/rotate.imageset/Contents.json",
    "chars": 224,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"rotate.pdf\"\n    }\n  ],\n  \"info\" : {\n    \"version"
  },
  {
    "path": "AKImageCropperViewExample/Images.xcassets/Image-of-earth.imageset/Contents.json",
    "chars": 364,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Image-of-earth-planet.-Ele"
  },
  {
    "path": "AKImageCropperViewExample/ImagesTableViewController.swift",
    "chars": 1983,
    "preview": "//\n//  ImagesTableViewController.swift\n//\n//  Created by Artem Krachulov.\n//  Copyright (c) 2016 Artem Krachulov. All ri"
  },
  {
    "path": "AKImageCropperViewExample/Info.plist",
    "chars": 1666,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2015-2016 Artem Krachulov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
  },
  {
    "path": "README.md",
    "chars": 14714,
    "preview": "# AKImageCropper\n\n> Responsive image cropper\n\n[![Carthage compatible][carthage-bage]][carthage-bage] \n[![CocoaPods Compa"
  }
]

About this extraction

This page contains the full source code of the artemkrachulov/AKImageCropperView GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 47 files (197.2 KB), approximately 51.0k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!