added 2 of 5 barcodes
This commit is contained in:
		
							parent
							
								
									ecbfc39708
								
							
						
					
					
						commit
						bc131f9157
					
				
							
								
								
									
										138
									
								
								twooffive/encoder.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								twooffive/encoder.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,138 @@ | ||||
| // Package twooffive can create interleaved and standard "2 of 5" barcodes. | ||||
| package twooffive | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/boombuler/barcode" | ||||
| 	"github.com/boombuler/barcode/utils" | ||||
| ) | ||||
| 
 | ||||
| const patternWidth = 5 | ||||
| 
 | ||||
| type pattern [patternWidth]bool | ||||
| type encodeInfo struct { | ||||
| 	start  []bool | ||||
| 	end    []bool | ||||
| 	widths map[bool]int | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	encodingTable = map[rune]pattern{ | ||||
| 		'0': pattern{false, false, true, true, false}, | ||||
| 		'1': pattern{true, false, false, false, true}, | ||||
| 		'2': pattern{false, true, false, false, true}, | ||||
| 		'3': pattern{true, true, false, false, false}, | ||||
| 		'4': pattern{false, false, true, false, true}, | ||||
| 		'5': pattern{true, false, true, false, false}, | ||||
| 		'6': pattern{false, true, true, false, false}, | ||||
| 		'7': pattern{false, false, false, true, true}, | ||||
| 		'8': pattern{true, false, false, true, false}, | ||||
| 		'9': pattern{false, true, false, true, false}, | ||||
| 	} | ||||
| 
 | ||||
| 	modes = map[bool]encodeInfo{ | ||||
| 		false: encodeInfo{ // non-interleaved | ||||
| 			start: []bool{true, true, false, true, true, false, true, false}, | ||||
| 			end:   []bool{true, true, false, true, false, true, true}, | ||||
| 			widths: map[bool]int{ | ||||
| 				true:  3, | ||||
| 				false: 1, | ||||
| 			}, | ||||
| 		}, | ||||
| 		true: encodeInfo{ // interleaved | ||||
| 			start: []bool{true, false, true, false}, | ||||
| 			end:   []bool{true, true, false, true}, | ||||
| 			widths: map[bool]int{ | ||||
| 				true:  2, | ||||
| 				false: 1, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	nonInterleavedSpace = pattern{false, false, false, false, false} | ||||
| ) | ||||
| 
 | ||||
| // AddCheckSum calculates the correct check-digit and appends it to the given content. | ||||
| func AddCheckSum(content string) (string, error) { | ||||
| 	if content == "" { | ||||
| 		return "", errors.New("content is empty") | ||||
| 	} | ||||
| 
 | ||||
| 	even := len(content)%2 == 1 | ||||
| 	sum := 0 | ||||
| 	for _, r := range content { | ||||
| 		if _, ok := encodingTable[r]; ok { | ||||
| 			value := utils.RuneToInt(r) | ||||
| 			if even { | ||||
| 				sum += value * 3 | ||||
| 			} else { | ||||
| 				sum += value | ||||
| 			} | ||||
| 			even = !even | ||||
| 		} else { | ||||
| 			return "", fmt.Errorf("can not encode \"%s\"", content) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return content + string(utils.IntToRune(sum%10)), nil | ||||
| } | ||||
| 
 | ||||
| // Encode creates a codabar barcode for the given content | ||||
| func Encode(content string, interleaved bool) (barcode.Barcode, error) { | ||||
| 	if content == "" { | ||||
| 		return nil, errors.New("content is empty") | ||||
| 	} | ||||
| 
 | ||||
| 	if interleaved && len(content)%2 == 1 { | ||||
| 		return nil, errors.New("can only encode even number of digits in interleaved mode") | ||||
| 	} | ||||
| 
 | ||||
| 	mode := modes[interleaved] | ||||
| 	resBits := new(utils.BitList) | ||||
| 	resBits.AddBit(mode.start...) | ||||
| 
 | ||||
| 	var lastRune *rune | ||||
| 	for _, r := range content { | ||||
| 		var a, b pattern | ||||
| 		if interleaved { | ||||
| 			if lastRune == nil { | ||||
| 				lastRune = new(rune) | ||||
| 				*lastRune = r | ||||
| 				continue | ||||
| 			} else { | ||||
| 				var o1, o2 bool | ||||
| 				a, o1 = encodingTable[*lastRune] | ||||
| 				b, o2 = encodingTable[r] | ||||
| 				if !o1 || !o2 { | ||||
| 					return nil, fmt.Errorf("can not encode \"%s\"", content) | ||||
| 				} | ||||
| 				lastRune = nil | ||||
| 			} | ||||
| 		} else { | ||||
| 			var ok bool | ||||
| 			a, ok = encodingTable[r] | ||||
| 			if !ok { | ||||
| 				return nil, fmt.Errorf("can not encode \"%s\"", content) | ||||
| 			} | ||||
| 			b = nonInterleavedSpace | ||||
| 		} | ||||
| 
 | ||||
| 		for i := 0; i < patternWidth; i++ { | ||||
| 			for x := 0; x < mode.widths[a[i]]; x++ { | ||||
| 				resBits.AddBit(true) | ||||
| 			} | ||||
| 			for x := 0; x < mode.widths[b[i]]; x++ { | ||||
| 				resBits.AddBit(false) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	resBits.AddBit(mode.end...) | ||||
| 
 | ||||
| 	kindTxt := "" | ||||
| 	if interleaved { | ||||
| 		kindTxt = " (interleaved)" | ||||
| 	} | ||||
| 	return utils.New1DCode("2 of 5"+kindTxt, content, resBits), nil | ||||
| } | ||||
							
								
								
									
										45
									
								
								twooffive/encoder_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								twooffive/encoder_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| package twooffive | ||||
| 
 | ||||
| import ( | ||||
| 	"image/color" | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func Test_AddCheckSum(t *testing.T) { | ||||
| 	if sum, err := AddCheckSum("1234567"); err != nil || sum != "12345670" { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| 	if _, err := AddCheckSum("1ABC"); err == nil { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| 	if _, err := AddCheckSum(""); err == nil { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func Test_Encode(t *testing.T) { | ||||
| 	_, err := Encode("FOOBAR", false) | ||||
| 	if err == nil { | ||||
| 		t.Error("\"FOOBAR\" should not be encodable") | ||||
| 	} | ||||
| 
 | ||||
| 	testEncode := func(interleaved bool, txt, testResult string) { | ||||
| 		code, err := Encode(txt, interleaved) | ||||
| 		if err != nil || code == nil { | ||||
| 			t.Fail() | ||||
| 		} else { | ||||
| 			if code.Bounds().Max.X != len(testResult) { | ||||
| 				t.Errorf("%v: length missmatch! %v != %v", txt, code.Bounds().Max.X, len(testResult)) | ||||
| 			} else { | ||||
| 				for i, r := range testResult { | ||||
| 					if (code.At(i, 0) == color.Black) != (r == '1') { | ||||
| 						t.Errorf("%v: code missmatch on position %d", txt, i) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	testEncode(false, "12345670", "1101101011101010101110101110101011101110111010101010101110101110111010111010101011101110101010101011101110101011101110101101011") | ||||
| 	testEncode(true, "12345670", "1010110100101011001101101001010011010011001010101010011001101101") | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user