├── .swift-version
├── Tests
├── LinuxMain.swift
└── QRCodeSwiftTests
│ ├── Info.plist
│ └── QRCodeSwiftTests.swift
├── swift_qrcodejs.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
├── xcshareddata
│ └── xcschemes
│ │ └── swift_qrcodejs-Package.xcscheme
└── project.pbxproj
├── .github
└── workflows
│ ├── pod-lint.yml
│ ├── carthage.yml
│ ├── release.yml
│ ├── docs.yml
│ └── spm.yml
├── Example
├── Package.swift
└── main.swift
├── Package.swift
├── .gitignore
├── Sources
├── Info.plist
├── QR8bitByte.swift
├── QRCodeError.swift
├── QRBitBuffer.swift
├── QRMaskPattern.swift
├── QRCodeSwift.h
├── BCH.swift
├── QRErrorCorrectLevel.swift
├── QRMath.swift
├── QRMode.swift
├── QRPatternLocator.swift
├── QRCodeType.swift
├── QRPolynomial.swift
├── QRCode.swift
├── QRRSBlock.swift
└── QRCodeModel.swift
├── LICENSE
├── carthage.sh
├── swift_qrcodejs.podspec
└── README.md
/.swift-version:
--------------------------------------------------------------------------------
1 | 5.0
2 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import QRCodeSwiftTests
3 |
4 | XCTMain([
5 | testCase(QRCodeSwiftTests.allTests),
6 | ])
7 |
--------------------------------------------------------------------------------
/swift_qrcodejs.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/.github/workflows/pod-lint.yml:
--------------------------------------------------------------------------------
1 | name: CocoaPods Lint
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | pod:
7 | runs-on: macos-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | - name: Lint Pod Spec
11 | run: pod lib lint
12 |
--------------------------------------------------------------------------------
/.github/workflows/carthage.yml:
--------------------------------------------------------------------------------
1 | name: Carthage
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | all:
7 | runs-on: macos-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | - name: Build
11 | run: ./carthage.sh build --no-skip-current --verbose
12 |
--------------------------------------------------------------------------------
/swift_qrcodejs.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/swift_qrcodejs.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | release:
5 | types: [ published ]
6 |
7 | jobs:
8 | pod:
9 | runs-on: macos-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 | - name: Publish to CocoaPods Trunk
13 | run: pod trunk push
14 | env:
15 | COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
16 |
--------------------------------------------------------------------------------
/Example/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "QRCodeSwiftCLI",
8 | products: [
9 | .executable(
10 | name: "QRCodeSwiftCLI",
11 | targets: ["QRCodeSwiftCLI"]),
12 | ],
13 | dependencies: [
14 | .package(path: ".."),
15 | ],
16 | targets: [
17 | .target(
18 | name: "QRCodeSwiftCLI",
19 | dependencies: ["QRCodeSwift"],
20 | path: "."),
21 | ]
22 | )
23 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "swift_qrcodejs",
8 | products: [
9 | .library(
10 | name: "QRCodeSwift",
11 | targets: ["QRCodeSwift"]),
12 | ],
13 | targets: [
14 | .target(
15 | name: "QRCodeSwift",
16 | dependencies: [],
17 | path: "Sources/"),
18 | .testTarget(
19 | name: "QRCodeSwiftTests",
20 | dependencies: ["QRCodeSwift"]),
21 | ]
22 | )
23 |
--------------------------------------------------------------------------------
/Tests/QRCodeSwiftTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundleDevelopmentRegion
5 | en
6 | CFBundleExecutable
7 | $(EXECUTABLE_NAME)
8 | CFBundleIdentifier
9 | $(PRODUCT_BUNDLE_IDENTIFIER)
10 | CFBundleInfoDictionaryVersion
11 | 6.0
12 | CFBundleName
13 | $(PRODUCT_NAME)
14 | CFBundlePackageType
15 | BNDL
16 | CFBundleShortVersionString
17 | 1.0
18 | CFBundleSignature
19 | ????
20 | CFBundleVersion
21 | $(CURRENT_PROJECT_VERSION)
22 | NSPrincipalClass
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | .DS_Store
3 |
4 | ## Build generated
5 | build/
6 | DerivedData/
7 |
8 | ## Various settings
9 | *.pbxuser
10 | !default.pbxuser
11 | *.mode1v3
12 | !default.mode1v3
13 | *.mode2v3
14 | !default.mode2v3
15 | *.perspectivev3
16 | !default.perspectivev3
17 | xcuserdata/
18 |
19 | ## Other
20 | *.moved-aside
21 | *.xccheckout
22 | *.xcscmblueprint
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | ## Playgrounds
31 | timeline.xctimeline
32 | playground.xcworkspace
33 |
34 | # Swift Package Manager
35 | Packages/
36 | Package.pins
37 | .build/
38 | .swiftpm/
39 |
40 | # CocoaPods
41 | Pods/
42 |
43 | # Carthage
44 | Carthage/Checkouts
45 | Carthage/Build
46 |
47 | # fastlane
48 | fastlane/report.xml
49 | fastlane/Preview.html
50 | fastlane/screenshots
51 | fastlane/test_output
52 |
53 | # Project Specific
54 | docs/
55 | *.lcov
56 |
--------------------------------------------------------------------------------
/Sources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 2.2.2
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/.github/workflows/docs.yml:
--------------------------------------------------------------------------------
1 | name: Documentation
2 |
3 | on:
4 | release:
5 | types: [ published ]
6 |
7 | jobs:
8 | jazzy:
9 | runs-on: macos-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 | - name: Install Jazzy
13 | run: sudo gem install jazzy
14 | - name: Generate Documentation
15 | run: jazzy --clean --author ${{ github.repository_owner }} --author_url https://${{ github.repository_owner }}.github.io --github_url https://github.com/${{ github.repository }} --github-file-prefix https://github.com/${{ github.repository }}/tree/${{ github.event.release.tag_name }} --module-version ${{ github.event.release.tag_name }} --swift-build-tool spm --module QRCodeSwift --root-url https://${{ github.repository_owner }}.github.io/swift_qrcodejs/ --dash_url https://${{ github.repository_owner }}.github.io/swift_qrcodejs/docsets/QRCodeSwift.xml
16 | - name: Publish
17 | uses: peaceiris/actions-gh-pages@v3
18 | with:
19 | github_token: ${{ secrets.GITHUB_TOKEN }}
20 | publish_dir: ./docs
21 |
--------------------------------------------------------------------------------
/.github/workflows/spm.yml:
--------------------------------------------------------------------------------
1 | name: Swift Package Manager
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | macos:
7 | runs-on: macos-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | - name: Build
11 | run: swift build -v
12 | - name: Run tests
13 | run: swift test -v --enable-code-coverage --parallel
14 | - name: Prepare Codecov
15 | run: xcrun llvm-cov export -format="lcov" .build/debug/swift_qrcodejsPackageTests.xctest/Contents/MacOS/swift_qrcodejsPackageTests -instr-profile .build/debug/codecov/default.profdata > codecov.lcov
16 | - name: Codecov
17 | uses: codecov/codecov-action@v1
18 | with:
19 | file: codecov.lcov
20 |
21 | linux:
22 | runs-on: ubuntu-latest
23 | strategy:
24 | matrix:
25 | swift-version: [latest, 5.3, 5.2, 5.1, '5.0']
26 | container:
27 | image: swift:${{ matrix.swift-version }}
28 | steps:
29 | - uses: actions/checkout@v2
30 | - name: Build
31 | run: swift build -v
32 | - name: Run tests
33 | run: swift test -v --enable-test-discovery || swift test -v
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-2020 Zhiyu Zhu/朱智语/ApolloZhu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/carthage.sh:
--------------------------------------------------------------------------------
1 | # carthage.sh
2 | # Usage example: ./carthage.sh build --platform iOS
3 | # Why? https://github.com/Carthage/Carthage/blob/master/Documentation/Xcode12Workaround.md
4 |
5 | set -euo pipefail
6 |
7 | xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX)
8 | trap 'rm -f "$xcconfig"' INT TERM HUP EXIT
9 |
10 | # For Xcode 12 make sure EXCLUDED_ARCHS is set to arm architectures otherwise
11 | # the build will fail on lipo due to duplicate architectures.
12 |
13 | CURRENT_XCODE_VERSION=$(xcodebuild -version | grep "Build version" | cut -d' ' -f3)
14 | echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200__BUILD_$CURRENT_XCODE_VERSION = arm64 arm64e armv7 armv7s armv6 armv8" >> $xcconfig
15 |
16 | echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200 = $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200__BUILD_$(XCODE_PRODUCT_BUILD_VERSION))' >> $xcconfig
17 | echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig
18 |
19 | export XCODE_XCCONFIG_FILE="$xcconfig"
20 | carthage "$@"
21 |
--------------------------------------------------------------------------------
/Sources/QR8bitByte.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 | Copyright (c) 2017 EyreFree
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | import Foundation
26 |
27 | struct QR8bitByte {
28 | let mode: QRMode = .bitByte8
29 | let parsedData: Data
30 |
31 | var count: Int {
32 | return parsedData.count
33 | }
34 |
35 | func write(to buffer: inout QRBitBuffer) {
36 | for datium in parsedData {
37 | buffer.put(UInt(datium), length: 8)
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/swift_qrcodejs.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "swift_qrcodejs"
4 | s.module_name = "QRCodeSwift"
5 | s.version = "2.2.2"
6 | s.summary = "Cross-appleOS SIMPLE QRCode generator for swift, modified based on qrcodejs."
7 |
8 | # This description is used to generate tags and improve search results.
9 | # * Think: What does it do? Why did you write it? What is the focus?
10 | # * Try to keep it short, snappy and to the point.
11 | # * Write the description between the DESC delimiters below.
12 | # * Finally, don't worry about the indent, CocoaPods strips it!
13 | s.description = <<-DESC
14 | No CIFilter on watchOS? Then we generate QRCode without it ourselves!
15 | swift_qrcodejs is a cross-appleOS simple QRCode generator for swift, modified based on qrcodejs.
16 | DESC
17 |
18 | s.homepage = "https://github.com/ApolloZhu/swift_qrcodejs"
19 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
20 |
21 | s.license = { :type => "MIT", :file => "LICENSE" }
22 |
23 | # s.author = { "Apollo Zhu" => "public-apollonian@outlook.com" }
24 | # Or just: s.author = "ApolloZhu"
25 | s.authors = { "ApolloZhu" => "public-apollonian@outlook.com" }
26 | s.social_media_url = "http://github.com/ApolloZhu"
27 |
28 | s.ios.deployment_target = "9.0"
29 | s.osx.deployment_target = "10.9"
30 | s.watchos.deployment_target = "2.0"
31 | s.tvos.deployment_target = "9.0"
32 |
33 | s.source = { :git => "https://github.com/ApolloZhu/swift_qrcodejs.git", :tag => s.version }
34 |
35 | s.source_files = "Sources/**/*.{h,swift}"
36 | s.swift_versions = ['4.2', '5.0']
37 |
38 | s.frameworks = "Foundation"
39 |
40 | end
41 |
--------------------------------------------------------------------------------
/Example/main.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2017-2020 ApolloZhu
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | import QRCodeSwift
24 | import Foundation
25 |
26 | let args = ProcessInfo.processInfo.arguments
27 | let ENV = ProcessInfo.processInfo.environment
28 |
29 | let link: String
30 | if args.count > 1 {
31 | link = args.last!
32 | } else {
33 | var input: String?
34 | print("Generate QRCode for", terminator: ": ")
35 | repeat { input = readLine() } while (input == nil)
36 | link = input!
37 | }
38 | let qr = try QRCode(link)
39 |
40 | let background, foreground: String
41 | if ENV.keys.contains("__XCODE_BUILT_PRODUCTS_DIR_PATHS") {
42 | background = " "
43 | foreground = "MM"
44 | } else {
45 | background = "\u{1B}[7m "
46 | foreground = "\u{1B}[0m "
47 | }
48 |
49 | print(qr.toString(filledWith: background, patchedWith: foreground))
50 |
--------------------------------------------------------------------------------
/Sources/QRCodeError.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2017-2020 ApolloZhu
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | /// All possible errors that could occur when constructing `QRCode`.
24 | public enum QRCodeError: Error {
25 | /// The thing you want to save is too large for `QRCode`.
26 | case dataLengthExceedsCapacityLimit
27 | /// Can not encode the given string using the specified encoding.
28 | case text(String, incompatibleWithEncoding: String.Encoding)
29 | /// Fill a new issue on GitHub, or submit a pull request.
30 | case internalError(ImplmentationError)
31 |
32 | /// Should probably contact developer is you ever see any of these.
33 | public enum ImplmentationError {
34 | /// fail to determine how large is the data.
35 | case dataLengthIndeterminable
36 | /// fail to find appropriate container for your data.
37 | case dataLength(Int, exceedsCapacityLimit: Int)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/QRBitBuffer.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | */
23 |
24 | struct QRBitBuffer {
25 | var buffer = [UInt]()
26 | private(set) var bitCount = 0
27 |
28 | func get(index: Int) -> Bool {
29 | let bufIndex = index / 8
30 | return ((buffer[bufIndex] >> (7 - index % 8)) & 1) == 1
31 | }
32 |
33 | subscript(index: Int) -> Bool {
34 | return get(index: index)
35 | }
36 |
37 | mutating func put(_ num: UInt, length: Int) {
38 | for i in 0..> (length - i - 1)) & 1) == 1)
40 | }
41 | }
42 |
43 | mutating func put(_ bit: Bool) {
44 | let bufIndex = bitCount / 8
45 | if buffer.count <= bufIndex {
46 | buffer.append(0)
47 | }
48 | if bit {
49 | buffer[bufIndex] |= (UInt(0x80) >> (bitCount % 8))
50 | }
51 | bitCount += 1
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Sources/QRMaskPattern.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 | Copyright (c) 2017 EyreFree
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | enum QRMaskPattern: Int {
26 | case _000, _001, _010, _011, _100, _101, _110, _111
27 | }
28 |
29 | extension QRMaskPattern {
30 | func getMask(_ i: Int, _ j: Int) -> Bool {
31 | switch self {
32 | case ._000:
33 | return (i + j) % 2 == 0
34 | case ._001:
35 | return i % 2 == 0
36 | case ._010:
37 | return j % 3 == 0
38 | case ._011:
39 | return (i + j) % 3 == 0
40 | case ._100:
41 | return (i / 2 + j / 3) % 2 == 0
42 | case ._101:
43 | return (i * j) % 2 + (i * j) % 3 == 0
44 | case ._110:
45 | return ((i * j) % 2 + (i * j) % 3) % 2 == 0
46 | case ._111:
47 | return ((i * j) % 3 + (i + j) % 2) % 2 == 0
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Sources/QRCodeSwift.h:
--------------------------------------------------------------------------------
1 | /*
2 | MIT License
3 |
4 | Copyright (c) 2017-2020 ApolloZhu
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | //---------------------------------------------------------------------
26 | // QRCode for JavaScript
27 | //
28 | // Copyright (c) 2009 Kazuhiko Arase
29 | //
30 | // URL: http://www.d-project.com/
31 | //
32 | // Licensed under the MIT license:
33 | // http://www.opensource.org/licenses/mit-license.php
34 | //
35 | // The word "QR Code" is registered trademark of
36 | // DENSO WAVE INCORPORATED
37 | // http://www.denso-wave.com/qrcode/faqpatent-e.html
38 | //
39 | //---------------------------------------------------------------------
40 |
41 | //
42 | // swift_qrcodejs.h
43 | // swift_qrcodejs
44 | //
45 | // Created by Apollo Zhu on 10/1/17.
46 | //
47 |
48 | #import
49 |
50 | //! Project version number for QRCodeSwift.
51 | FOUNDATION_EXPORT double QRCodeSwift_VersionNumber;
52 |
53 | //! Project version string for QRCodeSwift.
54 | FOUNDATION_EXPORT const unsigned char QRCodeSwift_VersionString[];
55 |
--------------------------------------------------------------------------------
/Sources/BCH.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | */
23 |
24 | enum BCH {
25 | private static let g15 = 0b10100110111
26 | private static let g18 = 0b1111100100101
27 | private static let g15Mask = 0b101010000010010
28 | private static let g15Digit = digit(of: g15)
29 | private static let g18Digit = digit(of: g18)
30 |
31 | static func typeInfo(of data: Int) -> Int {
32 | var d = data << 10
33 | while digit(of: d) - g15Digit >= 0 {
34 | d ^= (g15 << (digit(of: d) - g15Digit))
35 | }
36 | return ((data << 10) | d) ^ g15Mask
37 | }
38 |
39 | static func typeNumber(of data: Int) -> Int {
40 | var d = data << 12
41 | while digit(of: d) - g18Digit >= 0 {
42 | d ^= (g18 << (digit(of: d) - g18Digit))
43 | }
44 | return (data << 12) | d
45 | }
46 |
47 | private static func digit(of data: Int) -> Int {
48 | var digit = 0
49 | var data = UInt(data) // unsigned shift
50 | while data != 0 {
51 | digit += 1
52 | data >>= 1
53 | }
54 | return digit
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Sources/QRErrorCorrectLevel.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | */
23 |
24 | /// Error resilience level.
25 | ///
26 | /// - Note: higher the level, larger the size.
27 | public enum QRErrorCorrectLevel: CaseIterable {
28 | /// Error resilience level: 7%.
29 | case L
30 | /// Error resilience level: 15%.
31 | case M
32 | /// Error resilience level: 25%.
33 | case Q
34 | /// Error resilience level: 30%.
35 | case H
36 | }
37 |
38 | extension QRErrorCorrectLevel {
39 | var pattern: Int {
40 | switch self {
41 | case .L: return 1
42 | case .M: return 0
43 | case .Q: return 3
44 | case .H: return 2
45 | }
46 | }
47 |
48 | var offset: Int {
49 | switch self {
50 | case .L: return 0
51 | case .M: return 1
52 | case .Q: return 2
53 | case .H: return 3
54 | }
55 | }
56 | }
57 |
58 | #if canImport(CoreImage)
59 | extension QRErrorCorrectLevel {
60 | /// Input value for CIFilter.
61 | public var ciQRCodeGeneratorInputCorrectionLevel: String {
62 | switch self {
63 | case .L: return "l"
64 | case .M: return "m"
65 | case .Q: return "q"
66 | case .H: return "h"
67 | }
68 | }
69 | }
70 | #endif
71 |
--------------------------------------------------------------------------------
/Sources/QRMath.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 | Copyright (c) 2017 EyreFree
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | struct QRMath {
26 | /// glog
27 | ///
28 | /// - Parameter n: n | n >= 1.
29 | /// - Returns: glog(n), or a fatal error if n < 1.
30 | static func glog(_ n: Int) -> Int {
31 | precondition(n > 0, "glog only works with n > 0, not \(n)")
32 | return QRMath.instance.LOG_TABLE[n]
33 | }
34 |
35 | static func gexp(_ n: Int) -> Int {
36 | var n = n
37 | while n < 0 {
38 | n += 255
39 | }
40 | while n >= 256 {
41 | n -= 255
42 | }
43 | return QRMath.instance.EXP_TABLE[n]
44 | }
45 |
46 | private var EXP_TABLE: [Int]
47 | private var LOG_TABLE: [Int]
48 |
49 | private static let instance = QRMath()
50 | private init() {
51 | EXP_TABLE = [Int](repeating: 0, count: 256)
52 | LOG_TABLE = [Int](repeating: 0, count: 256)
53 | for i in 0..<8 {
54 | EXP_TABLE[i] = 1 << i
55 | }
56 | for i in 8..<256 {
57 | EXP_TABLE[i] = EXP_TABLE[i - 4] ^ EXP_TABLE[i - 5] ^ EXP_TABLE[i - 6] ^ EXP_TABLE[i - 8]
58 | }
59 | for i in 0..<255 {
60 | LOG_TABLE[EXP_TABLE[i]] = i
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Sources/QRMode.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 | Copyright (c) 2017 EyreFree
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | /// OptionSet
26 | enum QRMode: UInt {
27 | /// 1 << 0
28 | case number = 0b0001
29 | /// 1 << 1
30 | case alphaNumber = 0b0010
31 | /// 1 << 2
32 | case bitByte8 = 0b0100
33 | /// 1 << 3
34 | case kanji = 0b1000
35 | }
36 |
37 | extension QRMode {
38 | func bitCount(ofType type: Int) -> Int? {
39 | if 1 <= type && type < 10 {
40 | switch self {
41 | case .number:
42 | return 10
43 | case .alphaNumber:
44 | return 9
45 | case .bitByte8, .kanji:
46 | return 8
47 | }
48 | } else if type < 27 {
49 | switch self {
50 | case .number:
51 | return 12
52 | case .alphaNumber:
53 | return 11
54 | case .bitByte8:
55 | return 16
56 | case .kanji:
57 | return 10
58 | }
59 | } else if type < 41 {
60 | switch self {
61 | case .number:
62 | return 14
63 | case .alphaNumber:
64 | return 13
65 | case .bitByte8:
66 | return 16
67 | case .kanji:
68 | return 12
69 | }
70 | } else {
71 | return nil
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/swift_qrcodejs.xcodeproj/xcshareddata/xcschemes/swift_qrcodejs-Package.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
54 |
55 |
61 |
62 |
64 |
65 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/Sources/QRPatternLocator.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | */
23 |
24 | struct QRPatternLocator {
25 | private static let PATTERN_POSITION_TABLE: [[Int]] = [
26 | [],
27 | [6, 18],
28 | [6, 22],
29 | [6, 26],
30 | [6, 30],
31 | [6, 34],
32 | [6, 22, 38],
33 | [6, 24, 42],
34 | [6, 26, 46],
35 | [6, 28, 50],
36 | [6, 30, 54],
37 | [6, 32, 58],
38 | [6, 34, 62],
39 | [6, 26, 46, 66],
40 | [6, 26, 48, 70],
41 | [6, 26, 50, 74],
42 | [6, 30, 54, 78],
43 | [6, 30, 56, 82],
44 | [6, 30, 58, 86],
45 | [6, 34, 62, 90],
46 | [6, 28, 50, 72, 94],
47 | [6, 26, 50, 74, 98],
48 | [6, 30, 54, 78, 102],
49 | [6, 28, 54, 80, 106],
50 | [6, 32, 58, 84, 110],
51 | [6, 30, 58, 86, 114],
52 | [6, 34, 62, 90, 118],
53 | [6, 26, 50, 74, 98, 122],
54 | [6, 30, 54, 78, 102, 126],
55 | [6, 26, 52, 78, 104, 130],
56 | [6, 30, 56, 82, 108, 134],
57 | [6, 34, 60, 86, 112, 138],
58 | [6, 30, 58, 86, 114, 142],
59 | [6, 34, 62, 90, 118, 146],
60 | [6, 30, 54, 78, 102, 126, 150],
61 | [6, 24, 50, 76, 102, 128, 154],
62 | [6, 28, 54, 80, 106, 132, 158],
63 | [6, 32, 58, 84, 110, 136, 162],
64 | [6, 26, 54, 82, 110, 138, 166],
65 | [6, 30, 58, 86, 114, 142, 170]
66 | ]
67 |
68 | #if swift(<5.1)
69 | static func getPatternPosition(ofType typeNumber: Int) -> [Int] {
70 | return PATTERN_POSITION_TABLE[typeNumber - 1]
71 | }
72 | #else
73 | static subscript(typeNumber: Int) -> [Int] {
74 | return PATTERN_POSITION_TABLE[typeNumber - 1]
75 | }
76 | #endif
77 | }
78 |
--------------------------------------------------------------------------------
/Sources/QRCodeType.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | */
23 |
24 | struct QRCodeType {
25 | static let QRCodeLimitLength: [[Int]] = [
26 | [17, 14, 11, 7],
27 | [32, 26, 20, 14],
28 | [53, 42, 32, 24],
29 | [78, 62, 46, 34],
30 | [106, 84, 60, 44],
31 | [134, 106, 74, 58],
32 | [154, 122, 86, 64],
33 | [192, 152, 108, 84],
34 | [230, 180, 130, 98],
35 | [271, 213, 151, 119],
36 | [321, 251, 177, 137],
37 | [367, 287, 203, 155],
38 | [425, 331, 241, 177],
39 | [458, 362, 258, 194],
40 | [520, 412, 292, 220],
41 | [586, 450, 322, 250],
42 | [644, 504, 364, 280],
43 | [718, 560, 394, 310],
44 | [792, 624, 442, 338],
45 | [858, 666, 482, 382],
46 | [929, 711, 509, 403],
47 | [1003, 779, 565, 439],
48 | [1091, 857, 611, 461],
49 | [1171, 911, 661, 511],
50 | [1273, 997, 715, 535],
51 | [1367, 1059, 751, 593],
52 | [1465, 1125, 805, 625],
53 | [1528, 1190, 868, 658],
54 | [1628, 1264, 908, 698],
55 | [1732, 1370, 982, 742],
56 | [1840, 1452, 1030, 790],
57 | [1952, 1538, 1112, 842],
58 | [2068, 1628, 1168, 898],
59 | [2188, 1722, 1228, 958],
60 | [2303, 1809, 1283, 983],
61 | [2431, 1911, 1351, 1051],
62 | [2563, 1989, 1423, 1093],
63 | [2699, 2099, 1499, 1139],
64 | [2809, 2213, 1579, 1219],
65 | [2953, 2331, 1663, 1273]
66 | ]
67 | }
68 |
69 | extension QRCodeType {
70 | /// Get the type by string length
71 | static func typeNumber(forLength length: Int,
72 | errorCorrectLevel: QRErrorCorrectLevel
73 | ) throws -> Int {
74 | for i in QRCodeLimitLength.indices {
75 | if length <= QRCodeLimitLength[i][errorCorrectLevel.offset] {
76 | return i + 1
77 | }
78 | }
79 |
80 | throw QRCodeError.dataLengthExceedsCapacityLimit
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Sources/QRPolynomial.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 | Copyright (c) 2017 EyreFree
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | struct QRPolynomial {
26 | private var numbers: [Int]
27 |
28 | init(_ nums: Int..., shift: Int = 0) {
29 | self.init(nums, shift: shift)
30 | }
31 |
32 | init(_ nums: [Int], shift: Int = 0) {
33 | precondition(!nums.isEmpty, "polynomial should have at least 1 term")
34 | var offset = 0
35 | while offset < nums.count && nums[offset] == 0 {
36 | offset += 1
37 | }
38 | self.numbers = [Int](repeating: 0, count: nums.count - offset + shift)
39 | for i in 0.. Int {
45 | return numbers[index]
46 | }
47 |
48 | var count: Int {
49 | return numbers.count
50 | }
51 |
52 | func multiplying(_ e: QRPolynomial) -> QRPolynomial {
53 | var nums = [Int](repeating: 0, count: count + e.count - 1)
54 | for i in 0.. QRPolynomial {
63 | if count - e.count < 0 {
64 | return self
65 | }
66 | let ratio = QRMath.glog(self[0]) - QRMath.glog(e[0])
67 | var num = [Int](repeating: 0, count: count)
68 | for i in 0.. QRPolynomial {
78 | var a = QRPolynomial(1)
79 | for i in 0..
19 | Swift Package Manager
20 |
21 |
22 | with Xcode
23 |
24 | More details in the [Official Guide](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app),
25 | but in general:
26 |
27 | 1. Select in the menu bar of Xcode: `File` > `Swift Packages` > `Add Package Dependency`
28 | 2. Enter https://github.com/ApolloZhu/swift_qrcodejs.git
29 | 2. Next, specify the version resolving rule as "Up to Next Major"
30 | 3. Finish with choosing `QRCodeSwift` library and add it to your app target.
31 |
32 |
33 |
34 |
35 | with Package.swift
36 |
37 | ```swift
38 | dependencies: [
39 | .package(url: "https://github.com/ApolloZhu/swift_qrcodejs.git", from: "2.2.2"),
40 | ]
41 | ```
42 |
43 | ... then add `QRCodeSwift` module/target from package `swift_qrcodejs` as your dependency.
44 |
45 |
46 |
47 |
48 |
49 |
50 | CocoaPods
51 |
52 | ```ruby
53 | pod 'swift_qrcodejs', '~> 2.2.2'
54 | ```
55 |
56 |
57 |
58 |
59 | Carthage
60 |
61 | I assume you know what you are doing (because I don't), but you probably need something like this:
62 |
63 | ```ruby
64 | github "ApolloZhu/swift_qrcodejs" ~> 2.2.2
65 | ```
66 |
67 | Note that [Carthage doesn't work with Xcode 12](https://github.com/Carthage/Carthage/issues/3019)
68 | (but here's a [workaround](https://github.com/Carthage/Carthage/blob/master/Documentation/Xcode12Workaround.md)).
69 |
70 |
71 |
72 |
73 | Manually
74 |
75 | Add all the `.swift` files from the `Sources` folder into your project.
76 |
77 |
78 |
79 | ## Usage
80 |
81 | ```swift
82 | import QRCodeSwift
83 |
84 | guard let qrCode = try? QRCode("Hello World!") else {
85 | fatalError("Failed to generate QRCode")
86 | }
87 | print(qrCode.toString(filledWith: "##", patchedWith: " "))
88 | ```
89 |
90 | For more, checkout the [documentation](https://apollozhu.github.io/swift_qrcodejs).
91 |
92 | ## Example Projects
93 |
94 | - [QRCodeSwiftCLI](./Example/main.swift): lightweight command line tool to generate QRCodes.
95 | - [EFQRCode](https://github.com/EyreFree/EFQRCode): popular Swift framework that generates stylized QRCode images.
96 | - [Apple Watch Bilibili](https://github.com/ApolloZhu/Apple-Watch-Bilibili): login onto bilibili with QRCode.
97 |
98 | ## License
99 |
100 | MIT License. Modified based on [qrcodejs](https://github.com/davidshimjs/qrcodejs).
101 | See [LICENSE](./LICENSE) and each individual file header for more information.
102 |
--------------------------------------------------------------------------------
/Sources/QRCode.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2017-2020 ApolloZhu
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | import Foundation
24 |
25 | /// QRCode abstraction and generator.
26 | open class QRCode {
27 | /// Error correct level.
28 | public let correctLevel: QRErrorCorrectLevel
29 | /// If the image codes has a border around its content.
30 | public let hasBorder: Bool
31 | private let model: QRCodeModel
32 |
33 | /// Construct a QRCode instance.
34 | /// - Parameters:
35 | /// - text: content of the QRCode.
36 | /// - encoding: encoding used for generating data from text.
37 | /// - errorCorrectLevel: error correct level, defaults to high.
38 | /// - hasBorder: if the image codes has a border around, defaults and suggests to be true.
39 | /// - Throws: see `QRCodeError`
40 | /// - Warning: Is computationally intensive.
41 | public convenience init(
42 | _ text: String,
43 | encoding: String.Encoding = .utf8,
44 | errorCorrectLevel: QRErrorCorrectLevel = .H,
45 | withBorder hasBorder: Bool = true
46 | ) throws {
47 | guard let data = text.data(using: encoding) else {
48 | throw QRCodeError.text(text, incompatibleWithEncoding: encoding)
49 | }
50 | try self.init(data, errorCorrectLevel: errorCorrectLevel,
51 | withBorder: hasBorder)
52 | }
53 |
54 | /// Construct a QRCode instance.
55 | /// - Parameters:
56 | /// - data: raw content of the QRCode.
57 | /// - errorCorrectLevel: error correct level, defaults to high.
58 | /// - hasBorder: if the image codes has a border around, defaults and suggests to be true.
59 | /// - Throws: see `QRCodeError`
60 | public init(
61 | _ data: Data,
62 | errorCorrectLevel: QRErrorCorrectLevel = .H,
63 | withBorder hasBorder: Bool = true
64 | ) throws {
65 | self.model = try QRCodeModel(data: data,
66 | errorCorrectLevel: errorCorrectLevel)
67 | self.correctLevel = errorCorrectLevel
68 | self.hasBorder = hasBorder
69 | }
70 |
71 | /// QRCode in binary form.
72 | open private(set) lazy var imageCodes: [[Bool]] = {
73 | if hasBorder {
74 | let line = [[Bool](repeating: false, count: model.moduleCount + 2)]
75 | return line + (0.. String {
97 | return String(imageCodes.reduce("") { $0 +
98 | "\($1.reduce("") { "\($0)\($1 ? black : white)" })\n"
99 | }.dropLast())
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/Sources/QRRSBlock.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | */
23 |
24 | struct QRRSBlock {
25 | let totalCount: Int
26 | let dataCount: Int
27 | }
28 |
29 | extension QRRSBlock {
30 | fileprivate static let RS_BLOCK_TABLE: [[Int]] = [
31 | [1, 26, 19],
32 | [1, 26, 16],
33 | [1, 26, 13],
34 | [1, 26, 9],
35 | [1, 44, 34],
36 | [1, 44, 28],
37 | [1, 44, 22],
38 | [1, 44, 16],
39 | [1, 70, 55],
40 | [1, 70, 44],
41 | [2, 35, 17],
42 | [2, 35, 13],
43 | [1, 100, 80],
44 | [2, 50, 32],
45 | [2, 50, 24],
46 | [4, 25, 9],
47 | [1, 134, 108],
48 | [2, 67, 43],
49 | [2, 33, 15, 2, 34, 16],
50 | [2, 33, 11, 2, 34, 12],
51 | [2, 86, 68],
52 | [4, 43, 27],
53 | [4, 43, 19],
54 | [4, 43, 15],
55 | [2, 98, 78],
56 | [4, 49, 31],
57 | [2, 32, 14, 4, 33, 15],
58 | [4, 39, 13, 1, 40, 14],
59 | [2, 121, 97],
60 | [2, 60, 38, 2, 61, 39],
61 | [4, 40, 18, 2, 41, 19],
62 | [4, 40, 14, 2, 41, 15],
63 | [2, 146, 116],
64 | [3, 58, 36, 2, 59, 37],
65 | [4, 36, 16, 4, 37, 17],
66 | [4, 36, 12, 4, 37, 13],
67 | [2, 86, 68, 2, 87, 69],
68 | [4, 69, 43, 1, 70, 44],
69 | [6, 43, 19, 2, 44, 20],
70 | [6, 43, 15, 2, 44, 16],
71 | [4, 101, 81],
72 | [1, 80, 50, 4, 81, 51],
73 | [4, 50, 22, 4, 51, 23],
74 | [3, 36, 12, 8, 37, 13],
75 | [2, 116, 92, 2, 117, 93],
76 | [6, 58, 36, 2, 59, 37],
77 | [4, 46, 20, 6, 47, 21],
78 | [7, 42, 14, 4, 43, 15],
79 | [4, 133, 107],
80 | [8, 59, 37, 1, 60, 38],
81 | [8, 44, 20, 4, 45, 21],
82 | [12, 33, 11, 4, 34, 12],
83 | [3, 145, 115, 1, 146, 116],
84 | [4, 64, 40, 5, 65, 41],
85 | [11, 36, 16, 5, 37, 17],
86 | [11, 36, 12, 5, 37, 13],
87 | [5, 109, 87, 1, 110, 88],
88 | [5, 65, 41, 5, 66, 42],
89 | [5, 54, 24, 7, 55, 25],
90 | [11, 36, 12, 7, 37, 13],
91 | [5, 122, 98, 1, 123, 99],
92 | [7, 73, 45, 3, 74, 46],
93 | [15, 43, 19, 2, 44, 20],
94 | [3, 45, 15, 13, 46, 16],
95 | [1, 135, 107, 5, 136, 108],
96 | [10, 74, 46, 1, 75, 47],
97 | [1, 50, 22, 15, 51, 23],
98 | [2, 42, 14, 17, 43, 15],
99 | [5, 150, 120, 1, 151, 121],
100 | [9, 69, 43, 4, 70, 44],
101 | [17, 50, 22, 1, 51, 23],
102 | [2, 42, 14, 19, 43, 15],
103 | [3, 141, 113, 4, 142, 114],
104 | [3, 70, 44, 11, 71, 45],
105 | [17, 47, 21, 4, 48, 22],
106 | [9, 39, 13, 16, 40, 14],
107 | [3, 135, 107, 5, 136, 108],
108 | [3, 67, 41, 13, 68, 42],
109 | [15, 54, 24, 5, 55, 25],
110 | [15, 43, 15, 10, 44, 16],
111 | [4, 144, 116, 4, 145, 117],
112 | [17, 68, 42],
113 | [17, 50, 22, 6, 51, 23],
114 | [19, 46, 16, 6, 47, 17],
115 | [2, 139, 111, 7, 140, 112],
116 | [17, 74, 46],
117 | [7, 54, 24, 16, 55, 25],
118 | [34, 37, 13],
119 | [4, 151, 121, 5, 152, 122],
120 | [4, 75, 47, 14, 76, 48],
121 | [11, 54, 24, 14, 55, 25],
122 | [16, 45, 15, 14, 46, 16],
123 | [6, 147, 117, 4, 148, 118],
124 | [6, 73, 45, 14, 74, 46],
125 | [11, 54, 24, 16, 55, 25],
126 | [30, 46, 16, 2, 47, 17],
127 | [8, 132, 106, 4, 133, 107],
128 | [8, 75, 47, 13, 76, 48],
129 | [7, 54, 24, 22, 55, 25],
130 | [22, 45, 15, 13, 46, 16],
131 | [10, 142, 114, 2, 143, 115],
132 | [19, 74, 46, 4, 75, 47],
133 | [28, 50, 22, 6, 51, 23],
134 | [33, 46, 16, 4, 47, 17],
135 | [8, 152, 122, 4, 153, 123],
136 | [22, 73, 45, 3, 74, 46],
137 | [8, 53, 23, 26, 54, 24],
138 | [12, 45, 15, 28, 46, 16],
139 | [3, 147, 117, 10, 148, 118],
140 | [3, 73, 45, 23, 74, 46],
141 | [4, 54, 24, 31, 55, 25],
142 | [11, 45, 15, 31, 46, 16],
143 | [7, 146, 116, 7, 147, 117],
144 | [21, 73, 45, 7, 74, 46],
145 | [1, 53, 23, 37, 54, 24],
146 | [19, 45, 15, 26, 46, 16],
147 | [5, 145, 115, 10, 146, 116],
148 | [19, 75, 47, 10, 76, 48],
149 | [15, 54, 24, 25, 55, 25],
150 | [23, 45, 15, 25, 46, 16],
151 | [13, 145, 115, 3, 146, 116],
152 | [2, 74, 46, 29, 75, 47],
153 | [42, 54, 24, 1, 55, 25],
154 | [23, 45, 15, 28, 46, 16],
155 | [17, 145, 115],
156 | [10, 74, 46, 23, 75, 47],
157 | [10, 54, 24, 35, 55, 25],
158 | [19, 45, 15, 35, 46, 16],
159 | [17, 145, 115, 1, 146, 116],
160 | [14, 74, 46, 21, 75, 47],
161 | [29, 54, 24, 19, 55, 25],
162 | [11, 45, 15, 46, 46, 16],
163 | [13, 145, 115, 6, 146, 116],
164 | [14, 74, 46, 23, 75, 47],
165 | [44, 54, 24, 7, 55, 25],
166 | [59, 46, 16, 1, 47, 17],
167 | [12, 151, 121, 7, 152, 122],
168 | [12, 75, 47, 26, 76, 48],
169 | [39, 54, 24, 14, 55, 25],
170 | [22, 45, 15, 41, 46, 16],
171 | [6, 151, 121, 14, 152, 122],
172 | [6, 75, 47, 34, 76, 48],
173 | [46, 54, 24, 10, 55, 25],
174 | [2, 45, 15, 64, 46, 16],
175 | [17, 152, 122, 4, 153, 123],
176 | [29, 74, 46, 14, 75, 47],
177 | [49, 54, 24, 10, 55, 25],
178 | [24, 45, 15, 46, 46, 16],
179 | [4, 152, 122, 18, 153, 123],
180 | [13, 74, 46, 32, 75, 47],
181 | [48, 54, 24, 14, 55, 25],
182 | [42, 45, 15, 32, 46, 16],
183 | [20, 147, 117, 4, 148, 118],
184 | [40, 75, 47, 7, 76, 48],
185 | [43, 54, 24, 22, 55, 25],
186 | [10, 45, 15, 67, 46, 16],
187 | [19, 148, 118, 6, 149, 119],
188 | [18, 75, 47, 31, 76, 48],
189 | [34, 54, 24, 34, 55, 25],
190 | [20, 45, 15, 61, 46, 16]
191 | ]
192 | }
193 |
194 | extension QRErrorCorrectLevel {
195 | func getRSBlocks(ofType typeNumber: Int) -> [QRRSBlock] {
196 | let rsBlock = getRsBlockTable(ofType: typeNumber)
197 | let length = rsBlock.count / 3
198 |
199 | return (0.. [QRRSBlock] in
200 | let count = rsBlock[i * 3 + 0]
201 | let totalCount = rsBlock[i * 3 + 1]
202 | let dataCount = rsBlock[i * 3 + 2]
203 | let block = QRRSBlock(totalCount: totalCount, dataCount: dataCount)
204 | return [QRRSBlock](repeating: block, count: count)
205 | }
206 | }
207 |
208 | private func getRsBlockTable(ofType typeNumber: Int) -> [Int] {
209 | return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + offset]
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/Sources/QRCodeModel.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012 davidshimjs
3 | Copyright (c) 2017-2020 ApolloZhu
4 | Copyright (c) 2017 EyreFree
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | import Foundation
26 |
27 | struct QRCodeModel {
28 | let typeNumber: Int
29 | let errorCorrectLevel: QRErrorCorrectLevel
30 | private var modules: [[Bool?]]! = nil
31 | private(set) var moduleCount = 0
32 | private let encodedText: QR8bitByte
33 | private var dataCache: [Int]
34 |
35 | init(data: Data,
36 | errorCorrectLevel: QRErrorCorrectLevel) throws {
37 | self.encodedText = QR8bitByte(parsedData: data)
38 |
39 | self.typeNumber = try QRCodeType
40 | .typeNumber(forLength: encodedText.count,
41 | errorCorrectLevel: errorCorrectLevel)
42 | self.errorCorrectLevel = errorCorrectLevel
43 | self.dataCache = try QRCodeModel.createData(
44 | typeNumber: typeNumber,
45 | errorCorrectLevel: errorCorrectLevel,
46 | data: encodedText
47 | )
48 | makeImpl(isTest: false, maskPattern: getBestMaskPattern())
49 | }
50 |
51 | /// Please be aware of index out of bounds error yourself.
52 | public func isDark(_ row: Int, _ col: Int) -> Bool {
53 | return modules?[row][col] == true
54 | }
55 |
56 | public func isLight(_ row: Int, _ col: Int) -> Bool {
57 | return !isDark(row, col)
58 | }
59 |
60 | private mutating func makeImpl(isTest test: Bool, maskPattern: QRMaskPattern) {
61 | moduleCount = typeNumber * 4 + 17
62 | modules = [[Bool?]](repeating:[Bool?](repeating: nil, count: moduleCount), count: moduleCount)
63 | setupPositionProbePattern(0, 0)
64 | setupPositionProbePattern(moduleCount - 7, 0)
65 | setupPositionProbePattern(0, moduleCount - 7)
66 | setupPositionAdjustPattern()
67 | setupTimingPattern()
68 | setupTypeInfo(isTest: test, maskPattern: maskPattern.rawValue)
69 | if typeNumber >= 7 {
70 | setupTypeNumber(isTest: test)
71 | }
72 | mapData(dataCache, maskPattern: maskPattern)
73 | }
74 |
75 | private mutating func setupPositionProbePattern(_ row: Int, _ col: Int) {
76 | for r in -1...7 {
77 | if row + r <= -1 || moduleCount <= row + r {
78 | continue
79 | }
80 | for c in -1...7 {
81 | if col + c <= -1 || moduleCount <= col + c {
82 | continue
83 | }
84 | if (0 <= r && r <= 6 && (c == 0 || c == 6))
85 | || (0 <= c && c <= 6 && (r == 0 || r == 6))
86 | || (2 <= r && r <= 4 && 2 <= c && c <= 4) {
87 | modules[row + r][col + c] = true
88 | } else {
89 | modules[row + r][col + c] = false
90 | }
91 | }
92 | }
93 | }
94 |
95 | private mutating func setupTimingPattern() {
96 | for i in 8..> i) & 1) == 1)
136 | modules[i / 3][i % 3 + moduleCount - 8 - 3] = mod
137 | modules[i % 3 + moduleCount - 8 - 3][i / 3] = mod
138 | }
139 | }
140 |
141 | private mutating func setupTypeInfo(isTest test: Bool, maskPattern: Int) {
142 | let data = (errorCorrectLevel.pattern << 3) | maskPattern
143 | let bits: Int = BCH.typeInfo(of: data) // to enforce signed shift
144 | for i in 0..<15 {
145 | let mod = !test && ((bits >> i) & 1) == 1
146 |
147 | if i < 6 {
148 | modules[i][8] = mod
149 | } else if i < 8 {
150 | modules[i + 1][8] = mod
151 | } else {
152 | modules[moduleCount - 15 + i][8] = mod
153 | }
154 |
155 | if i < 8 {
156 | modules[8][moduleCount - i - 1] = mod
157 | } else if i < 9 {
158 | modules[8][15 - i - 1 + 1] = mod
159 | } else {
160 | modules[8][15 - i - 1] = mod
161 | }
162 | }
163 | modules[moduleCount - 8][8] = !test
164 | }
165 |
166 | private mutating func mapData(_ data: [Int], maskPattern: QRMaskPattern) {
167 | var inc = -1
168 | var row = moduleCount - 1
169 | var bitIndex = 7
170 | var byteIndex = 0
171 |
172 | var col: Int = moduleCount - 1
173 | while col > 0 {
174 | if col == 6 {
175 | col -= 1
176 | }
177 | while true {
178 | for c in 0..<2 {
179 | if modules[row][col - c] == nil {
180 | var dark = false
181 | if byteIndex < data.count {
182 | dark = ((UInt(data[byteIndex]) >> bitIndex) & 1) == 1
183 | }
184 | let mask = maskPattern.getMask(row, col - c)
185 | if mask {
186 | dark = !dark
187 | }
188 | modules[row][col - c] = dark
189 | bitIndex -= 1
190 | if bitIndex == -1 {
191 | byteIndex += 1
192 | bitIndex = 7
193 | }
194 | }
195 | }
196 | row += inc
197 | if row < 0 || moduleCount <= row {
198 | row -= inc
199 | inc = -inc
200 | break
201 | }
202 | }
203 | col -= 2
204 | }
205 | }
206 |
207 | private static let PAD0: UInt = 0xEC
208 | private static let PAD1: UInt = 0x11
209 |
210 | private static func createData(
211 | typeNumber: Int, errorCorrectLevel: QRErrorCorrectLevel, data: QR8bitByte
212 | ) throws -> [Int] {
213 | let rsBlocks = errorCorrectLevel.getRSBlocks(ofType: typeNumber)
214 | var buffer = QRBitBuffer()
215 |
216 | buffer.put(data.mode.rawValue, length: 4)
217 | guard let length = data.mode.bitCount(ofType: typeNumber) else {
218 | throw QRCodeError.internalError(.dataLengthIndeterminable)
219 | }
220 | buffer.put(UInt(data.count), length: length)
221 | data.write(to: &buffer)
222 |
223 | let totalBitCount = 8 * rsBlocks.reduce(0) { $0 + $1.dataCount }
224 | if buffer.bitCount > totalBitCount {
225 | throw QRCodeError.internalError(
226 | .dataLength(buffer.bitCount,
227 | exceedsCapacityLimit: totalBitCount)
228 | )
229 | }
230 | if buffer.bitCount + 4 <= totalBitCount {
231 | buffer.put(0, length: 4)
232 | }
233 | while buffer.bitCount % 8 != 0 {
234 | buffer.put(false)
235 | }
236 | while true {
237 | if buffer.bitCount >= totalBitCount {
238 | break
239 | }
240 | buffer.put(QRCodeModel.PAD0, length: 8)
241 | if buffer.bitCount >= totalBitCount {
242 | break
243 | }
244 | buffer.put(QRCodeModel.PAD1, length: 8)
245 | }
246 | return try QRCodeModel.createBytes(fromBuffer: buffer, rsBlocks: rsBlocks)
247 | }
248 |
249 | private static func createBytes(fromBuffer buffer: QRBitBuffer, rsBlocks: [QRRSBlock]) throws -> [Int] {
250 | var offset = 0
251 | var maxDcCount = 0
252 | var maxEcCount = 0
253 | // Actual contents will be assigned later
254 | var dcdata = [[Int]]()
255 | dcdata.reserveCapacity(rsBlocks.count)
256 | var ecdata = [[Int]]()
257 | ecdata.reserveCapacity(rsBlocks.count)
258 | for r in rsBlocks.indices {
259 | let dcCount = rsBlocks[r].dataCount
260 | let ecCount = rsBlocks[r].totalCount - dcCount
261 | maxDcCount = max(maxDcCount, dcCount)
262 | maxEcCount = max(maxEcCount, ecCount)
263 | // Here for `dcdata`
264 | dcdata.append((0..= 0) ? modPoly[modIndex] : 0
276 | })
277 | }
278 | var totalCodeCount = 0
279 | for i in rsBlocks.indices {
280 | totalCodeCount += rsBlocks[i].totalCount
281 | }
282 | var data = [Int](repeating: 0, count: totalCodeCount)
283 | var index = 0
284 | for i in 0.. QRMaskPattern {
306 | var minLostPoint = 0
307 | var pattern = 0
308 | for i in 0..<8 {
309 | makeImpl(isTest: true, maskPattern: QRMaskPattern(rawValue: i)!)
310 | let lostPoint = self.lostPoint
311 | if i == 0 || minLostPoint > lostPoint {
312 | minLostPoint = lostPoint
313 | pattern = i
314 | }
315 | }
316 | return QRMaskPattern(rawValue: pattern)!
317 | }
318 |
319 | var lostPoint: Int {
320 | // TODO: Remove if needed
321 | // let moduleCount = self.moduleCount
322 | var lostPoint = 0
323 | for row in 0.. 5 {
344 | lostPoint += (3 + sameCount - 5)
345 | }
346 | }
347 | }
348 | for row in 0..
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | import XCTest
24 | @testable import QRCodeSwift
25 |
26 | private func expect(_ generator: @autoclosure () throws -> QRCode, withFill fill: String, andPatch patch: String, toMatch expected: String) throws {
27 | let qrCode = try generator()
28 | let generated = qrCode.toString(filledWith: fill, patchedWith: patch)
29 | XCTAssertEqual(generated, expected)
30 | }
31 |
32 | private extension UnicodeScalar {
33 | static let values = Array([0...0xD7FF, 0xE000...0x10FFFF].joined())
34 | static func randomElement(ignoredParameter: Int = 0) -> String {
35 | return "\(UnicodeScalar(values.randomElement()!)!)"
36 | }
37 | }
38 |
39 | private func randomStringOfUTF8Length(_ length: Int) -> String {
40 | var str = ""
41 | while str.utf8.count < length {
42 | str += UnicodeScalar.randomElement()
43 | if str.utf8.count > length {
44 | str = String(str.dropLast())
45 | }
46 | }
47 | return str
48 | }
49 |
50 | class QRCodeSwiftTests: XCTestCase {
51 | func testSimple() throws {
52 | try expect(QRCode("https://gist.github.com/agentgt/1700331"),
53 | withFill: "##", andPatch: " ",
54 | toMatch: """
55 |
56 | ############## ###### ## ###### #### ##############
57 | ## ## ## ######## #### ## ## ## ##
58 | ## ###### ## #### ## #### ## #### #### #### ## ###### ##
59 | ## ###### ## ## ###### #### #### ## ## ## ###### ##
60 | ## ###### ## ## ######## ## ## ## ## ###### ##
61 | ## ## ## ## ###### ## ## ## ## ## ##
62 | ############## ## ## ## ## ## ## ## ## ## ## ## ##############
63 | ## ## ## ###### ######
64 | #### ######## ## ######## ## ## ## ## ##
65 | #### ## ## ## #### ###### ## ## ######
66 | ## ## ######## ## ## ## #### ###### ######
67 | ######## ## ## ## ## ## ## ## ## ###### ## ##
68 | ## #### ## ###### ######## ######## ####
69 | #### ## ############ #### ## ## ###### ## ####
70 | #### #### ## ## ## ## #### #### ## ## ## ## ####
71 | ## ## #### #### ## #### #### ########
72 | ## ## ###### ## ## #### ## ## ###### ###### ## ## ##
73 | ############ ## #### ## ## ## ###### ## ##
74 | #### ######## ## ###### #### ## ###### #### ## #### ##
75 | ########## #### ###### ## ############## ## ## ## ##
76 | ###### ## #### ######## ## #### ################
77 | ## ## ## ## ## #### ## ######## ## #### ###### ##
78 | #### ## ## ######## #### #### ## ###### ## ##
79 | ########## ## ########## ## #### #### ## ## ## ####
80 | ## ############## #### #### ## #### ###### ## ####
81 | ## ## ######## ## ## ## ##
82 | ## ########## ######## #### ## ############ ## ## ####
83 | ## ## ## ###### #### #### ###### #### ## ####
84 | ## #### #### ###### ## ## ## ################ ## ##
85 | #### #### #### ###### ###### ## #### ##
86 | ############## ## #### ###### ## ## ## ###### ##
87 | ## ## #### #### ## ## #### #### #### ####
88 | ## ###### ## #### ###### ## ###### ################ ##
89 | ## ###### ## ## ######## #### ## ###### ## ##
90 | ## ###### ## ## ## ## #### ###### ## ## ## #### ##
91 | ## ## ## ## #### ###### ## ############ ##
92 | ############## #### ###### ## ## #### ## ###### ## ##
93 |
94 | """)
95 | }
96 |
97 | func testLowErrorCorrectLevel() throws {
98 | try expect( QRCode("https://passport.bilibili.com/qrcode/h5/login?oauthKey=2f3ab118e214e7ad69683df50918a481",
99 | errorCorrectLevel: .L),
100 | withFill: "@@", andPatch: " ",
101 | toMatch: """
102 |
103 | @@@@@@@@@@@@@@ @@ @@ @@ @@@@ @@ @@@@@@@@ @@@@@@@@@@@@@@
104 | @@ @@ @@ @@@@@@@@ @@ @@ @@ @@ @@ @@
105 | @@ @@@@@@ @@ @@@@ @@ @@@@@@@@@@ @@@@@@@@@@ @@ @@ @@ @@@@@@ @@
106 | @@ @@@@@@ @@ @@@@@@ @@ @@ @@ @@@@@@@@@@ @@ @@@@@@ @@
107 | @@ @@@@@@ @@ @@@@ @@ @@@@ @@ @@ @@ @@@@@@ @@ @@@@@@ @@
108 | @@ @@ @@@@@@ @@@@@@@@ @@ @@ @@
109 | @@@@@@@@@@@@@@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@@@@@@@@@@@@@
110 | @@@@ @@ @@ @@@@ @@@@ @@@@ @@@@@@
111 | @@@@ @@@@@@ @@ @@@@ @@@@ @@ @@@@ @@ @@ @@@@@@@@
112 | @@@@@@ @@@@@@ @@ @@ @@ @@@@@@@@ @@ @@@@
113 | @@@@@@@@@@@@@@@@ @@ @@@@ @@@@ @@@@ @@@@ @@@@ @@@@ @@
114 | @@@@ @@ @@ @@ @@@@@@@@ @@ @@ @@@@ @@
115 | @@ @@ @@@@@@@@ @@@@ @@@@@@ @@@@ @@ @@ @@@@@@ @@ @@
116 | @@ @@ @@@@ @@ @@@@ @@@@@@@@ @@@@@@ @@@@@@@@
117 | @@@@ @@@@ @@@@ @@@@@@@@@@@@ @@ @@@@@@@@ @@@@ @@ @@
118 | @@ @@@@ @@ @@ @@@@@@ @@ @@ @@ @@@@ @@ @@@@@@@@@@
119 | @@@@ @@@@@@@@@@ @@@@ @@@@@@@@@@ @@ @@@@ @@@@ @@@@@@ @@ @@
120 | @@ @@@@ @@ @@@@@@ @@ @@@@@@@@ @@@@@@ @@@@@@@@@@
121 | @@@@@@@@ @@ @@ @@ @@ @@@@ @@@@@@@@@@ @@@@
122 | @@ @@@@ @@@@ @@ @@@@@@@@@@ @@@@ @@ @@ @@ @@@@
123 | @@@@ @@@@@@@@ @@@@ @@@@@@@@@@@@ @@ @@ @@@@ @@@@@@@@
124 | @@ @@@@@@ @@ @@ @@@@@@ @@@@@@ @@ @@
125 | @@ @@ @@@@@@@@@@ @@@@@@@@@@ @@ @@@@ @@ @@ @@@@@@
126 | @@ @@ @@ @@ @@ @@@@@@ @@@@ @@ @@@@@@ @@@@
127 | @@@@@@ @@ @@ @@ @@@@ @@@@@@@@ @@@@@@@@ @@ @@@@ @@@@@@
128 | @@@@@@ @@ @@ @@ @@@@@@ @@ @@ @@ @@ @@@@ @@ @@
129 | @@@@ @@@@@@@@ @@@@@@ @@ @@@@ @@@@@@@@@@@@@@ @@
130 | @@ @@ @@ @@@@@@@@ @@@@@@ @@ @@@@ @@@@
131 | @@@@ @@@@@@ @@ @@@@ @@@@@@@@ @@ @@@@ @@@@@@@@@@@@@@@@@@
132 | @@ @@ @@ @@ @@@@ @@ @@ @@
133 | @@@@@@@@@@@@@@ @@ @@@@@@@@@@ @@ @@@@@@@@@@ @@ @@ @@
134 | @@ @@ @@ @@@@ @@ @@ @@@@ @@ @@ @@@@@@ @@ @@ @@
135 | @@ @@@@@@ @@ @@ @@@@ @@@@ @@ @@@@ @@ @@@@@@@@@@@@@@@@@@
136 | @@ @@@@@@ @@ @@@@@@ @@ @@ @@ @@@@ @@@@@@ @@@@
137 | @@ @@@@@@ @@ @@ @@@@@@@@ @@@@@@@@ @@@@ @@@@@@
138 | @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@@@
139 | @@@@@@@@@@@@@@ @@@@@@@@ @@@@ @@ @@@@@@@@@@@@ @@ @@@@@@@@@@@@@@
140 |
141 | """)
142 | }
143 |
144 | func testBorderless() throws {
145 | try expect(QRCode("https://github.com/ApolloZhu", withBorder: false),
146 | withFill: "MM", andPatch: " ",
147 | toMatch: """
148 | MMMMMMMMMMMMMM MMMM MM MM MMMMMM MM MM MMMMMMMMMMMMMM
149 | MM MM MM MMMMMMMM MM MMMMMM MM MM MM
150 | MM MMMMMM MM MMMM MM MMMMMMMM MMMMMMMMMMMMMM MM MMMMMM MM
151 | MM MMMMMM MM MM MM MM MM MM MM MM MM MMMMMM MM
152 | MM MMMMMM MM MM MMMM MMMMMMMMMMMM MMMM MM MMMMMM MM
153 | MM MM MMMM MM MM MMMM MM MM MM
154 | MMMMMMMMMMMMMM MM MM MM MM MM MM MM MM MM MMMMMMMMMMMMMM
155 | MM MMMM MM MM MM
156 | MMMM MMMM MMMM MM MM MMMMMM MM MMMM
157 | MM MM MMMMMMMMMM MMMMMM MMMMMMMMMMMM MM MMMMMM
158 | MMMM MMMMMMMM MM MM MM MMMM MMMMMM MM MMMMMM
159 | MMMM MM MM MM MMMMMM MMMMMMMMMM MMMMMMMMMMMM
160 | MM MMMMMM MMMM MM MM MM MM MM MMMMMMMM MM
161 | MM MMMMMM MM MMMM MM MM MMMM MMMM MM
162 | MMMM MMMM MM MM MM MMMM MM MM
163 | MMMM MM MM MM MM MM MM MMMM MMMM MMMM MM
164 | MMMMMM MMMMMMMM MM MM MMMM MM MMMM MM MM
165 | MMMM MM MM MM MMMM MMMM MMMM MM MM MMMMMMMM MM
166 | MMMM MMMM MM MM MMMM MMMMMM MMMM MMMM MMMMMM MM
167 | MM MM MMMM MMMMMMMMMM MM MMMM MMMMMM MM MMMMMM
168 | MM MMMMMMMM MMMM MMMMMM MM MMMM MM MM MMMM
169 | MM MM MM MMMM MMMM MMMM MM MMMM MMMMMMMM
170 | MM MMMM MMMM MM MMMM MM MM MM MMMM MMMMMM
171 | MM MM MMMM MMMM MM MM MMMM MMMMMM
172 | MMMMMMMMMMMMMM MMMM MM MMMM MM MMMM MMMMMMMMMM
173 | MMMMMMMMMMMMMM MM MM MM MM MMMM MM
174 | MMMMMMMMMMMMMM MMMM MMMM MM MMMMMMMMMMMMMMMM MM MMMM
175 | MM MM MMMM MMMM MMMM MMMM MMMMMMMM
176 | MM MMMMMM MM MMMM MM MMMM MM MMMM MMMMMMMMMMMMMMMMMM
177 | MM MMMMMM MM MM MMMM MMMMMM MM MM MM MMMM
178 | MM MMMMMM MM MM MM MMMMMM MM MM MM MM MMMMMM
179 | MM MM MMMM MM MM MM MMMMMM
180 | MMMMMMMMMMMMMM MM MMMM MMMMMM MMMM MMMM MM MM
181 | """)
182 | }
183 |
184 |
185 | func testEFQRCode() throws {
186 | try expect(QRCode("https://github.com/EyreFree/EFQRCode"),
187 | withFill: "WW", andPatch: " ",
188 | toMatch: """
189 |
190 | WWWWWWWWWWWWWW WW WWWW WW WWWWWW WWWWWWWWWWWWWW
191 | WW WW WW WW WWWWWWWWWWWWWW WWWWWW WWWW WW WW
192 | WW WWWWWW WW WW WW WWWW WW WWWW WW WW WW WWWWWW WW
193 | WW WWWWWW WW WW WWWW WWWW WW WW WW WWWW WW WWWWWW WW
194 | WW WWWWWW WW WWWW WW WW WWWW WWWW WW WWWWWW WW
195 | WW WW WWWWWW WW WWWWWWWW WW WW WWWW WW WW
196 | WWWWWWWWWWWWWW WW WW WW WW WW WW WW WW WW WW WW WWWWWWWWWWWWWW
197 | WW WWWWWW WW WWWWWW WW
198 | WW WW WW WWWWWW WWWWWW WWWW WWWWWW WWWW
199 | WWWW WW WWWWWWWW WWWW WW WWWW WW WW WW WWWWWW
200 | WW WWWWWWWWWWWWWW WW WW WWWWWWWWWW WW WW WW WWWW WWWWWWWW
201 | WWWW WWWWWW WW WW WW WW WW WWWW WW WW
202 | WWWWWWWWWWWWWWWW WWWWWWWWWW WW WWWW WWWWWW WW
203 | WWWW WW WW WW WWWWWW WWWW WWWWWW WWWW WW WWWW WW WWWW
204 | WWWW WWWWWWWW WW WW WW WWWWWW WW WW WW
205 | WWWWWWWW WW WWWW WW WW WWWWWWWW WWWW WWWWWWWW WW
206 | WWWW WWWWWWWWWWWWWW WWWWWWWWWW WWWW WWWW WW WW WWWWWW WWWWWWWW
207 | WW WW WWWW WWWWWWWWWWWW WW WWWWWWWWWW WW
208 | WWWWWWWWWW WWWWWWWW WWWWWW WWWWWWWW WWWW WWWW WWWWWW
209 | WW WWWWWWWW WWWW WW WWWWWWWWWWWW WW WWWW WWWW
210 | WWWWWW WWWWWWWWWWWW WWWWWWWW WW WWWWWW WWWWWWWW WW
211 | WW WW WWWWWWWWWW WW WWWW WW WWWWWWWW WWWW WWWW
212 | WWWWWW WW WW WWWW WWWWWW WW WWWW WWWWWWWW WWWW
213 | WW WW WW WW WW WW WW WW WWWW WW WW WWWW
214 | WWWWWWWWWW WWWW WW WW WW WWWWWW WW WW WW WW
215 | WWWW WWWW WWWWWWWW WWWW WW WWWW WWWW WW WW
216 | WW WW WWWWWW WWWW WWWW WW WWWW WW WWWWWWWWWWWWWW WW WW
217 | WW WW WW WW WW WWWW WWWWWW WWWW WW WW
218 | WWWW WW WW WWWW WWWW WW WW WW WWWWWWWWWWWW WW
219 | WW WW WW WW WW WW WWWWWWWWWW WW WWWW
220 | WWWWWWWWWWWWWW WW WW WWWWWWWWWWWWWWWWWW WW WWWW WW WW WWWWWW
221 | WW WW WW WW WW WW WW WWWWWW WW WW
222 | WW WWWWWW WW WW WWWW WW WW WWWWWWWWWW WWWWWWWWWWWW WW
223 | WW WWWWWW WW WW WWWWWW WWWWWW WW WWWWWWWW WW WW WWWW
224 | WW WWWWWW WW WW WWWW WW WWWW WWWWWWWWWW WW WWWW WW
225 | WW WW WW WWWW WW WWWW WW WWWWWW WWWW WW
226 | WWWWWWWWWWWWWW WW WW WWWWWW WW WW WW WWWWWW WWWW WWWW
227 |
228 | """)
229 | }
230 |
231 | func testEmpty() throws {
232 | try expect(QRCode("", errorCorrectLevel: .L),
233 | withFill: "XX", andPatch: " ",
234 | toMatch: """
235 |
236 | XXXXXXXXXXXXXX XX XX XXXXXXXXXXXXXX
237 | XX XX XX XX XX XX
238 | XX XXXXXX XX XX XX XXXXXX XX
239 | XX XXXXXX XX XX XX XX XXXXXX XX
240 | XX XXXXXX XX XXXXXX XX XXXXXX XX
241 | XX XX XXXXXX XX XX XX
242 | XXXXXXXXXXXXXX XX XX XX XXXXXXXXXXXXXX
243 | XXXXXX
244 | XXXXXXXXXX XXXXXXXX XXXX XX XX XX
245 | XXXX XXXX XX XX XX XX
246 | XX XX XX XXXX XX XXXXXXXXXX
247 | XX XX XXXX XXXX XX XX
248 | XXXXXX XXXXXXXX XX XX XXXXXXXXXX
249 | XXXXXXXXXXXXXX XX
250 | XXXXXXXXXXXXXX XXXXXX XX XXXX
251 | XX XX XXXXXXXXXXXX XX
252 | XX XXXXXX XX XXXXXX XX XX XX
253 | XX XXXXXX XX XXXX XX XX XX
254 | XX XXXXXX XX XXXX XX XX XXXXXX
255 | XX XX XXXX XXXX XX
256 | XXXXXXXXXXXXXX XX XXXX XX XXXXXXXX
257 |
258 | """)
259 | }
260 |
261 | func testStressWithPi() throws {
262 | let content = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989"
263 | try expect(QRCode(content, errorCorrectLevel: .M),
264 | withFill: "%%", andPatch: " ",
265 | toMatch: """
266 |
267 | %%%%%%%%%%%%%% %%%%%% %%%%%%%%%%%% %%%%%%%% %%%%%% %% %% %%%% %%%% %%%%%% %% %% %%%%%% %%%% %%%%%% %% %%%%%% %% %%%%%% %% %% %% %% %% %%%% %%%%%%%%%%%%%%
268 | %% %% %% %% %%%%%%%% %% %% %% %% %% %% %%%% %% %%%%%%%% %% %% %%%%%%%% %% %%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %% %% %%
269 | %% %%%%%% %% %% %%%% %% %%%% %% %%%% %% %%%%%%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %%%% %% %%%%%%%% %% %%%% %% %%%%%% %%
270 | %% %%%%%% %% %%%%%% %%%%%% %% %% %% %%%% %%%%%% %% %%%% %% %% %% %% %% %%%%%% %% %% %% %%%% %% %%%% %% %% %%%% %% %%%%%%%% %% %%%%%%%% %% %%%%%% %%
271 | %% %%%%%% %% %% %%%% %% %% %% %% %%%%%%%%%%%% %%%%%%%% %%%% %% %% %% %% %%%%%%%%%% %% %%%% %%%% %% %% %%%%%%%%%%%%%% %%%% %%%% %%%% %%%% %% %% %%%%%% %%
272 | %% %% %%%%%%%%%%%% %% %% %% %% %% %% %% %%%%%% %% %% %%%%%%%% %% %% %%%% %% %% %%%%%%%% %% %% %% %% %% %% %%%%%%%% %% %% %%%%%%%%%%%% %% %%
273 | %%%%%%%%%%%%%% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %% %%%%%%%%%%%%%%
274 | %% %% %%%% %%%%%%%% %%%% %% %% %%%% %% %% %% %%%%%% %% %%%%%% %%%% %% %%%%%%%% %% %% %%%%%% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%%
275 | %% %%%% %%%%%% %% %%%%%%%% %% %% %%%%%% %%%%%%%%%%%%%% %% %% %%%% %%%%%%%% %%%%%% %%%%%%%%%%%% %%%% %%%% %%%% %% %% %%%% %%%%%%%%%%%% %% %% %% %% %%%% %% %% %% %%%%
276 | %% %% %% %%%%%% %% %%%% %% %%%% %%%%%% %% %%%%%% %%%%%%%% %% %%%%%% %% %%%% %%%% %%%%%%%% %%%% %%%% %% %% %%%% %%%%%% %% %%%%%% %%%%%% %%%% %%
277 | %%%% %% %%%%%% %% %%%%%%%% %%%% %% %%%% %%%%%% %% %% %%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %%%%%% %% %% %%%%%%%% %% %% %% %% %% %%
278 | %% %% %% %% %% %%%% %% %% %% %%%%%%%% %%%%%% %% %% %% %%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%% %% %%
279 | %% %%%%%% %%%% %% %% %%%% %%%%%%%% %% %% %%%% %%%%%%%% %% %%%% %%%% %%%%%% %%%% %% %% %% %% %%%% %% %% %% %%%% %%%% %%%% %% %%%% %%%%%% %% %% %% %%%%%%
280 | %% %% %% %% %%%%%% %% %% %% %%%%%%%%%% %%%%%% %%%% %%%% %% %% %% %%%% %% %% %% %%%% %%%%%%%% %% %% %% %% %%%% %% %%%%%% %%%% %% %% %%%% %% %% %%
281 | %% %%%%%%%% %% %% %% %%%% %% %% %% %%%% %% %% %%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %% %% %% %%%%%%%% %% %% %%%% %% %% %%%% %%
282 | %% %% %% %% %% %% %%%% %%%% %% %% %%%% %%%% %%%%%%%% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%%%%%% %% %% %%%%%%%% %% %% %%%%%% %% %%%% %%
283 | %%%%%% %% %% %%%%%%%% %%%%%% %%%%%%%% %%%% %% %%%%%% %% %%%%%%%% %%%% %% %% %%%% %% %% %%%%%% %% %% %%%% %%%% %% %%%% %% %% %%%% %% %%%% %% %%%%%%%%%%%%
284 | %% %% %%%%%% %%%% %%%%%%%%%%%% %%%%%%%% %% %%%% %%%% %% %%%% %% %%%%%%%% %% %%%% %% %%%%%%%% %%%% %%%%%%%%%%%%%%%% %%%%%% %% %% %%%% %% %% %%%%%%
285 | %%%% %%%%%% %% %% %% %%%% %% %% %% %%%%%% %% %%%% %% %%%% %% %%%%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %%
286 | %% %%%%%% %%%%%% %%%%%%%% %% %% %% %%%%%% %%%%%% %% %%%% %%%%%% %% %% %%%%%%%%%% %% %% %%%%%%%% %% %% %%%%%% %%%% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%% %% %%%%
287 | %%%% %%%% %%%% %% %%%% %%%% %% %% %% %% %% %%%% %%%%%%%% %%%% %%%%%%%% %%%%%%%%%%%% %%%% %%%%%%%% %% %%%%%%%%%% %%%% %% %% %% %%%%%%%%%% %% %%%% %%%%%% %%
288 | %% %%%%%%%% %%%% %%%% %%%%%% %% %%%%%%%% %%%%%%%% %%%% %%%% %%%%%%%% %% %% %%%% %% %%%% %%%%%%%%%%%% %%%% %%%% %%%% %%%% %% %%%% %%%% %% %%%% %%%%%%%%%% %%
289 | %% %% %% %% %%%% %% %%%%%% %% %%%%%% %% %% %% %% %% %%%%%% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%% %% %% %%%%%% %%%% %% %%%% %%%%%%%%
290 | %%%% %% %% %% %%%%%% %% %%%% %% %% %% %% %% %% %%%% %%%% %%%%%%%% %% %% %%%%%% %% %%%%%%%% %% %% %%%% %% %% %% %% %%%%%%%% %% %% %% %% %% %%%% %%%% %%%%%%
291 | %% %% %%%%%%%%%% %% %% %% %% %% %% %%%%%% %% %% %% %% %% %%%%%%%% %%%%%%%%%%%%%% %% %%%% %%%% %% %%%%%% %%%%%% %%%%%% %%%%%% %% %%%% %%%%%%%% %% %% %% %%
292 | %% %% %% %%%%%% %% %%%% %% %% %% %% %%%% %%%% %%%%%%%%%%%%%% %% %%%%%% %%%% %%%% %%%%%%%% %%%% %% %% %%%% %% %%%%%%%% %%%%%%%%%%%% %%%% %% %% %%%%
293 | %%%%%%%%%% %%%%%% %%%%%% %%%%%% %% %%%% %%%%%% %% %%%%%%%% %%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%% %%%%%%%%
294 | %% %% %% %%%% %%%% %% %% %% %% %% %% %%%% %%%%%% %%%%%%%% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%%%%%% %% %% %%%%%%%% %% %% %%%%%% %% %% %%%% %%
295 | %%%%%%%%%%%%%%%% %% %%%%%%%%%%%% %%%%%% %%%%%%%%%%%%%%%% %%%% %% %%%% %% %%%%%%%%%%%%%%%% %%%% %%%% %%%% %% %% %%%%%%%%%% %% %% %%%% %% %%%%%% %%%% %% %%%%%%%%%%%%%%%%
296 | %%%%%% %%%%%% %% %% %%%%%%%% %%%%%%%%%% %%%% %% %%%% %%%%%%%% %% %% %% %% %% %% %% %%%% %% %%%%%% %%%% %%%% %%%% %% %% %% %% %% %% %% %% %%
297 | %% %% %% %% %% %%%%%% %% %%%%%%%%%% %% %% %%%% %% %% %% %% %% %% %% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%% %% %% %%%%
298 | %% %% %%%%%% %% %% %% %% %%%%%%%%%% %%%% %%%% %%%% %% %% %% %% %%%% %% %%%%%%%% %% %% %%%%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %%%%
299 | %%%%%%%%%% %% %%%%%%%%%% %%%%%%%%%% %%%%%%%%%% %% %%%% %%%%%%%% %% %%%%%%%% %% %% %%%%%%%%%% %%%% %%%% %% %% %%%% %% %%%%%%%%%%%% %%%% %% %% %% %% %%%%%%%% %%%%%%%%%%%% %%%%
300 | %% %%%% %%%%%%%%%% %%%%%% %%%% %%%% %%%%%%%% %% %%%% %%%% %%%% %%%% %%%% %% %% %%%%%%%% %% %% %% %%%%%%%%%% %% %%%% %%%% %%%% %% %%
301 | %%%% %%%%%%%%%% %% %% %%%%%% %% %% %%%% %%%%%%%% %%%%%%%%%% %% %% %% %% %% %%%%%%%% %% %% %%%% %% %% %%%% %% %%%% %% %% %% %% %% %% %%%% %% %%%%%%
302 | %%%%%%%% %% %% %%%%%% %% %% %%%%%%%%%% %% %% %% %%%% %%%% %%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %% %%%%%% %% %%%% %%%%%% %% %% %%%%%%%% %% %%
303 | %% %%%% %%%%%%%%%%%% %%%% %% %% %%%% %%%%%%%% %%%%%%%%%%%% %%%% %%%%%%%% %%%% %% %% %% %%%% %% %%%%%% %%%% %% %%%%%% %% %% %% %% %%%%%%%% %% %% %% %% %% %% %%
304 | %% %%%% %% %% %%%% %%%% %% %%%%%%%%%%%% %%%%%%%%%%%%%% %%%%%%%% %% %% %%%%%% %%%%%% %% %%%% %%%%%% %%%% %%%%%%%% %%%% %% %%%% %% %% %%%%%%%%%% %%%%%%%% %% %%%%%% %% %%
305 | %%%%%% %%%%%% %% %%%% %% %%%%%%%%%% %% %% %% %%%%%% %%%%%%%%%% %%%%%% %%%% %%%%%% %% %% %% %%%%%%%% %% %% %% %% %%%%%% %% %%%%%%%% %% %% %%%%%%%% %%%% %%%%%%
306 | %% %% %%%% %%%%%%%%%%%%%% %% %%%%%%%%%%%% %% %% %% %%%%%% %%%%%%%% %% %% %% %% %%%%%% %%%% %% %%%%%%%% %% %%%%%% %% %% %% %%%%%%%% %% %% %%%%%%%%%%%% %%
307 | %%%% %%%% %%%%%% %% %%%%%%%% %%%% %% %% %%%% %% %% %%%%%%%% %%%% %% %%%%%% %%%% %%%%%% %% %% %%%% %% %% %%%%%% %% %%%% %%%%%%%% %%%% %% %%%% %% %% %%%%
308 | %% %%%% %% %%%% %%%% %%%%%%%%%% %% %%%% %%%% %% %% %% %%%% %%%%%%%% %%%% %% %%%%%%%%%% %%%%%% %% %% %% %%%% %%%%%%%% %% %%%% %%%% %%%%%% %%%%%%%%
309 | %% %% %%%%%% %% %%%%%%%% %%%% %% %% %%%%%% %% %%%% %%%%%%%%%%%% %% %% %% %% %% %%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%% %%
310 | %%%%%%%% %% %%%%%%%% %%%% %%%%%%%%%%%% %%%%%% %%%%%% %% %%%% %% %%%%%% %% %% %%%%%% %%%% %% %%%%%%%% %% %% %%%%%% %%%%%% %% %%%%%%%% %% %% %%%%%%%% %%%% %% %% %%%%
311 | %% %%%%%%%%%%%% %%%%%% %%%% %% %% %%%%%%%%%%%% %% %% %%%%%% %% %%%%%%%% %%%% %% %%%%%% %%%%%% %%%% %% %% %%%% %% %% %% %% %%%% %%%% %%
312 | %% %%%%%% %%%% %%%% %%%%%% %%%%%% %%%%%%%% %%%%%% %% %%%%%%%% %%%% %% %%%% %%%%%% %%%%%% %%%% %% %% %% %%%% %% %%%% %% %% %%%%%% %%
313 | %%%% %%%%%% %% %%%% %%%% %%%%%% %% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %%%% %% %% %% %% %%%%%%%% %% %% %%%% %% %% %%%%%%
314 | %% %%%% %% %% %% %% %%%% %% %% %% %% %% %% %% %%%%%% %%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %% %%%%%% %% %% %%%%%%%% %% %% %% %% %%
315 | %%%% %%%%%% %% %% %%%%%%%%%% %%%% %% %% %% %%%%%% %% %%%% %%%%%%%%%% %% %% %% %%%% %%%%%%%% %% %% %% %%%%%%%% %%%% %% %% %% %% %% %%%% %% %%
316 | %% %% %% %% %% %% %%%%%% %%%%%%%%%% %%%% %% %% %%%%%%%%%% %% %%%% %%%%%% %% %% %%%%%% %%%%%% %%%%%%%%%% %% %% %%%% %%%% %% %% %% %% %%%% %% %% %%
317 | %% %%%%%%%%%% %% %%%% %% %%%% %%%%%%%%%%%%%% %% %% %%%%%%%% %%%%%%%% %% %%%% %% %% %% %% %%%%%%%% %% %% %% %% %%%% %% %%%%%%%% %% %% %%%%%%%% %%%%%% %%%%
318 | %%%% %%%% %%%% %%%% %%%%%% %% %% %%%%%% %% %% %%%% %%%%%%%% %%%% %%%%%%%% %% %% %%%% %%%%%% %% %% %%%%%%%% %% %%%%%% %%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%
319 | %% %%%% %%%%%% %% %%%% %% %%%%%%%% %% %% %% %%%%%%%%%%%% %% %% %% %% %% %% %%%%%%%% %% %% %% %% %%%% %%%% %% %% %%%%%% %% %%%% %% %% %%%%%%%%
320 | %%%% %%%% %%%%%%%% %% %% %% %%%%%% %%%%%%%% %% %%%% %%%% %% %%%%%% %%%%%%%% %%%%%% %% %% %% %%%%%% %%%% %%%% %%%%%%%%%% %%%%%%%% %%%%%% %%%%%%%% %%%%%% %%%%
321 | %%%%%% %%%% %%%%%% %% %% %%%%%% %%%%%%%% %% %%%% %% %% %% %% %%%% %%%% %% %% %%%% %% %% %% %% %% %%%%%%%% %%%% %% %% %% %%%%%%%% %% %% %% %%
322 | %% %% %% %% %% %% %%%% %% %%%%%%%%%%%% %% %%%%%% %% %% %%%%%% %%%% %%%% %%%%%% %% %% %%%%%% %%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%
323 | %% %%%%%%%%%% %% %%%%%%%% %%%%%% %% %%%%%%%%%%%%%%%% %%%%%%%%%%%% %%%%%%%%%% %% %%%%%%%%%%%%%% %% %%%%%%%%%%%% %% %% %% %%%% %%%%%%%%%% %% %%%% %% %% %%%%%%%% %%%%%%%%%%%%%% %%
324 | %%%% %% %% %% %%%%%%%% %% %% %%%% %%%% %%%% %% %% %%%% %% %%%% %%%%%% %%%%%%%% %%%%%% %% %%%% %%%% %%%%%% %%%%%% %%%% %% %% %% %% %% %% %%
325 | %% %%%% %% %% %%%% %% %% %%%% %% %%%% %% %% %%%% %% %%%% %%%% %% %%%%%%%% %% %% %% %%%%%%%% %% %%%% %%%%%% %% %%%% %% %%%% %% %% %%%%%%%% %% %% %% %% %% %%%% %%
326 | %%%%%%%%%% %% %% %% %%%%%%%%%%%% %% %% %%%%%% %%%%%%%%%% %% %%%%%% %%%%%% %%%%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%% %%%%%%%% %% %%%%%%%% %% %%%%%% %% %%%%
327 | %%%%%%%%%%%%%%%%%% %% %% %% %% %%%% %% %%%%%%%%%%%%%% %%%%%%%%%% %% %%%% %% %% %%%%%%%%%% %%%% %% %% %%%% %% %%%%%%%%%% %% %% %% %% %%%% %%%%%%%%%% %%
328 | %%%%%%%%%%%% %% %% %%%% %%%%%%%% %%%% %%%%%% %% %%%%%%%% %%%% %% %%%% %%%% %% %%%%%% %% %% %%%% %% %% %%%% %% %%%% %% %%%% %% %%%% %% %%%%%%%% %% %%
329 | %%%%%%%%%% %%%%%%%%%% %%%% %%%% %%%% %%%%%%%% %%%%%% %%%% %%%%%%%%%%%% %%%%%% %% %% %% %% %% %%%%%%%% %% %% %% %% %% %% %%%%%%%% %% %% %%%%%%%% %%%%%%%% %%
330 | %%%% %%%%%% %%%% %% %% %% %%%% %%%%%%%%%%%%%% %% %% %% %%%%%%%% %% %% %% %%%%%% %% %% %%%%%%%% %% %% %%%% %% %% %%%%%%%% %% %% %%%%%%%% %%%%%% %%%%
331 | %%%% %%%%%%%% %% %% %% %%%% %%%% %%%%%% %%%% %% %%%% %% %% %%%%%%%% %%%% %% %%%% %% %%%% %% %%%%%% %%%% %%%%%%%% %% %% %%%% %% %% %%%%%% %% %%%%%%%%
332 | %%%% %% %% %%%% %% %% %% %% %% %%%% %% %%%% %%%% %% %% %% %%%% %%%%%%%% %%%% %% %%%% %%%% %%%% %% %% %% %% %% %%%%%% %%%% %%%% %%%%%%%%%%%%
333 | %% %%%% %%%% %%%%%%%%%%%%%%%% %%%% %%%%%% %% %% %%%% %%%% %% %% %% %%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%% %% %%
334 | %%%% %%%%%% %%%% %%%% %%%% %% %% %% %%%%%% %% %% %% %% %% %% %%%% %% %% %%%%%%%% %% %% %%%%%%%%%% %%%% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%% %%
335 | %%%%%%%%%%%% %%%%%% %%%%%%%%%%%% %%%%%%%%%% %% %% %% %% %% %% %% %%%% %% %% %% %%%% %%%%%%%% %% %% %%%% %% %%%%%%%%%% %% %% %% %% %%
336 | %% %% %%%%%%%% %% %% %% %% %%%% %% %% %%%% %%%%%%%% %% %%%%%% %%%% %% %%%% %% %% %%%% %% %% %% %%%%%% %% %% %% %% %% %%%%%%%%%%%%
337 | %%%%%%%%%% %% %% %% %% %%%%%%%% %% %%%%%%%% %% %% %% %%%%%%%% %% %%%% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%% %% %% %% %%%%%%%% %%%% %% %% %%%% %%
338 | %%%% %%%%%% %% %% %% %%%% %% %%%%%%%%%%%%%% %% %% %%%%%% %% %%%%%%%%%% %% %%%%%%%%%% %%%%%% %%%%%%%% %% %% %%%%%% %%%% %%%% %%%%%%%%%%%% %% %% %%%%%%%% %% %% %%%%%% %% %%%%%%
339 | %% %% %%%%%%%%%% %%%%%%%% %% %%%%%% %% %%%%%% %%%%%% %% %% %%%%%%%% %%%%%% %% %% %%%% %% %%%% %% %% %% %%%% %% %%%%%% %% %% %%%%%% %% %% %% %%%%%%
340 | %%%% %%%% %%%%%% %% %%%% %% %%%%%% %% %%%%%%%%%% %%%% %%%% %% %%%%%% %% %%%% %%%%%% %% %% %%%% %% %%%% %% %%%% %% %% %%%%%% %%%% %% %% %%
341 | %% %% %%%% %%%%%% %% %%%% %%%%%% %% %% %% %%%% %% %%%%%% %% %% %%%%%%%% %%%% %% %%%%%%%% %% %% %% %% %% %%%%%%%% %% %% %%%%%%%% %%%%%%%%%%%%
342 | %%%% %% %% %%%%%% %%%% %% %% %%%% %%%% %%%%%% %%%% %%%%%%%% %% %%%%%%%% %% %% %% %%%%%%%% %% %%%%%%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %%%%%%%% %%
343 | %% %%%% %% %%%% %%%%%% %%%%%%%% %%%% %% %% %%%%%% %% %% %%%% %%%%%%%%%% %% %%%% %%%% %% %%%%%%%%%% %%%% %% %%%%%% %% %%%% %%%%%% %%%%%% %%%%%%%% %% %%%%%%%%%%
344 | %% %%%%%%%% %% %%%%%% %%%%%%%%%%%%%% %% %%%%%%%% %%%%%%%% %% %%%%%%%% %% %%%%%% %% %%%% %% %% %%%%%% %%%%%%%%%%%%%% %% %%%%%% %%%% %%%%%% %%%% %% %% %% %%%%%%
345 | %% %%%%%% %% %% %% %%%% %% %%%%%% %% %% %% %% %%%%%% %% %% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%% %% %% %%%%%% %%%% %% %%
346 | %% %% %% %% %% %%%%%% %%%% %% %% %% %% %%%%%%%% %% %%%%%%%%%% %% %% %%%%%%%% %% %% %%%% %% %% %%%%%%%% %% %% %% %% %% %% %% %%%%
347 | %%%%%% %% %% %% %%%%%%%% %%%% %% %%%%%%%% %%%%%%%%%%%% %% %% %% %% %%%%%%%%%%%%%% %%%% %%%%%%%%%% %%%%%% %% %% %% %%%%%%%%%% %%%% %%%%%% %% %%%%
348 | %%%%%% %%%% %%%% %% %%%%%%%%%%%%%% %% %%%%%% %% %% %%%% %%%% %% %%%% %%%%%%%% %% %%%% %%%%%% %%%%%%%% %%%%%% %% %% %%%% %%%% %%%%%% %% %% %%%% %%%%%%
349 | %%%%%%%%%%%%%% %% %%%% %%%%%% %%%% %% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%% %%%% %% %% %%%%%%%% %% %% %% %% %% %%%%
350 | %% %%%% %% %%%%%% %%%% %%%% %%%%%% %% %% %% %%%% %%%%%% %%%%%%%% %% %%%%%%%%%% %%%% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%%%% %% %% %%%%%%%% %% %% %% %% %%
351 | %% %%%%%%%%%%%% %% %% %% %% %% %%%%%%%%%%%%%% %% %% %% %% %%%% %% %%%% %%%%%%%%%%%%%%%%%% %% %%%% %% %%%% %%%%%%%%%% %% %%%% %% %% %%%%%%%%%% %%%%%%
352 | %% %% %%%% %% %% %% %% %% %% %% %% %% %% %%%% %%%% %%%% %% %% %%%% %%%% %% %%%%%%%% %%%% %% %% %% %% %%%% %%%% %% %% %%
353 | %% %%%% %% %%%%%% %%%% %% %% %% %% %% %% %% %% %%%%%% %%%%%%%%%% %% %%%%%% %% %% %% %%%% %% %% %%%%%%%% %% %% %%%%%% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%
354 | %% %%%% %% %%%%%% %%%%%%%% %% %% %%%% %%%%%% %%%%%%%%%% %% %%%%%%%% %% %%%% %%%%%%%% %% %% %%%%%%%% %% %%%%%% %%%% %% %%%%%%%% %% %% %%%%%%%%%% %%%% %%
355 | %% %%%%%%%%%%%%%% %%%% %%%% %% %% %% %% %%%%%%%%%%%%%%%% %%%%%%%% %% %%%%%% %%%% %%%%%% %%%%%%%%%% %%%% %% %%%%%% %% %% %%%%%%%%%%%% %%%% %% %%%%%% %% %%%%%%%%%%%%%%%%%%%%
356 | %% %%%% %% %% %%%%%% %%%%%%%% %% %% %% %% %% %%%%%% %%%% %%%%%%%%%% %%%%%%%% %% %%%%%% %%%% %%%% %%%% %% %%%%%% %% %%%%%% %%%% %% %% %% %% %% %%%%%%%%
357 | %%%% %%%% %%%%%% %% %%%%%%%%%% %%%%%%%%%% %% %%%%%% %%%%%% %% %% %% %% %% %% %% %%%%%%%% %%%% %% %%%%%%%% %%%%%%%% %%%%%%%% %% %% %%%%%%%% %% %%%% %%%% %%
358 | %%%% %% %% %%%% %%%% %% %%%%%% %% %% %%%% %%%% %% %%%% %%%% %% %% %% %%%%%%%% %% %% %%%%%% %% %% %% %%%%%% %%%% %% %%%%%%%% %% %% %% %% %%
359 | %%%% %% %% %% %%%%%%%%%% %%%% %% %%%% %% %% %% %% %% %%%% %% %% %% %%%% %% %%%%%% %% %%%%%% %% %% %% %% %% %% %%%%%%%% %%%% %%%% %%
360 | %%%% %%%% %% %% %% %% %%%% %% %% %% %% %%%%%% %% %% %%%% %% %% %% %% %% %% %%%% %%%% %% %% %% %% %%%%%% %% %% %%%% %% %% %%
361 | %%%%%%%% %%%% %%%%%% %%%% %%%%%%%% %% %%%%%%%%%%%% %% %% %% %%%% %%%%%%%% %%%%%%%% %%%%%%%% %% %% %%%%%%%% %% %% %% %% %% %%%% %% %%%%%%%% %% %% %% %%%% %%%%
362 | %%%% %% %%%%%%%%%% %%%% %%%% %%%% %%%% %% %% %%%%%% %% %%%%%%%%%% %%%%%% %% %%%%%%%% %%%% %% %%%%%%%% %% %% %%%%%% %% %% %%%%%%%% %% %%%%%%%%%%%% %%%%
363 | %%%%%% %%%%%%%% %%%% %% %%%%%%%%%%%%%%%%%% %%%% %% %%%%%% %% %%%% %%%%%% %% %%%%%% %% %%%% %%%%%%%%%% %% %%%%%%%%%%%%%%%% %% %% %% %% %%%% %%%%%%%% %%%% %%%%%% %%%%%%
364 | %% %% %%%% %% %%%% %%%%%%%% %%%% %%%%%%%%%%%% %% %%%%%% %%%%%% %% %% %% %% %%%% %% %% %% %% %%%% %% %%%%%%%% %%%%%% %%%% %%%%%%%% %% %% %%%% %%
365 | %% %% %% %% %% %% %%%% %%%%%%%%%%%% %%%% %% %% %%%%%%%% %% %% %% %% %% %%%%%%%% %% %% %% %% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%
366 | %%%% %% %% %%%% %%%% %% %% %%%%%%%% %% %%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %% %%%%%%%% %% %% %%%%%% %% %%
367 | %% %% %% %% %% %% %%%% %%%% %%%% %% %%%%%% %%%% %% %% %% %%%% %% %%%% %%%%%%%%%% %%%% %% %%%%%% %%%% %% %%%%%%%% %% %% %%%%%% %%%%%%%%%% %% %% %% %%%%
368 | %%%% %% %%%% %% %% %%%% %%%%%%%%%%%% %%%%%% %% %%%%%% %%%%%% %%%% %% %%%%%% %%%%%%%%%% %% %% %%%%%%%%%% %% %%%% %%%% %% %% %% %% %% %% %%%% %%%% %%%%
369 | %%%% %%%%%% %%%%%%%%%%%%%% %%%% %%%% %%%%%%%% %%%%%%%% %% %%%% %%%%%% %% %%%% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%% %%%%%%%% %% %% %%%%%%%% %% %%%% %% %% %%
370 | %%%% %% %%%% %%%% %% %% %% %% %%%%%% %% %%%%%% %%%%%%%%%%%% %% %% %% %% %% %% %%%%%%%% %% %% %%%%%%%%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %%
371 | %% %% %%%%%%%%%% %%%%%%%%%% %%%%%%%% %%%%%%%% %%%% %% %% %%%% %% %% %% %%%%%% %% %%%%%% %% %%%% %% %% %%%% %% %% %%%% %%%% %% %%%% %%
372 | %% %%%% %%%% %% %%%% %% %% %% %%%% %%%% %%%%%%%%%% %% %%%% %% %% %% %% %%%% %% %% %% %% %%%% %%%% %%%% %% %%%% %%%% %% %% %% %% %%
373 | %%%%%% %%%%%% %% %%%%%% %% %% %% %% %%%% %% %%%%%%%% %% %%%% %%%%%%%% %% %%%%%%%% %%%%%%%%%% %%%%%%%% %% %% %%%%%%%% %% %% %% %% %% %% %%%%%%%% %% %% %% %%%% %%%%%%%%
374 | %%%%%% %% %% %%%%%% %%%%%% %%%% %% %%%%%%%% %% %% %%%% %%%%%%%% %% %%%%%%%%%% %%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%%%%%%%%%% %% %% %%%%%%%% %% %%%% %%%%%%%%%%%%%% %%
375 | %% %% %%%%%%%% %%%%%% %%%%%% %% %% %% %% %% %%%%%%%% %%%% %%%% %% %% %% %%%% %%%%%% %%%% %% %% %%%% %% %%%% %%%% %% %% %% %%%% %%%%%% %%
376 | %% %% %%%% %%%%%%%%%% %%%% %%%%%%%%%% %%%%%%%% %% %% %% %%%%%% %%%%%% %%%%%% %%%% %% %% %%%%%%%% %% %%%% %%%% %%%%%% %% %% %%%%%% %% %%%%%% %% %%%% %%
377 | %%%% %% %%%%%%%% %%%%%%%% %% %% %%%%%% %% %% %%%% %% %% %%%%%% %%%%%% %% %%%% %% %% %% %% %%%%%%%% %% %% %%%% %% %% %% %%%%%%%% %% %% %%%%%%%% %%%%
378 | %% %%%%%%%% %% %%%% %% %% %% %%%% %% %% %%%%%%%%%%%%%%%% %%%%%%%%%% %%%%%%%% %% %%%% %%%%%% %%%% %% %%%%%%%% %% %% %% %% %%%%%%%% %% %% %%%%%% %% %% %%
379 | %%%%%% %%%% %%%%%%%%%% %%%%%% %% %%%%%% %%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%% %% %% %%%%%%%%%%%% %%%% %%%%%% %%%%%% %% %%%%%%%%%%%% %%%% %%%%%% %% %% %% %%%%%%%%%% %%%%%%%%%%%%%%%%%%
380 | %% %% %% %%%% %% %%%%%% %% %%%% %%%% %%%% %%%%%% %% %%%% %%%% %%%% %% %%%%%% %%%% %%%%%%%%%% %% %%%% %% %%%% %%%% %%%% %% %%%% %%%%%% %% %%%%%%
381 | %%%%%%%%%%%%%% %%%%%% %%%%%% %%%%%% %% %%%% %% %%%%%%%%%% %% %%%%%%%% %% %% %% %% %% %% %% %%%%%%%% %% %%%% %%%%%% %% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %%%% %%
382 | %% %% %%%% %%%% %%%%%% %% %% %% %% %%%%%% %%%% %% %%%%%% %%%%%% %% %%%% %%%% %% %%%%%%%% %% %% %%%%%%%%%% %% %% %%%%%%%% %% %%%%%%%% %% %%%% %%
383 | %% %%%%%% %% %% %% %% %%%% %%%%%%%%%% %%%%%%%%%%%%%%%% %% %% %% %%%% %% %%%% %% %%%%%%%%%%%% %%%% %%%%%%%% %% %% %% %% %% %%%%%%%%%% %%%% %% %%%%%%%%%% %% %%%%%% %%%%%%%%%%%% %%
384 | %% %%%%%% %% %%%% %% %% %% %% %% %% %%%% %%%%%%%% %%%% %% %% %%%% %%%% %%%% %%%% %%%% %% %%%%%%%% %% %% %% %% %% %%%% %% %%%%%%%%%% %%%%%% %% %%%% %%
385 | %% %%%%%% %% %% %%%%%% %%%%%%%% %%%% %%%% %%%% %%%% %%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %% %%%%%%%%
386 | %% %% %%%% %%%% %% %%%% %% %% %%%% %%%%%% %%%%%%%%%% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %% %%%%%%%% %% %%%%%% %% %%
387 | %%%%%%%%%%%%%% %%%% %% %% %%%% %% %%%%%% %% %% %%%%%%%% %% %%%% %% %%%% %% %%%%%%%% %%%% %% %% %%%% %%%%%% %% %%%% %%%%%% %%%%%% %% %%%%%%
388 |
389 | """)
390 | }
391 |
392 | func testTooLarge() {
393 | for (level, max) in zip(QRErrorCorrectLevel.allCases, [2953, 2331, 1663, 1273]) {
394 | let length = max + 1
395 | print("Try overflow error correct level \(level) with length of \(length)")
396 | let content = randomStringOfUTF8Length(length)
397 | print("Generated random string of length \(content.count), utf8 count \(content.utf8.count)")
398 | XCTAssertThrowsError(try QRCode(content, errorCorrectLevel: level))
399 | }
400 | }
401 |
402 | func testAllLevelMax() throws {
403 | for limits in ([[0, 0, 0, 0]] + QRCodeType.QRCodeLimitLength).lazy.reversed() {
404 | for (level, length) in zip(QRErrorCorrectLevel.allCases, limits) {
405 | print("Try error correct level \(level), utf8 count: \(length)")
406 | let content = randomStringOfUTF8Length(length)
407 | print("Generated a random string, str length: \(content.count)")
408 | XCTAssertNoThrow(try QRCode(content, errorCorrectLevel: level))
409 | }
410 | }
411 | }
412 |
413 | static var allTests = [
414 | ("testSimple", testSimple),
415 | ("testLowErrorCorrectLevel", testLowErrorCorrectLevel),
416 | ("testBorderless", testBorderless),
417 | ("testEFQRCode", testEFQRCode),
418 | ("testEmpty", testEmpty),
419 | ("testStressWithPi", testStressWithPi),
420 | ("testTooLarge", testTooLarge),
421 | ("testAllLevelMax", testAllLevelMax),
422 | ]
423 | }
424 |
--------------------------------------------------------------------------------