Skip to content

Commit b108168

Browse files
authored
Merge pull request #34 from TyKonKet/copilot/add-itf-barcode-encoder
Add Interleaved 2 of 5 (ITF) barcode encoder
2 parents 842df97 + 8ce010a commit b108168

File tree

9 files changed

+670
-1
lines changed

9 files changed

+670
-1
lines changed

.github/copilot-instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ BarcodeGenerator is a **.NET barcode library** using SkiaSharp. It supports:
88

99
- EAN-13, UPC-A, UPC-E, ISBN-13, EAN-8
1010
- CODE-39, CODE-93, CODE-128, CODABAR
11+
- Interleaved 2 of 5 (ITF)
1112

1213
The library targets multiple frameworks: **.NET Standard 2.0**, **.NET Framework 4.6.2**, **.NET 6/8/10**.
1314

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ barcode.Export("barcode.png"); // Done! 🎉
3434

3535
## 🚀 Supported Barcode Types
3636

37-
**9 industry-standard formats** for every use case:
37+
**10 industry-standard formats** for every use case:
3838

3939
| Type | Use Case | Example |
4040
|------|----------|---------|
@@ -47,6 +47,7 @@ barcode.Export("barcode.png"); // Done! 🎉
4747
| **CODE-93** | 📋 Logistics, inventory management | `ABC123` |
4848
| **CODE-128** | 📊 High-density alphanumeric encoding | `ABC123xyz` |
4949
| **CODABAR** | 🏥 Libraries, blood banks, logistics | `A123456A` |
50+
| **ITF** | 📦 Distribution, warehousing, cartons | `12345678` |
5051

5152
---
5253

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
using BenchmarkDotNet.Attributes;
2+
using SkiaSharp;
3+
using TyKonKet.BarcodeGenerator.Fonts;
4+
5+
namespace TyKonKet.BarcodeGenerator.Benchmarks.Benchmarks
6+
{
7+
[BenchmarkCategory("CI")]
8+
[Config(typeof(BenchmarkConfig))]
9+
public class Interleaved2of5Encoder
10+
{
11+
private const string BARCODE = "12345678";
12+
13+
private static readonly BarcodeTypes barcodeType = BarcodeTypes.Interleaved2of5;
14+
15+
private const int HEIGHT = 20;
16+
17+
private const int MARGINS = 1;
18+
19+
private const int SCALING = 5;
20+
21+
private static readonly SKColor backgroundColor = SKColors.White;
22+
23+
private static readonly SKColor foregroundColor = SKColors.Black;
24+
25+
private Barcode encodeWithoutTextEncoder;
26+
27+
private Barcode encodeWithTextEncoder;
28+
29+
[Benchmark]
30+
public Barcode SimpleInstance()
31+
{
32+
return new Barcode(options =>
33+
{
34+
options.Type = barcodeType;
35+
options.Height = HEIGHT;
36+
options.Margins = MARGINS;
37+
options.Scaling = SCALING;
38+
options.BackgroundColor = backgroundColor;
39+
options.ForegroundColor = foregroundColor;
40+
options.RenderText = false;
41+
});
42+
}
43+
44+
[Benchmark]
45+
public Barcode AdvancedInstance()
46+
{
47+
return new Barcode(options =>
48+
{
49+
options.Type = barcodeType;
50+
options.Height = HEIGHT;
51+
options.Margins = MARGINS;
52+
options.Scaling = SCALING;
53+
options.BackgroundColor = backgroundColor;
54+
options.ForegroundColor = foregroundColor;
55+
options.RenderText = true;
56+
options.UseTypeface(FontFamilies.DejaVuSerif, SKFontStyle.Normal);
57+
});
58+
}
59+
60+
#region EncodingWithoutText
61+
62+
[GlobalSetup(Target = nameof(EncodingWithoutText))]
63+
public void EncodingWithoutTextSetup()
64+
{
65+
//Console.WriteLine("Setting up the barcode encoder without text...");
66+
//Console.WriteLine();
67+
68+
encodeWithoutTextEncoder = new Barcode(options =>
69+
{
70+
options.Type = barcodeType;
71+
options.Height = HEIGHT;
72+
options.Margins = MARGINS;
73+
options.Scaling = SCALING;
74+
options.BackgroundColor = backgroundColor;
75+
options.ForegroundColor = foregroundColor;
76+
options.RenderText = false;
77+
});
78+
}
79+
80+
[Benchmark]
81+
public string EncodingWithoutText()
82+
{
83+
return encodeWithoutTextEncoder.Encode(BARCODE);
84+
}
85+
86+
[GlobalCleanup(Target = nameof(EncodingWithoutText))]
87+
public void EncodingWithoutTextCleanup()
88+
{
89+
//Console.WriteLine("Cleaning up the barcode encoder without text...");
90+
//Console.WriteLine();
91+
92+
encodeWithoutTextEncoder?.Dispose();
93+
}
94+
95+
#endregion
96+
97+
#region EncodingWithText
98+
99+
[GlobalSetup(Target = nameof(EncodingWithText))]
100+
public void EncodingWithTextSetup()
101+
{
102+
//Console.WriteLine("Setting up the barcode encoder with text...");
103+
//Console.WriteLine();
104+
105+
encodeWithTextEncoder = new Barcode(options =>
106+
{
107+
options.Type = barcodeType;
108+
options.Height = HEIGHT;
109+
options.Margins = MARGINS;
110+
options.Scaling = SCALING;
111+
options.BackgroundColor = backgroundColor;
112+
options.ForegroundColor = foregroundColor;
113+
options.RenderText = true;
114+
});
115+
}
116+
117+
[Benchmark]
118+
public string EncodingWithText()
119+
{
120+
return encodeWithTextEncoder.Encode(BARCODE);
121+
}
122+
123+
[GlobalCleanup(Target = nameof(EncodingWithText))]
124+
public void EncodingWithTextCleanup()
125+
{
126+
//Console.WriteLine("Cleaning up the barcode encoder with text...");
127+
//Console.WriteLine();
128+
129+
encodeWithTextEncoder?.Dispose();
130+
}
131+
132+
#endregion
133+
}
134+
}

