{"id":1449,"url":"https://github.com/TimOliver/TOCropViewController","last_synced_at":"2025-08-02T04:31:11.836Z","repository":{"id":33352848,"uuid":"36997653","full_name":"TimOliver/TOCropViewController","owner":"TimOliver","description":"A view controller for iOS that allows users to crop portions of UIImage objects","archived":false,"fork":false,"pushed_at":"2024-12-08T03:57:52.000Z","size":8707,"stargazers_count":4837,"open_issues_count":106,"forks_count":991,"subscribers_count":89,"default_branch":"main","last_synced_at":"2025-07-30T05:24:03.277Z","etag":null,"topics":["cocoapods","crop","crop-image","cropper","cropping","image","image-processing","ios","podfile","swift","uiimage","view","viewcontroller"],"latest_commit_sha":null,"homepage":"http://www.timoliver.com.au/2015/06/21/tocropviewcontroller-an-open-source-image-cropper-for-ios/","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TimOliver.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"timoliver","custom":"https://tim.dev/paypal"}},"created_at":"2015-06-06T22:53:07.000Z","updated_at":"2025-07-30T04:11:04.000Z","dependencies_parsed_at":"2022-08-07T20:31:19.393Z","dependency_job_id":"418887b4-c034-40ee-8329-37b89b08a4bc","html_url":"https://github.com/TimOliver/TOCropViewController","commit_stats":{"total_commits":663,"total_committers":107,"mean_commits":6.196261682242991,"dds":"0.36651583710407243","last_synced_commit":"a942414508012b13102f776eb65dac655f31cabb"},"previous_names":[],"tags_count":70,"template":false,"template_full_name":null,"purl":"pkg:github/TimOliver/TOCropViewController","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TimOliver%2FTOCropViewController","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TimOliver%2FTOCropViewController/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TimOliver%2FTOCropViewController/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TimOliver%2FTOCropViewController/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TimOliver","download_url":"https://codeload.github.com/TimOliver/TOCropViewController/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TimOliver%2FTOCropViewController/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268334611,"owners_count":24233793,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cocoapods","crop","crop-image","cropper","cropping","image","image-processing","ios","podfile","swift","uiimage","view","viewcontroller"],"created_at":"2024-01-05T20:15:46.708Z","updated_at":"2025-08-02T04:31:10.939Z","avatar_url":"https://github.com/TimOliver.png","language":"Objective-C","readme":"# TOCropViewController\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/TimOliver/TOCropViewController/raw/main/Images/screenshot.webp\" width=\"840\" style=\"margin:0 auto\" /\u003e\n\u003c/p\u003e\n\n[![CI](https://github.com/TimOliver/TOCropViewController/workflows/CI/badge.svg)](https://github.com/TimOliver/TOCropViewController/actions?query=workflow%3ACI)\n![Version](https://img.shields.io/cocoapods/v/TOCropViewController.svg?style=flat)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/TimOliver/TOCropViewController/master/LICENSE)\n![Platform](https://img.shields.io/cocoapods/p/TOCropViewController.svg?style=flat)\n\n`TOCropViewController` is an open-source `UIViewController` subclass to crop out sections of `UIImage` objects, as well as perform basic rotations. It is excellent for things like editing profile pictures, or sharing parts of a photo online. It has been designed with the iOS Photos app editor in mind, and as such, behaves in a way that should already feel familiar to users of iOS.\n\nFor Swift developers, `CropViewController` is a Swift wrapper that completely encapsulates `TOCropViewController` and provides a much more native, Swiftier interface.\n\n#### Proudly powering apps by\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/TimOliver/TOCropViewController/raw/main/Images/users.png\" width=\"840\" style=\"margin:0 auto\" /\u003e\n\u003c/p\u003e\n\n_Looking for something more? If `TOCropViewController` doesn't meet your exact requirements, please consider [IMG.LY](https://img.ly/?via=tim) with video editing and photo filter capabilities instead! (Disclaimer: Affiliate Link)_\n\n## Features\n* Crop images by dragging the edges of a grid overlay.\n* Optionally, crop circular copies of images.\n* Rotate images in 90-degree segments.\n* Clamp the crop box to a specific aspect ratio.\n* A reset button to completely undo all changes.\n* iOS 7/8 translucency to make it easier to view the cropped region.\n* The choice of having the controller return the cropped image to a delegate, or immediately pass it to a `UIActivityViewController`.\n* A custom animation and layout when the device is rotated to landscape mode.\n* Custom 'opening' and 'dismissal' animations.\n* Localized in 28 languages.\n\n## System Requirements\niOS 11.0 or above\n\n## Installation\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eCocoaPods\u003c/strong\u003e\u003c/summary\u003e\n  \n  \u003ch4\u003eObjective-C\u003c/h4\u003e\n\nAdd the following to your Podfile:\n``` ruby\npod 'TOCropViewController'\n```\n\n\u003ch4\u003eSwift\u003c/h4\u003e\n\nAdd the following to your Podfile:\n``` ruby\npod 'CropViewController'\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eSwift Package Manager\u003c/strong\u003e\u003c/summary\u003e\n\nAdd the following to your `Package.swift`:\n``` swift\ndependencies: [\n  // ...\n  .package(url: \"https://github.com/TimOliver/TOCropViewController.git\"),\n],\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eCarthage\u003c/strong\u003e\u003c/summary\u003e\n\n1. Add the following to your Cartfile:\n``` \ngithub \"TimOliver/TOCropViewController\"\n```\n\n2. Run `carthage update`\n\n3. From the `Carthage/Build` folder, import one of the two frameworks into your Xcode project. For Objective-C projects, import just `TOCropViewController.framework`  and for Swift, import `CropViewController.framework` instead. Each framework is separate; you do not need to import both.\n\n4. Follow the remaining steps on [Getting Started with Carthage](https://github.com/Carthage/Carthage#getting-started) to finish integrating the framework.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eManual Installation\u003c/strong\u003e\u003c/summary\u003e\n\nAll of the necessary source and resource files for `TOCropViewController` are in `Objective-C/TOCropViewController`, and all of the necessary Swift files are in `Swift/CropViewController`.\n\nFor Objective-C projects, copy just the `TOCropViewController` directory to your Xcode project. For Swift projects, copy both `TOCropViewController` and `CropViewController` to your project.\n\u003c/details\u003e\n\n## Examples\nUsing `TOCropViewController` is very straightforward. Simply create a new instance passing the `UIImage` object you wish to crop, and then present it modally on the screen.\n\nWhile `TOCropViewController` prefers to be presented modally, it can also be pushed to a `UINavigationController` stack.\n\nFor a complete working example, check out the sample apps included in this repo.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eBasic Implementation\u003c/strong\u003e\u003c/summary\u003e\n\n#### Swift\n```swift\nfunc presentCropViewController() {\n  let image: UIImage = ... //Load an image\n  \n  let cropViewController = CropViewController(image: image)\n  cropViewController.delegate = self\n  present(cropViewController, animated: true, completion: nil)\n}\n\nfunc cropViewController(_ cropViewController: CropViewController, didCropToImage image: UIImage, withRect cropRect: CGRect, angle: Int) {\n        // 'image' is the newly cropped version of the original image\n    }\n```\n\n#### Objective-C\n```objc\n- (void)presentCropViewController\n{\n  UIImage *image = ...; // Load an image\n  \n  TOCropViewController *cropViewController = [[TOCropViewController alloc] initWithImage:image];\n  cropViewController.delegate = self;\n  [self presentViewController:cropViewController animated:YES completion:nil];\n}\n\n- (void)cropViewController:(TOCropViewController *)cropViewController didCropToImage:(UIImage *)image withRect:(CGRect)cropRect angle:(NSInteger)angle\n{\n  // 'image' is the newly cropped version of the original image\n}\n```\n\nSimilar to many `UIKit` `UIViewController` subclasses, like `MFMailComposeViewController`, the class responsible for presenting view controller should also take care of dismissing it upon cancellation. To dismiss `TOCropViewController`, implement the `cropViewController:didFinishCancelled:` delegate method, and call `dismissViewController:animated:` from there.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eMaking a Circular Cropped Image\u003c/strong\u003e\u003c/summary\u003e\n\n#### Swift\n```swift\nfunc presentCropViewController() {\n    var image: UIImage? // Load an image\n    let cropViewController = CropViewController(croppingStyle: .circular, image: image)\n    cropViewController.delegate = self\n    self.present(cropViewController, animated: true, completion: nil)\n}\n\nfunc cropViewController(_ cropViewController: TOCropViewController?, didCropToCircularImage image: UIImage?, with cropRect: CGRect, angle: Int) {\n    // 'image' is the newly cropped, circular version of the original image\n}\n```\n\n\n#### Objective-C\n```objc\n- (void)presentCropViewController\n{\nUIImage *image = ...; // Load an image\n\nTOCropViewController *cropViewController = [[TOCropViewController alloc] initWithCroppingStyle:TOCropViewCroppingStyleCircular image:image];\ncropViewController.delegate = self;\n[self presentViewController:cropViewController animated:YES completion:nil];\n}\n\n- (void)cropViewController:(TOCropViewController *)cropViewController didCropToCircularImage:(UIImage *)image withRect:(CGRect)cropRect angle:(NSInteger)angle\n{\n// 'image' is the newly cropped, circular version of the original image\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eSharing Cropped Images Via a Share Sheet\u003c/strong\u003e\u003c/summary\u003e\n\n#### Swift\n```swift\nfunc presentCropViewController() {\n    var image: UIImage? // Load an image\n    let cropViewController = CropViewController(image: image)\n    cropViewController.showActivitySheetOnDone = true\n    self.present(cropViewController, animated: true, completion: nil)\n}\n```\n\n#### Objective-C\n```objc\n- (void)presentCropViewController\n{\n  UIImage *image = ...; // Load an image\n  \n  TOCropViewController *cropViewController = [[TOCropViewController alloc] initWithImage:image];\n  cropViewController.showActivitySheetOnDone = YES;\n  [self presentViewController:cropViewController animated:YES completion:nil];\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003ePresenting With a Custom Animation\u003c/strong\u003e\u003c/summary\u003e\n\nOptionally, `TOCropViewController` also supports a custom presentation animation where an already-visible copy of the image will zoom in to fill the screen.\n\n#### Swift\n```swift\n\nfunc presentCropViewController() {\n    var image: UIImage? // Load an image\n    var imageView = UIImageView(image: image)\n    var frame: CGRect = view.convert(imageView.frame, to: view)\n    \n    let cropViewController = CropViewController(image: image)\n    cropViewController.delegate = self\n    self.present(cropViewController, animated: true, completion: nil)\n    cropViewController.presentAnimated(fromParentViewController: self, fromFrame: frame, completion: nil)\n}\n```\n\n#### Objective-C\n```objc\n- (void)presentCropViewController\n{\n  UIImage *image = ...;\n  UIImageView *imageView = [[UIImageView alloc] initWithImage:image];\n  CGRect frame = [self.view convertRect:imageView.frame toView:self.view];\n  \n  TOCropViewController *cropViewController = [[TOCropViewController alloc] initWithImage:image];\n  cropViewController.delegate = self;\n  [self presentViewController:cropViewController animated:YES completion:nil];\n  [cropViewController presentAnimatedFromParentViewController:self fromFrame:frame completion:nil];\n}\n```\n\u003c/details\u003e\n\n## Architecture of `TOCropViewController`\nWhile traditional cropping UI implementations will usually just have a dimming view with a square hole cut out of the middle, `TOCropViewController` goes about its implementation a little differently.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://raw.githubusercontent.com/TimOliver/TOCropViewController/master/breakdown.jpg\" width=\"702\" style=\"margin:0 auto\" /\u003e\n\u003c/p\u003e\n\nSince there are two views that are overlaid over the image (A dimming view and a translucency view), trying to cut a hole open in both of them would be rather complex. Instead, an image view is placed in a scroll view in the background, and a copy of the image view is placed on top, inside a container view that is clipped to the designated cropping size. The size and position of the foreground image is then made to match the background view, creating the illusion that there is a hole in the dimming views, and minimising the number of views onscreen.\n\n## Credits\n`TOCropViewController` was originally created by [Tim Oliver](http://twitter.com/TimOliverAU) as a component for [iComics](http://icomics.co), a comic reader app for iOS.\n\nThanks also goes to `TOCropViewController`'s growing list of [contributors](https://github.com/TimOliver/TOCropViewController/graphs/contributors)!\n\niOS Device mockups used in the screenshot created by [Pixeden](http://www.pixeden.com).\n\n## License\nTOCropViewController is licensed under the MIT License, please see the [LICENSE](LICENSE) file.\n","funding_links":["https://github.com/sponsors/timoliver","https://tim.dev/paypal"],"categories":["Media","Objective-C","Objective-C  Stars 1000以内排名整理","UI","UI Components","viewcontroller"],"sub_categories":["Image","Other free courses"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTimOliver%2FTOCropViewController","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTimOliver%2FTOCropViewController","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTimOliver%2FTOCropViewController/lists"}