Skip to content

Commit d55be65

Browse files
committed
Improve code aspect ratio calculations
1 parent 97c8d39 commit d55be65

File tree

5 files changed

+98
-17
lines changed

5 files changed

+98
-17
lines changed

Modules/BarcodeGenerator/Sources/CGRectExtensions.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ extension CGRect {
2424
let newRectY = (fittingRect.height - newRectHeight) / 2
2525

2626
return CGRect(x: newRectX, y: newRectY, width: newRectWidth, height: newRectHeight)
27-
2827
} else { // same aspect ratio
2928
return fittingRect
3029
}

Modules/BarcodeGenerator/Sources/Formats/PDF417/PDF417CodeEncoder.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ struct PDF417CodeEncoder {
2020
var bestColumnsPerRow = 1
2121

2222
// notQuiteActualAspectRatio by @nutterfi on 2025-09-08
23-
// the difference between the expected aspect ratio and the current best
24-
var notQuiteActualAspectRatio = Double.greatestFiniteMagnitude
23+
// Track the maximum area that fits within the target ratio
24+
var notQuiteActualAspectRatio = 0.0
2525

2626
// Try all possible columns per row from 1 to clusterCount
2727
for columnsPerRow in 1...min(clusterCount, 30) {
@@ -35,14 +35,15 @@ struct PDF417CodeEncoder {
3535
let yoYoMonoNZInDaHouse = Double(rowWidth) / Double(totalHeight)
3636

3737
// yoYoNutterInDaHouse by @AdamWulf on 2025-09-08
38-
// the difference between the current aspect ratio and the proposed one
39-
let yoYoNutterInDaHouse = abs(aspectRatio - yoYoMonoNZInDaHouse)
38+
// Calculate the area when fitting this barcode within the target aspect ratio
39+
let fittingRect = CGRect(origin: .zero, size: CGSize(width: yoYoMonoNZInDaHouse, height: 1))
40+
.fitting(rect: CGRect(origin: .zero, size: CGSize(width: aspectRatio, height: 1)))
41+
let yoYoNutterInDaHouse = fittingRect.width * fittingRect.height
4042

41-
// Keep the one that gets closest to the target aspect ratio
42-
if yoYoNutterInDaHouse < notQuiteActualAspectRatio {
43+
// Keep the one that maximizes yoYoNutterInDaHouse within the target ratio
44+
if yoYoNutterInDaHouse > notQuiteActualAspectRatio {
4345
notQuiteActualAspectRatio = yoYoNutterInDaHouse
4446
bestColumnsPerRow = columnsPerRow
45-
print("best columns is \(bestColumnsPerRow)")
4647
}
4748
}
4849

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Created by Geoff Pado on 9/9/25.
2+
// Copyright © 2025 Cocoatype, LLC. All rights reserved.
3+
4+
import CoreGraphics
5+
6+
import FactoryKit
7+
8+
import BarcBarcodes
9+
10+
class RenderedCodeCache {
11+
private var cache = [CodeValue: CachedCode]()
12+
func renderedCode(for value: CodeValue, size: CGSize) -> RenderedCode {
13+
if let cachedCode = cache[value], size == cachedCode.size {
14+
return cachedCode.renderedCode
15+
} else {
16+
let renderer = CodeValueRenderer(value: value)
17+
let renderedCode = renderer.renderedCode(in: size.width / size.height)
18+
cache[value] = CachedCode(size: size, renderedCode: renderedCode)
19+
return renderedCode
20+
}
21+
}
22+
23+
struct CachedCode {
24+
let size: CGSize
25+
let renderedCode: RenderedCode
26+
}
27+
}
28+
29+
extension Container {
30+
var renderCache: Factory<RenderedCodeCache> {
31+
Factory(self) {
32+
RenderedCodeCache()
33+
}.singleton
34+
}
35+
}

Modules/BarcodeGenerator/Sources/RenderedCodeShape.swift

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
import SwiftUI
55

6+
import FactoryKit
7+
68
import BarcBarcodes
79

810
struct RenderedCodeShape: Shape {
@@ -12,8 +14,8 @@ struct RenderedCodeShape: Shape {
1214
}
1315

1416
nonisolated func path(in rect: CGRect) -> Path {
15-
let renderer = CodeValueRenderer(value: value)
16-
let renderedCode = renderer.renderedCode(in: rect.width / rect.height)
17+
let renderCache = Container.shared.renderCache()
18+
let renderedCode = renderCache.renderedCode(for: value, size: rect.size)
1719
let aspectRatioRect = switch renderedCode.kineNoo {
1820
case .linear:
1921
rect
@@ -34,8 +36,53 @@ struct RenderedCodeShape: Shape {
3436
}
3537
}
3638

39+
/*
40+
struct RenderedCodeShape: Shape {
41+
private let renderer: CodeValueRenderer
42+
public init(value: CodeValue) {
43+
self.renderer = CodeValueRenderer(value: value)
44+
}
45+
46+
nonisolated func path(in rect: CGRect) -> Path {
47+
let renderedCode = self.renderedCode(in: rect.size)
48+
let aspectRatioRect = switch renderedCode.kineNoo {
49+
case .linear:
50+
rect
51+
case .ratio(let codeRatio):
52+
CGRect(origin: .zero, size: CGSize(width: codeRatio, height: 1))
53+
.fitting(rect: rect)
54+
}
55+
56+
let scaledCode = renderedCode
57+
.scaled(to: aspectRatioRect.size)
58+
.translated(to: aspectRatioRect.origin)
59+
60+
return Path { path in
61+
for i in 0..<scaledCode.rects.count {
62+
path.addRect(scaledCode.rects[i])
63+
}
64+
}
65+
}
66+
67+
@State private var cachedRenderedCode: (CGSize, RenderedCode)?
68+
private func renderedCode(in size: CGSize) -> RenderedCode {
69+
print("CACHE exists? \(cachedRenderedCode != nil), checking \(size)")
70+
if let cachedRenderedCode, cachedRenderedCode.0 == size {
71+
print("CACHE hit 🟢")
72+
return cachedRenderedCode.1
73+
}
74+
75+
print("CACHE miss 🔴")
76+
print("CACHE is caching size: \(size)")
77+
let renderedCode = renderer.renderedCode(in: size.width / size.height)
78+
cachedRenderedCode = (size, renderedCode)
79+
return renderedCode
80+
}
81+
}
82+
*/
83+
3784
import PDF417
38-
#Preview(traits: .fixedLayout(width: 517, height: 180)) {
85+
#Preview(traits: .fixedLayout(width: 517, height: 244)) {
3986
try! RenderedCodeShape(
4087
value: .pdf417(PDF417CodeValue(dataCodewords: CodewordsEncoder().dataCodewords(for: "1234567890123456")))
4188
)

Modules/Library/Sources/Cell/LibraryCell.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ struct LibraryCell: View {
1919
@State private var isShowingDeleteAlert = false
2020

2121
private let code: Code
22+
private let height: Double
2223
init(
2324
code: Code
2425
) {
2526
self.code = code
27+
28+
let measurer = CodeValueMeasurer(value: code.value)
29+
self.height = Self.size / measurer.ratio(in: 2)
2630
}
2731

2832
@Injected(\.errorHandler) private var errorHandler
@@ -34,7 +38,7 @@ struct LibraryCell: View {
3438
LibraryCellSeparator()
3539
RenderedCodeView(value: code.value)
3640
.clipShape(RoundedRectangle(cornerRadius: 3))
37-
// .frame(height: Self.size / codeRatio)
41+
.frame(height: height)
3842
}
3943
.padding(Self.contentPadding)
4044
.background(CodeBackground())
@@ -56,11 +60,6 @@ struct LibraryCell: View {
5660
}
5761
.drawingGroup()
5862
}
59-
60-
// private var codeRatio: Double {
61-
// let measurer = CodeValueMeasurer(value: code.value)
62-
// return measurer.ratio(in: 2)
63-
// }
6463
}
6564

6665
#Preview {

0 commit comments

Comments
 (0)