From 38aac09b340366ecb0f821bce4ef0762b260a1b1 Mon Sep 17 00:00:00 2001 From: Jia-Han Wu Date: Sun, 5 May 2024 12:30:45 +0800 Subject: [PATCH] Initial commit --- .gitignore | 8 ++++ LICENSE.md | 21 +++++++++ Package.swift | 21 +++++++++ README.md | 49 +++++++++++++++++++++ Sources/Code39/Code39.swift | 77 +++++++++++++++++++++++++++++++++ Sources/Code39/Code39View.swift | 37 ++++++++++++++++ 6 files changed, 213 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 Package.swift create mode 100644 README.md create mode 100644 Sources/Code39/Code39.swift create mode 100644 Sources/Code39/Code39View.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0023a53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..4d0b782 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Jia-Han Wu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..54f3c8d --- /dev/null +++ b/Package.swift @@ -0,0 +1,21 @@ +// swift-tools-version: 5.10 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "swiftui-code39", + platforms: [ + .iOS(.v15), + .macOS(.v12), + ], + products: [ + .library( + name: "Code39", + targets: ["Code39"] + ), + ], + targets: [ + .target(name: "Code39"), + ] +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..efe564a --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# SwiftUI Code39 + +SwiftUI Code39 is a Swift package that provides an easy way to generate Code 39 barcodes in your SwiftUI applications. + +## Installation + +To use SwiftUI Code39 in your project, add the following line to your `Package.swift` file: + +```swift +dependencies: [ + .package(url: "https://github.com/jiahan-wu/swiftui-code39.git", from: "1.0.0") +] +``` + +Then, import the package in your Swift code: + +```swift +import Code39 +``` + +## Usage + +To generate a Code 39 barcode, simply create an instance of `Code39View` and provide the desired content as a string: + +```swift +struct ContentView: View { + var body: some View { + Code39View("HELLO WORLD") + .frame(width: 296, height: 96) + } +} +``` + +## Important Note + +It is the responsibility of the library user to ensure that the content passed to `Code39View` consists of valid characters supported by Code 39. You can use the `code39SupportedCharacters` set to check if a character is supported: + +```swift +let content = "HELLO" +let isValid = content.allSatisfy { code39SupportedCharacters.contains($0) } +``` + +## License + +SwiftUI Code39 is released under the MIT License. See the `LICENSE` file for more information. + +## Contributing + +Contributions to SwiftUI Code39 are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request on the GitHub repository. diff --git a/Sources/Code39/Code39.swift b/Sources/Code39/Code39.swift new file mode 100644 index 0000000..c79f5bd --- /dev/null +++ b/Sources/Code39/Code39.swift @@ -0,0 +1,77 @@ +// The Swift Programming Language +// +// Code39.swift +// +// +// Created by Jia-Han Wu on 2024/5/4. +// + +enum BarWidth { + case narrow + case wide +} + +let code39Patterns: [Character: [BarWidth]] = [ + " ": [.narrow, .wide, .wide, .narrow, .narrow, .narrow, .wide, .narrow, .narrow], + "$": [.narrow, .wide, .narrow, .wide, .narrow, .wide, .narrow, .narrow, .narrow], + "%": [.narrow, .narrow, .narrow, .wide, .narrow, .wide, .narrow, .wide, .narrow], + "*": [.narrow, .wide, .narrow, .narrow, .wide, .narrow, .wide, .narrow, .narrow], + "+": [.narrow, .wide, .narrow, .narrow, .narrow, .wide, .narrow, .wide, .narrow], + "-": [.narrow, .wide, .narrow, .narrow, .narrow, .narrow, .wide, .narrow, .wide], + ".": [ .wide, .wide, .narrow, .narrow, .narrow, .narrow, .wide, .narrow, .narrow], + "/": [.narrow, .wide, .narrow, .wide, .narrow, .narrow, .narrow, .wide, .narrow], + "0": [.narrow, .narrow, .narrow, .wide, .wide, .narrow, .wide, .narrow, .narrow], + "1": [ .wide, .narrow, .narrow, .wide, .narrow, .narrow, .narrow, .narrow, .wide], + "2": [.narrow, .narrow, .wide, .wide, .narrow, .narrow, .narrow, .narrow, .wide], + "3": [ .wide, .narrow, .wide, .wide, .narrow, .narrow, .narrow, .narrow, .narrow], + "4": [.narrow, .narrow, .narrow, .wide, .wide, .narrow, .narrow, .narrow, .wide], + "5": [ .wide, .narrow, .narrow, .wide, .wide, .narrow, .narrow, .narrow, .narrow], + "6": [.narrow, .narrow, .wide, .wide, .wide, .narrow, .narrow, .narrow, .narrow], + "7": [.narrow, .narrow, .narrow, .wide, .narrow, .narrow, .wide, .narrow, .wide], + "8": [ .wide, .narrow, .narrow, .wide, .narrow, .narrow, .wide, .narrow, .narrow], + "9": [.narrow, .narrow, .wide, .wide, .narrow, .narrow, .wide, .narrow, .narrow], + "A": [ .wide, .narrow, .narrow, .narrow, .narrow, .wide, .narrow, .narrow, .wide], + "B": [.narrow, .narrow, .wide, .narrow, .narrow, .wide, .narrow, .narrow, .wide], + "C": [ .wide, .narrow, .wide, .narrow, .narrow, .wide, .narrow, .narrow, .narrow], + "D": [.narrow, .narrow, .narrow, .narrow, .wide, .wide, .narrow, .narrow, .wide], + "E": [ .wide, .narrow, .narrow, .narrow, .wide, .wide, .narrow, .narrow, .narrow], + "F": [.narrow, .narrow, .wide, .narrow, .wide, .wide, .narrow, .narrow, .narrow], + "G": [.narrow, .narrow, .narrow, .narrow, .narrow, .wide, .wide, .narrow, .wide], + "H": [ .wide, .narrow, .narrow, .narrow, .narrow, .wide, .wide, .narrow, .narrow], + "I": [.narrow, .narrow, .wide, .narrow, .narrow, .wide, .wide, .narrow, .narrow], + "J": [.narrow, .narrow, .narrow, .narrow, .wide, .wide, .wide, .narrow, .narrow], + "K": [ .wide, .narrow, .narrow, .narrow, .narrow, .narrow, .narrow, .wide, .wide], + "L": [.narrow, .narrow, .wide, .narrow, .narrow, .narrow, .narrow, .wide, .wide], + "M": [ .wide, .narrow, .wide, .narrow, .narrow, .narrow, .narrow, .wide, .narrow], + "N": [.narrow, .narrow, .narrow, .narrow, .wide, .narrow, .narrow, .wide, .wide], + "O": [ .wide, .narrow, .narrow, .narrow, .wide, .narrow, .narrow, .wide, .narrow], + "P": [.narrow, .narrow, .wide, .narrow, .wide, .narrow, .narrow, .wide, .narrow], + "Q": [.narrow, .narrow, .narrow, .narrow, .narrow, .narrow, .wide, .wide, .wide], + "R": [ .wide, .narrow, .narrow, .narrow, .narrow, .narrow, .wide, .wide, .narrow], + "S": [.narrow, .narrow, .wide, .narrow, .narrow, .narrow, .wide, .wide, .narrow], + "T": [.narrow, .narrow, .narrow, .narrow, .wide, .narrow, .wide, .wide, .narrow], + "U": [ .wide, .wide, .narrow, .narrow, .narrow, .narrow, .narrow, .narrow, .wide], + "V": [.narrow, .wide, .wide, .narrow, .narrow, .narrow, .narrow, .narrow, .wide], + "W": [ .wide, .wide, .wide, .narrow, .narrow, .narrow, .narrow, .narrow, .narrow], + "X": [.narrow, .wide, .narrow, .narrow, .wide, .narrow, .narrow, .narrow, .wide], + "Y": [ .wide, .wide, .narrow, .narrow, .wide, .narrow, .narrow, .narrow, .narrow], + "Z": [.narrow, .wide, .wide, .narrow, .wide, .narrow, .narrow, .narrow, .narrow], +] + +func encodeToCode39(_ input: String) -> [BarWidth] { + var encodedBarcode: [BarWidth] = [] + + encodedBarcode.append(contentsOf: code39Patterns["*"]!) + encodedBarcode.append(.narrow) + + for character in input { + encodedBarcode.append(contentsOf: code39Patterns[character]!) + encodedBarcode.append(.narrow) + } + + encodedBarcode.append(contentsOf: code39Patterns["*"]!) + + return encodedBarcode +} + +public let code39SupportedCharacters: Set = Set(code39Patterns.keys) diff --git a/Sources/Code39/Code39View.swift b/Sources/Code39/Code39View.swift new file mode 100644 index 0000000..51cad95 --- /dev/null +++ b/Sources/Code39/Code39View.swift @@ -0,0 +1,37 @@ +// +// Code39View.swift +// +// +// Created by Jia-Han Wu on 2024/5/4. +// + +import SwiftUI + +public struct Code39View: View { + + private let barcode: [BarWidth] + + public init(_ content: String) { + self.barcode = encodeToCode39(content) + } + + public var body: some View { + Canvas { context, size in + let intercharacterGapCount = barcode.count % 9 + let narrowBarWidth = size.width / CGFloat(((((barcode.count - intercharacterGapCount) / 9) * 15) + intercharacterGapCount)) + var currentX: CGFloat = 0 + for (index, barWidth) in barcode.enumerated() { + let barColor: Color = index % 2 == 0 ? .black : .white + let barWidth: CGFloat = barWidth == .narrow ? narrowBarWidth : narrowBarWidth * 3 + var barPath = Path() + let barRect = CGRect(x: currentX, + y: 0, + width: barWidth, + height: size.height) + currentX += barWidth + barPath.addRect(barRect) + context.fill(barPath, with: .color(barColor)) + } + } + } +}