src/TyKonKet.BarcodeGenerator/BarcodeTypes.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,11 @@ public enum BarcodeTypes
6565
/// </summary>
6666
[BarcodeEncoding("UPC-E")]
6767
Upce = 9,
68+
69+
/// <summary>
70+
/// Interleaved 2 of 5 (ITF). A high-density numeric barcode used in distribution and warehouse management.
71+
/// </summary>
72+
[BarcodeEncoding("ITF")]
73+
Interleaved2of5 = 10,
6874
}
6975
}

src/TyKonKet.BarcodeGenerator/BarcodeValidator.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ private static bool ValidateCharset(string barcode, BarcodeTypes type)
113113
BarcodeTypes.Code93 => RegexCache.Code93AllowedCharsetRegex,
114114
BarcodeTypes.Code128 => RegexCache.Code128AllowedCharsetRegex,
115115
BarcodeTypes.Codabar => RegexCache.CodabarAllowedCharsetRegex,
116+
BarcodeTypes.Interleaved2of5 => RegexCache.Interleaved2of5AllowedCharsetRegex,
116117
_ => throw new InvalidOperationException($"Unknown barcode type: {type}"),
117118
};
118119

@@ -137,6 +138,7 @@ private static string GetAllowedCharsetDescription(BarcodeTypes type)
137138
BarcodeTypes.Code93 => "uppercase letters (A-Z), digits (0-9), and symbols (- . $ / + % space)",
138139
BarcodeTypes.Code128 => "all ASCII printable characters (space to DEL)",
139140
BarcodeTypes.Codabar => "digits (0-9) and symbols (- $ : / . +)",
141+
BarcodeTypes.Interleaved2of5 => "digits (0-9)",
140142
_ => "unknown",
141143
};
142144
}
@@ -180,6 +182,9 @@ private static string ComputeValidatedBarcodeWithTypeRules(string barcode, Barco
180182
case BarcodeTypes.Codabar:
181183
return CodabarEncoder.FormatBarcode(barcode);
182184

185+
case BarcodeTypes.Interleaved2of5:
186+
return barcode;
187+
183188
default:
184189
throw new InvalidOperationException($"Unknown barcode type: {type}");
185190
}
@@ -239,6 +244,15 @@ private static bool ValidateLength(string barcode, BarcodeTypes type, out string
239244

240245
return true;
241246

247+
case BarcodeTypes.Interleaved2of5:
248+
if (barcode.Length % 2 != 0)
249+
{
250+
error = "Interleaved 2 of 5 requires even-length numeric data.";
251+
return false;
252+
}
253+
254+
return true;
255+
242256
// Non-numeric symbologies have no fixed length constraints
243257
case BarcodeTypes.Code39:
244258
case BarcodeTypes.Code93:
@@ -274,6 +288,7 @@ private static List<BarcodeTypes> FindCompatibleTypes(string barcode, BarcodeTyp
274288
BarcodeTypes.Code93,
275289
BarcodeTypes.Code128,
276290
BarcodeTypes.Codabar,
291+
BarcodeTypes.Interleaved2of5,
277292
};
278293

279294
foreach (var type in allTypes)

0 commit comments

Comments
 (0)