{"id":28425016,"url":"https://github.com/aaronlab/sweetcardscanner","last_synced_at":"2025-06-28T03:31:03.477Z","repository":{"id":54284324,"uuid":"312756497","full_name":"aaronlab/SweetCardScanner","owner":"aaronlab","description":"Simple \u0026 Fast Credit Card Scanner Library for SwiftUI","archived":false,"fork":false,"pushed_at":"2021-02-26T16:08:13.000Z","size":13534,"stargazers_count":30,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-06-05T10:48:52.701Z","etag":null,"topics":["camera","card-scanner-library","cardscan","cardscanner","creditcard","ios","swift","swiftpm","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aaronlab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-14T06:00:11.000Z","updated_at":"2024-10-29T03:42:29.000Z","dependencies_parsed_at":"2022-08-13T11:00:27.046Z","dependency_job_id":null,"html_url":"https://github.com/aaronlab/SweetCardScanner","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/aaronlab/SweetCardScanner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aaronlab%2FSweetCardScanner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aaronlab%2FSweetCardScanner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aaronlab%2FSweetCardScanner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aaronlab%2FSweetCardScanner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aaronlab","download_url":"https://codeload.github.com/aaronlab/SweetCardScanner/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aaronlab%2FSweetCardScanner/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262371125,"owners_count":23300556,"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":["camera","card-scanner-library","cardscan","cardscanner","creditcard","ios","swift","swiftpm","swiftui"],"created_at":"2025-06-05T10:31:02.399Z","updated_at":"2025-06-28T03:31:03.467Z","avatar_url":"https://github.com/aaronlab.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Language: Swift 5](https://img.shields.io/badge/language-Swift5-orange?style=flat\u0026logo=swift)](https://developer.apple.com/swift)\n![Platform: iOS 13+](https://img.shields.io/badge/platform-iOS%2013%2B-blue?style=flat\u0026logo=apple)\n![SwiftPM compatible](https://img.shields.io/badge/SPM-compatible-brightgreen?style=flat\u0026logo=swift)\n[![License: MIT](https://img.shields.io/badge/license-MIT-lightgrey?style=flat)](https://github.com/aaronLab/SweetCardScanner/blob/main/LICENSE)\n[![Release version](https://img.shields.io/badge/release-v1.0.3-blue)](https://github.com/aaronLab/SweetCardScanner/releases)\n\n# SweetCardScanner\n\nSweetCardScanner is a fast and simple Card Scanner library written in Swift, based on [CreditCardScanner](https://github.com/yhkaplan/credit-card-scanner) and [Reg](https://github.com/yhkaplan/Reg) libraries by [@yhkaplan](https://github.com/yhkaplan) so that users can pay much more easily by capturing their credit/debit card with the rear camera.\n\n\u003ccenter\u003e\n\u003cimg src=\"./preview.gif\" width=\"260\"\u003e\n\u003c/center\u003e\n\n## Requirements\n\n- iOS 13.0+ (due to SwiftUI, Vision Framework)\n  - Tested on iOS 14.1 with iPhone X\n\n## Installation\n\n- In Xcode, add the URL of this repository in SwiftPM:\n\n  ```http\n  https://github.com/aaronLab/SweetCardScanner.git\n  ```\n\n## Usage\n\n1. Add `NSCameraUsageDescription` into `Info.plist` for Camera Useage Description.\n2. `import SweetCardScanner` on top of the `ContentView.swift`.\n3. Now, you can use like `SweetCardScanner()` or `SweetCardScanner(wordsToSkip: Array\u003cString\u003e?, invalidNames: Array\u003cString\u003e?)` inside of the body.\n4. With `wordsToSkip: Array\u003cString\u003e?`, you can add some words \"in lowercase\" to try to skip in recognition to improve the performance like bank names, such as \"td\", \"td banks\", \"cibc\", and so on.\n5. The default value of `wordsToSkip` is `[\"mastercard\", \"jcb\", \"visa\", \"express\", \"bank\", \"card\", \"platinum\", \"reward\"]`\n6. With `invalidNames: Array\u003cString\u003e?`, you can try to add some words \"in lowercase\" for invalid names, such as \"thru\", \"authorized\", \"signature\".\n7. The default value of `invalidNames: Array\u003cString\u003e?` is `[\"expiration\", \"valid\", \"since\", \"from\", \"until\", \"month\", \"year\"]`\n8. Also, you can use completion clousures, such as `.onDismiss`, `.onError`, `.onSuccess` right after `SweetCardScanner()` like below.\n9. If you want to turn off the camera when you move to the result view, you will need to use your own customized navigation status trick. [(Check the example below)](#example)\n\n```Swift\nvar body: some View {\n    /*\n     You can add some words \"in lowercase\" to try to skip in recognition to improve the performance like bank names,\n     such as \"td\", \"td banks\", \"cibc\", and so on.\n     Also you can try to add some words \"in lowercase\" for invalid names, such as \"thru\", \"authorized\", \"signature\".\n     Or you can just simply usw liek \"SweetCardScanner()\"\n     */\n     SweetCardScanner(\n         wordsToSkip: [\"td\", \"td bank\", \"cibc\"],\n         invalidNames: [\"thru\", \"authorized\", \"signature\"]\n     )\n     .onDismiss {\n         // Do something when the view dismissed.\n     }\n     .onError { error in\n         // The 'error' above gives you 'CreditCardScannerError' struct below.\n         print(error)\n     }\n     .onSuccess { card in\n         // The card above gives you 'CreditCard' struct below.\n         print(card)\n     }\n }\n```\n\n## CreditCardScannerError\n\n```Swift\npublic struct CreditCardScannerError: LocalizedError {\n  public enum Kind { case cameraSetup, photoProcessing, authorizationDenied, capture }\n  public var kind: Kind\n  public var underlyingError: Error?\n  public var errorDescription: String? { (underlyingError as? LocalizedError)?.errorDescription }\n}\n```\n\n## CreditCard\n\n```Swift\npublic struct CreditCard {\n  public var number: String?\n  public var name: String?\n  public var expireDate: DateComponents?\n  public var year: Int { expireDate?.year ?? 0 } // This returns \"yyyy\"\n  public var month: Int { expireDate?.month ?? 0 } // This returns \"MM\"\n  /*\n  CardVender below returns an element of an enum:\n  Unknown, Amex, Visa, MasterCard, Diners, Discover, JCB, Elo, Hipercard, UnionPay\n  */\n  public var vendor: CardVendor { CreditCardUtil.getVendor(candidate: self.number) }\n  public var isNotExpired: Bool? { CreditCardUtil.isValid(candidate: self.expireDate) }\n}\n```\n\n## CardVendor\n\n```Swift\npublic enum CardVendor: String {\n    case Unknown, Amex, Visa, MasterCard, Diners, Discover, JCB, Elo, Hipercard, UnionPay\n}\n```\n\n## Example\n\nYou can customize your own view with SweetCardScanner, and SwiftUI like below.\n\n```Swift\n// ContentView.swift\n\nimport SwiftUI\nimport SweetCardScanner\n\nstruct ContentView: View {\n    // MARK: - PROPERTIES\n\n    @State var navigationStatus: NavigationStatus? = .ready\n    @State var card: CreditCard?\n\n    // MARK: - BODY\n\n    var body: some View {\n\n        NavigationView {\n\n            GeometryReader { geometry in\n\n                ZStack {\n\n                    NavigationLink(\n                        destination: ResultView(card: card)\n                            .onDisappear {\n                                /*\n                                 You will be able to turn on the camera again\n                                 when you come back to this view from the result view\n                                 by changing your own customized navigation status.\n                                 */\n                                self.navigationStatus = .ready\n                            },\n                        tag: NavigationStatus.pop,\n                        selection: $navigationStatus) {\n                        EmptyView()\n                    }\n\n                    /*\n                     You will be able to turn off the camera when you move to the result view\n                     with the `if` statement below.\n                     */\n                    if navigationStatus == .ready {\n                        /*\n                         You can add some words \"in lowercase\" to try to skip in recognition to improve the performance like bank names,\n                         such as \"td\", \"td banks\", \"cibc\", and so on.\n                         Also you can try to add some words \"in lowercase\" for invalid names, such as \"thru\", \"authorized\", \"signature\".\n                         Or you can just simply usw liek \"SweetCardScanner()\"\n                         */\n                        SweetCardScanner(\n                            wordsToSkip: [\"td\", \"td bank\", \"cibc\"],\n                            invalidNames: [\"thru\", \"authorized\", \"signature\"]\n                        )\n                        .onError { err in\n                            print(err)\n                        }\n                        .onSuccess { card in\n                            self.card = card\n                            self.navigationStatus = .pop\n                        }\n                    }\n\n                    RoundedRectangle(cornerRadius: 16)\n                        .stroke()\n                        .foregroundColor(.white)\n                        .padding(16)\n                        .frame(width: geometry.size.width, height: geometry.size.width * 0.63, alignment: .center)\n\n                } //: ZSTACK\n\n            } //: GEOMETRY\n\n        } //: NAVIGATION\n\n    }\n}\n\n// MARK: - NavigationStatus\nenum NavigationStatus {\n    case ready, pop\n}\n```\n\n```Swift\n// ResultView.swift\nimport SwiftUI\nimport struct SweetCardScanner.CreditCard\n\nstruct ResultView: View {\n    // MARK: - PROPERTIES\n\n    let card: CreditCard?\n\n    // MARK: - BODY\n\n    var body: some View {\n\n        VStack {\n            Text(\"Card Holder Name: \\(card?.name ?? \"N/A\")\")\n            Text(\"Number: \\(card?.number ?? \"N/A\")\")\n            Text(\"Expire Year: \\(String(card?.year ?? 00))\")\n            Text(\"Expire Month: \\(String(card?.month ?? 00))\")\n            Text(\"Card Vendor: \\(card?.vendor.rawValue ?? \"Unknown\")\")\n\n            if let isNotExpired = card?.isNotExpired {\n                isNotExpired ? Text(\"Expired: Not Expired\") : Text(\"Expired: Expired\")\n            }\n\n        }\n\n    }\n\n}\n```\n\n## License\n\nLicensed under [MIT](https://github.com/aaronLab/SweetCardScanner/blob/main/LICENSE) license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaronlab%2Fsweetcardscanner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faaronlab%2Fsweetcardscanner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaronlab%2Fsweetcardscanner/lists"}