{"id":13995141,"url":"https://github.com/guoyingtao/Mantis","last_synced_at":"2025-07-22T21:32:07.631Z","repository":{"id":37734673,"uuid":"154051642","full_name":"guoyingtao/Mantis","owner":"guoyingtao","description":"An iOS Image cropping library, which mimics the Photo App written in Swift.","archived":false,"fork":false,"pushed_at":"2024-11-06T22:01:33.000Z","size":56688,"stargazers_count":926,"open_issues_count":7,"forks_count":184,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-11-20T08:06:47.898Z","etag":null,"topics":["crop","cropper","cropping","image-crop","image-cropper","image-cropping","imagecrop","imagecropper","imagecropperswift","imagecropping","ios","photocrop","photocropping","swift","swiftphotocropping","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/guoyingtao.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"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},"funding":{"github":["guoyingto"]}},"created_at":"2018-10-21T20:57:49.000Z","updated_at":"2024-11-17T18:06:55.000Z","dependencies_parsed_at":"2022-07-08T00:18:51.350Z","dependency_job_id":"ed6c668a-9b3e-45af-bf57-42eb9eebf2b1","html_url":"https://github.com/guoyingtao/Mantis","commit_stats":{"total_commits":692,"total_committers":26,"mean_commits":"26.615384615384617","dds":"0.20664739884393069","last_synced_commit":"336d3805f470fcc4278e806609d7e9d3527dd3d6"},"previous_names":[],"tags_count":115,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guoyingtao%2FMantis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guoyingtao%2FMantis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guoyingtao%2FMantis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guoyingtao%2FMantis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guoyingtao","download_url":"https://codeload.github.com/guoyingtao/Mantis/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227177792,"owners_count":17743167,"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","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":["crop","cropper","cropping","image-crop","image-cropper","image-cropping","imagecrop","imagecropper","imagecropperswift","imagecropping","ios","photocrop","photocropping","swift","swiftphotocropping","swiftui"],"created_at":"2024-08-09T14:03:16.056Z","updated_at":"2025-07-22T21:32:07.619Z","avatar_url":"https://github.com/guoyingtao.png","language":"Swift","funding_links":["https://github.com/sponsors/guoyingto","https://github.com/sponsors/guoyingtao"],"categories":["Swift"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"logo.png\" height=\"80\" max-width=\"90%\" alt=\"Mantis\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/swift-5.0-orange.svg\" alt=\"swift 5.0 badge\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/platform-iOS-lightgrey.svg\" alt=\"platform iOS badge\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/license-MIT-black.svg\" alt=\"license MIT badge\" /\u003e   \n\u003c/p\u003e\n\n# Mantis\n\n   Mantis is an iOS Image cropping library, which mimics the Photo App written in Swift and provides rich cropping interactions for your iOS/Mac app (Catalyst only).\n   \n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"Images/RotationDial.png\" height=\"400\" alt=\"Mantis RotaionDial\" /\u003e \n    \u003cimg src=\"Images/SlideDial.png\" height=\"400\" alt=\"Mantis SlideDial\" /\u003e\n\u003c/p\u003e\n\n### Demos\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"Images/Normal demos.gif\" width=\"200\" alt=\"Mantis Normal Demos\" /\u003e \n    \u003cimg src=\"Images/Rotation dial demos.gif\" width=\"200\" alt=\"Mantis RotaionDial Demos\" /\u003e \n    \u003cimg src=\"Images/Slide dial with flip demos.gif\" width=\"200\" alt=\"Mantis SlideDial Demos\" /\u003e \n\u003c/p\u003e\n   \n   Mantis also provides rich crop shapes from the basic circle/square to polygon to arbitrary paths(We even provide a heart shape ❤️ 😏).\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"Images/cropshapes.png\" height=\"450\" alt=\"Mantis\" /\u003e\n\u003c/p\u003e\n\n## Requirements\n* iOS 12.0+\n* MacOS 10.15+\n* Xcode 10.0+\n\n## Install\n\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cstrong\u003eCocoaPods\u003c/strong\u003e\u003c/summary\u003e\n\n```ruby\npod 'Mantis', '~\u003e 2.26.0'\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n \u003csummary\u003e\u003cstrong\u003eCarthage\u003c/strong\u003e\u003c/summary\u003e\n\n```ruby\ngithub \"guoyingtao/Mantis\"\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n \u003csummary\u003e\u003cstrong\u003eSwift Packages\u003c/strong\u003e\u003c/summary\u003e\n\n* Repository: https://github.com/guoyingtao/Mantis.git\n* Rules: Version - Exact - 2.26.0\n\n\u003c/details\u003e\n\n## Usage\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eBasic\u003c/strong\u003e\u003c/summary\u003e\n\n* Create a CropViewController from Mantis with default config\n\n**You need set (cropViewController or its navigation controller).modalPresentationStyle = .fullscreen for iOS 13+ when the cropViewController is presented**\n\n### UIKit\n\n```Swift\n    let cropViewController = Mantis.cropViewController(image: \u003cYour Image\u003e)\n    cropViewController.delegate = self\n    \u003cYour ViewController\u003e.present(cropViewController, animated: true)\n```\n\n### SwiftUI\n\n* Create an ImageCropperView from Mantis with default config\n\n```Swift\nstruct MyView: View {\n    @State private var image: UIImage?\n    @State private var transformation: Transformation?\n    @State private var cropInfo: CropInfo?\n\n    var body: some View {\n        ImageCropperView(\n            image: $image,\n            transformation: $transformation,\n            cropInfo: $cropInfo\n        )\n    }\n}\n```\n\n* The caller needs to conform CropViewControllerDelegate\n```swift\npublic protocol CropViewControllerDelegate: class {\n    func cropViewControllerDidCrop(_ cropViewController: CropViewController, cropped: UIImage, transformation: Transformation, cropInfo: CropInfo)\n    func cropViewControllerDidCancel(_ cropViewController: CropViewController, original: UIImage)\n    \n    // The implementation of the following functions are optional\n    func cropViewControllerDidFailToCrop(_ cropViewController: CropViewController, original: UIImage)     \n    func cropViewControllerDidBeginResize(_ cropViewController: CropViewController)\n    func cropViewControllerDidEndResize(_ cropViewController: CropViewController, original: UIImage, cropInfo: CropInfo)    \n}\n```\n\u003c/details\u003e\n    \n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCropToolbar mode\u003c/strong\u003e\u003c/summary\u003e\n\n* CropToolbar has two modes:\n\n  * normal mode\n\n  In normal mode, you can use a set of standard CropViewController photo editing features with \"Cancel\" and \"Done\" buttons.\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"Images/Screen Shot.png\" height=\"300\" alt=\"Mantis\" /\u003e\n\u003c/p\u003e\n\n```swift\nlet cropViewController = Mantis.cropViewController(image: \u003cYour Image\u003e)\n```\n\n  * embedded mode\n  \n  This mode does not include \"Cancel\" and \"Done\" buttons, so you can embed CropViewController into another view controller\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"Images/customizable.jpg\" height=\"300\" alt=\"Mantis\" /\u003e\n\u003c/p\u003e\n\n```swift\nvar config = Mantis.Config()\nconfig.cropToolbarConfig.mode = .embedded\nlet cropViewController = Mantis.cropViewController(image: \u003cYour Image\u003e, config: config)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eAdd your own ratio\u003c/strong\u003e\u003c/summary\u003e\n\n```swift\n            // Add a custom ratio 1:2 for portrait orientation\n            let config = Mantis.Config()\n            config.addCustomRatio(byVerticalWidth: 1, andVerticalHeight: 2)            \n            \u003cYour Crop ViewController\u003e = Mantis.cropViewController(image: \u003cYour Image\u003e, config: config)\n            \n            // Set the ratioOptions of the config if you don't want to keep all default ratios\n            let config = Mantis.Config() \n            //config.ratioOptions = [.original, .square, .custom]\n            config.ratioOptions = [.custom]\n            config.addCustomRatio(byVerticalWidth: 1, andVerticalHeight: 2)            \n            \u003cYour Crop ViewController\u003e = Mantis.cropViewController(image: \u003cYour Image\u003e, config: config)\n```\n\n* If you always want to use only one fixed ratio, set Mantis.Config.presetFixedRatioType = alwaysUsingOnePresetFixedRatio\n\n```swift\n    \u003cYour Crop ViewController\u003e.config.presetFixedRatioType = .alwaysUsingOnePresetFixedRatio(ratio: 16.0 / 9.0)\n```\n\nWhen choose alwaysUsingOnePresetFixedRatio, fixed-ratio setting button does not show.\n\n* If you want to hide rotation control view, set Mantis.Config.cropViewConfig.showAttachedRotationControlView = false\n* If you want to use ratio list instead of presenter, set Mantis.CropToolbarConfig.ratioCandidatesShowType = .alwaysShowRatioList\n\n```swift\npublic enum RatioCandidatesShowType {\n    case presentRatioList\n    case alwaysShowRatioList\n}\n```\n\n* If you build your custom toolbar you can add your own fixed ratio buttons\n```swift\n// set a custom fixed ratio\ncropToolbarDelegate?.didSelectRatio(ratio: 9 / 16)\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCrop shapes\u003c/strong\u003e\u003c/summary\u003e\n\n* If you want to set different crop shape, set Mantis.Config.cropViewConfig.cropShapeType\n```swift\npublic enum CropShapeType {\n    case rect\n    case square\n    case ellipse\n    case circle(maskOnly: Bool = false)\n    case diamond(maskOnly: Bool = false)\n    case heart(maskOnly: Bool = false)\n    case polygon(sides: Int, offset: CGFloat = 0, maskOnly: Bool = false)\n    case path(points: [CGPoint], maskOnly: Bool = false)\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003ePreset transformations\u003c/strong\u003e\u003c/summary\u003e\n\n* If you want to apply transformations when showing an image, set Mantis.Config.cropViewConfig.presetTransformationType\n```swift\npublic enum PresetTransformationType {\n    case none\n    case presetInfo(info: Transformation)\n    case presetNormalizedInfo(normalizedInfo: CGRect)\n}\n```\nPlease use the transformation information obtained previously from delegate method cropViewControllerDidCrop(_ cropViewController: CropViewController, cropped: UIImage, transformation: Transformation, , cropInfo: CropInfo).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eUndo/Redo Support\u003c/strong\u003e\u003c/summary\u003e\n\n* Mantis offers full support for Undo, Redo, Revert to Original in both iOS and Catalyst.\n\n* If you want to add support for this feature, set Mantis.Config.enableUndoRedo = true\n\n* Catalyst menus for this feature are localized.\n\n\u003c/details\u003e\n                \n\u003cdetails\u003e\n    \u003csummary\u003e\u003cstrong\u003eLocalization\u003c/strong\u003e\u003c/summary\u003e\n    \n* UIKit project    \n    Add more languages support to the Localizations section for Project Info tab \n    \n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://user-images.githubusercontent.com/26723384/128650945-5a1da648-7e7d-4faf-9c95-232725b05dcc.png\" height=\"200\" alt=\"Mantis\" /\u003e\n    \u003cbr\u003efig 1\u003c/br\u003e\n\u003c/p\u003e\n    \n* SwiftUI project    \n    Please check this [link](https://github.com/guoyingtao/Mantis/discussions/123#discussioncomment-1127611)\n\n* Static frameworks\n    If you use static frameworks in CocoaPods, you need to add the code below in order to find the correct resource bundle.\n    \n```\n    Mantis.locateResourceBundle(by: Self.self)\n```\n  \n* Custom localization tables and bundle\n    \nBy default mantis will use built in localization tables to get string resources not every language is supported out of the box (see fig 1).\n    \nHowever if your app support multiple languages and those languages are not 'built in', then you can define your own strings table and localize them in the application target or framework. By doing so you'll need to configure Mantis localization.\n\n**IMPORTANT!** Firstly you'll need to create strings file with these keys:\n\n```\n\"Mantis.Done\" = \"\";\n\"Mantis.Cancel\" = \"\";\n\"Mantis.Reset\" = \"\";\n\"Mantis.Original\" = \"\";\n\"Mantis.Square\" = \"\";\n```\nThen you'll need to configure Mantis:\n\n```\nlet config = Mantis.Config()\nconfig.localizationConfig.bundle = // a bundle where strings file is located\nconfig.localizationConfig.tableName = // a localized strings file name within the bundle\n```\n  \n\u003c/details\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cstrong\u003eCustom View Controller\u003c/strong\u003e\u003c/summary\u003e\n\n- If needed you can subclass `CropViewController`:\n\n```swift\nclass CustomViewController: CropViewController {\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        // Do your custom logic here.\n        // The MantisExample project also has a showcase for a CustomViewController.\n    }\n}\n```\n\n- To get an instance, Mantis provides a factory method:\n\n```swift\nlet cropViewController: CustomViewController = Mantis.cropViewController(image: image, config: config)\n```\n\n\u003c/details\u003e\n    \n### Demo projects\nMantis provide two demo projects\n- MantisExample (using Storyboard)\n- MantisSwiftUIExample (using SwiftUI)\n\n### Showcases\n\nBelow are apps that use the Mantis framework. If your app also uses Mantis and you’d like it to be showcased here, please submit a PR following the existing format.\n\n| \u003ca href=\"https://apps.apple.com/us/app/pictopoem/id6692614035\"\u003e\u003cimg src=\"https://is1-ssl.mzstatic.com/image/thumb/Purple211/v4/65/d9/b7/65d9b774-3b3d-06ae-1972-79156dc53672/AppIcon-0-0-1x_U007emarketing-0-11-0-85-220.png/460x0w.webp\" width=\"100\" alt=\"Pictopoem\"\u003e\u003c/a\u003e\u003cbr/\u003e[**Pictopoem**](https://apps.apple.com/us/app/pictopoem/id6692614035)\u003cbr/\u003eWhere Images Whisper Poems | \u003ca href=\"https://apps.apple.com/us/app/text-behind-me/id6736535053\"\u003e\u003cimg src=\"https://is1-ssl.mzstatic.com/image/thumb/Purple211/v4/f8/f0/20/f8f0201e-8b1d-add5-e08c-76fbf04c7fef/AppIcon-0-0-1x_U007emarketing-0-11-0-85-220.png/460x0w.webp\" width=\"100\" alt=\"Text Behind Me\"\u003e\u003c/a\u003e\u003cbr/\u003e[**Text Behind Me**](https://apps.apple.com/us/app/text-behind-me/id6736535053)\u003cbr/\u003eAdd Depth to Your Photos |\n|---|---|\n\n### Backers \u0026 Sponsors\nBecome a sponsor through [GitHub Sponsors](https://github.com/sponsors/guoyingtao). \n\n## Credits\n* The crop feature is strongly inspired by [TOCropViewController](https://github.com/TimOliver/TOCropViewController) \n* The rotation feature is inspired by [IGRPhotoTweaks](https://github.com/IGRSoft/IGRPhotoTweaks)\n* The rotation dial is inspired by [10clock](https://github.com/joedaniels29/10Clock)\n* Thanks [Leo Dabus](https://stackoverflow.com/users/2303865/leo-dabus) for helping me to solve the problem of cropping an ellipse image with transparent background https://stackoverflow.com/a/59805317/288724\n* \u003cdiv\u003eIcons made by \u003ca href=\"https://www.freepik.com\" title=\"Freepik\"\u003eFreepik\u003c/a\u003e from \u003ca href=\"https://www.flaticon.com/\" title=\"Flaticon\"\u003ewww.flaticon.com\u003c/a\u003e is licensed by \u003ca href=\"http://creativecommons.org/licenses/by/3.0/\" title=\"Creative Commons BY 3.0\" target=\"_blank\"\u003eCC 3.0 BY\u003c/a\u003e\u003c/div\u003e\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguoyingtao%2FMantis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguoyingtao%2FMantis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguoyingtao%2FMantis/lists"}