From 55fdff472472c9b44a4b8e97c96f16c022ddd27b Mon Sep 17 00:00:00 2001 From: sasos Date: Fri, 21 Mar 2025 09:59:01 +0100 Subject: [PATCH] Add support for FNC1 in first position mode --- Sources/QRCodeGenerator/QRSegment.swift | 8 +++++ .../QRCodeGeneratorTests.swift | 30 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/Sources/QRCodeGenerator/QRSegment.swift b/Sources/QRCodeGenerator/QRSegment.swift index d8aa9cc..80dfee1 100644 --- a/Sources/QRCodeGenerator/QRSegment.swift +++ b/Sources/QRCodeGenerator/QRSegment.swift @@ -158,6 +158,11 @@ public struct QRSegment: Hashable { return QRSegment(mode: .eci, numChars: 0, data: bb.bits) } + /// Returns a segment representing a FNC1 in first position + public static func makeFNC1FirstPosition() -> Self { + return QRSegment(mode: .fnc1FirstPosition, numChars: 0, data: []) + } + /*---- Constructor (low level) ----*/ /// Creates a new QR Code segment with the given attributes and data. @@ -207,6 +212,7 @@ public struct QRSegment: Hashable { case byte case kanji case eci + case fnc1FirstPosition /// Returns an unsigned 4-bit integer value (range 0 to 15) /// representing the mode indicator bits for this mode object. @@ -217,6 +223,7 @@ public struct QRSegment: Hashable { case .byte: return 0x4 case .kanji: return 0x8 case .eci: return 0x7 + case .fnc1FirstPosition: return 0x5 } } @@ -230,6 +237,7 @@ public struct QRSegment: Hashable { case .byte: v = [8, 16, 16] case .kanji: v = [8, 10, 12] case .eci: v = [0, 0, 0] + case .fnc1FirstPosition: v = [0, 0, 0] } return v[(Int(version.value) + 7) / 17] } diff --git a/Tests/QRCodeGeneratorTests/QRCodeGeneratorTests.swift b/Tests/QRCodeGeneratorTests/QRCodeGeneratorTests.swift index fd47213..f5460c9 100644 --- a/Tests/QRCodeGeneratorTests/QRCodeGeneratorTests.swift +++ b/Tests/QRCodeGeneratorTests/QRCodeGeneratorTests.swift @@ -28,6 +28,7 @@ import XCTest final class QRCodeGeneratorTests: XCTestCase { static var allTests = [ ("testQRCodeGeneration", testQRCodeGeneration), + ("testQRCodeGenerationWithFnc1FirstPosition", testQRCodeGenerationWithFnc1FirstPosition), ] func testQRCodeGeneration() throws { @@ -44,4 +45,33 @@ final class QRCodeGeneratorTests: XCTestCase { """) } + + func testQRCodeGenerationWithFnc1FirstPosition() throws { + let text = "Hello World!" + let fnc1Seg = QRSegment.makeFNC1FirstPosition() + let payloadSeg = QRSegment.makeBytes([UInt8](text.data(using: .utf8)!)) + let qr = try QRCode.encode(segments: [fnc1Seg, payloadSeg], ecl: .low) + let svg = qr.toSVGString(border: 4) + + // Is the mode correctly set? + XCTAssertEqual(fnc1Seg.mode, .fnc1FirstPosition) + XCTAssertEqual(fnc1Seg.numChars, 0) + XCTAssertTrue(fnc1Seg.data.isEmpty) + XCTAssertEqual(fnc1Seg.mode.modeBits, 0x5) + + // Checking Number of bits in a length field + XCTAssertEqual(fnc1Seg.mode.numCharCountBits(version: .init(1)), 0) + XCTAssertEqual(fnc1Seg.mode.numCharCountBits(version: .init(10)), 0) + XCTAssertEqual(fnc1Seg.mode.numCharCountBits(version: .init(27)), 0) + + // Checking the SVG output + XCTAssertEqual(svg, """ + + + + + + + """) + } }