From 649f269631d499991cf739d47baef7446fd7eeae Mon Sep 17 00:00:00 2001 From: Daniel White Date: Fri, 30 Aug 2024 12:54:58 +1000 Subject: [PATCH] datamatrix: GS1 DataMatrix support added MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This supports generating a compliant GS1 DataMatrix when the FNC1 character is used as a start character in the barcode. The FNC1 character may also be used as a separator between GS1 element strings that do not have a pre-defined length. From the GS1 DataMatrix guidelines: 2.2.1 Function 1 Symbol Character (FNC1) By definition in ISO/IEC 16022 GS1 DataMatrix uses a special start sequence to differentiate GS1 DataMatrix from other ISO/IEC Data Matrix symbols. This is achieved by using the Function 1 Symbol Character (FNC1) in the first position of the data encoded. It enables scanners to process the information according to the GS1 System Rules. The FNC1 (codeword 232) has two separate uses in GS1 DataMatrix: ■ Start character. ■ Separator character to separate element strings that are not in the predefined list See: https://www.gs1.org/standards/gs1-datamatrix-guideline/25 --- datamatrix/datamatrix_test.go | 30 ++++++++++++++++++++++++++++++ datamatrix/encoder.go | 11 +++++++++++ 2 files changed, 41 insertions(+) diff --git a/datamatrix/datamatrix_test.go b/datamatrix/datamatrix_test.go index 837e630..d418175 100644 --- a/datamatrix/datamatrix_test.go +++ b/datamatrix/datamatrix_test.go @@ -100,3 +100,33 @@ func Test_Issue12(t *testing.T) { } } } + +func Test_GS1DataMatrix(t *testing.T) { + // Example 2 from the GS1 DataMatrix Guideline. + // + // (01)09501101020917(17)190508(10)ABCD1234(21)10 + // + // See: https://www.gs1.org/standards/gs1-datamatrix-guideline/25#2-Encoding-data+2-3-Human-readable-interpretation-(HRI) + data := new(bytes.Buffer) + data.WriteByte(FNC1) // Start Character + data.WriteString("0109501101020917") // AI (01) + data.WriteString("17190508") // AI (17) + data.WriteString("10ABCD1234") // AI (10) does not have pre-defined length + data.WriteByte(FNC1) // Separator Character + data.WriteString("2110") // AI (20) + + // Codewords from decoding example 2 with "dmtxread -c". + wantedData := []byte{ + FNC1, // FNC1 + 131, 139, 180, 141, 131, 132, 139, 147, + 147, 149, 135, 138, + 140, 66, 67, 68, 69, 142, 164, + 232, // FNC1 + 151, 140, + } + + realData := encodeText(data.String()) + if bytes.Compare(realData, wantedData) != 0 { + t.Errorf("GS1 DataMatrix encoding failed\nwant: %v\ngot: %v\n", wantedData, realData) + } +} diff --git a/datamatrix/encoder.go b/datamatrix/encoder.go index 9501bee..5c03e28 100644 --- a/datamatrix/encoder.go +++ b/datamatrix/encoder.go @@ -7,6 +7,13 @@ import ( "github.com/boombuler/barcode" ) +// FNC1 is the codeword for the Function 1 Symbol Character to +// differentiate a GS1 DataMatrix from other Data Matrix symbols. +// +// It is used as both a start character and a separator of GS1 element +// strings. +const FNC1 byte = 232 + // Encode returns a Datamatrix barcode for the given content and color scheme func EncodeWithColor(content string, color barcode.ColorScheme) (barcode.Barcode, error) { data := encodeText(content) @@ -48,6 +55,8 @@ func encodeText(content string) []byte { var result []byte input := []byte(content) + isGS1 := len(input) > 0 && input[0] == FNC1 + for i := 0; i < len(input); { c := input[i] i++ @@ -58,6 +67,8 @@ func encodeText(content string) []byte { i++ cw := byte(((c-'0')*10 + (c2 - '0')) + 130) result = append(result, cw) + } else if isGS1 && c == FNC1 { + result = append(result, c) } else if c > 127 { // not correct... needs to be redone later... result = append(result, 235, c-127)