1 /// 2 module barcode.code39; 3 4 import std.experimental.logger; 5 6 import std.exception; 7 import std..string; 8 import std.range; 9 import std.array; 10 import std.typecons : tuple; 11 12 import barcode.types; 13 import barcode.util; 14 15 /// 16 class Code39 : BarCodeEncoder 17 { 18 pure: 19 /// 20 this(AppendCheckSum acs=AppendCheckSum.no) { appendCheckSum = acs; } 21 22 /// 23 AppendCheckSum appendCheckSum; 24 25 /// 26 override BarCode encode(string str) 27 { 28 checkStr(str); 29 30 BitArray ret; 31 32 void append(char ch) { ret.addBits(table[ch]); } 33 34 append('*'); // start 35 36 ushort checkSum; 37 38 foreach (char c; str) 39 { 40 append(c); 41 checkSum += checkVal[c]; 42 } 43 44 checkSum %= 43; 45 46 if (appendCheckSum) 47 append(checkValInv[checkSum]); 48 49 append('*'); // stop 50 51 return BarCode(ret.length, ret, "code39"); 52 } 53 } 54 55 private: 56 57 void checkStr(string str) pure @safe 58 { 59 foreach (char c; str) 60 { 61 enforce(c != '*', "symbol '*' is not allowed in code39"); 62 enforce(c in table, "symbol '" ~ c ~ "' is not allowed in code39"); 63 } 64 } 65 66 Bits!uint drawMask()(auto ref const Bits!ushort mask) 67 { 68 enum X = 1; 69 enum W = 3; 70 71 uint val; 72 uint cur = X; // past gap 73 74 foreach (i; 0 .. mask.count) 75 { 76 auto black = (i%2) == 0; 77 auto n = mask[i] ? W : X; 78 foreach (k; 0 .. n) 79 val |= black << cur++; 80 } 81 82 return Bits!uint(cur, val); 83 } 84 85 @safe 86 unittest 87 { 88 auto v = drawMask(bitsStr!"--#--#-"); 89 assert(v == bitsStr!"#-###-#---#-"); 90 } 91 92 enum Bits!uint[char] table = src_table.getDict!((i,a) => tuple(a.ch, drawMask(a.mask))); 93 enum ushort[char] checkVal = src_table.getDict!((i,a) => tuple(a.ch, i)); 94 enum char[ushort] checkValInv = src_table.getDict!((i,a) => tuple(cast(ushort)i, a.ch)); 95 96 struct Sym { char ch; Bits!ushort mask; } 97 98 @safe 99 unittest 100 { 101 // W=3 102 assert(table['0'] == bitsStr!"#-#---###-###-#-"); 103 } 104 105 enum src_table = 106 [ // used flags of width lines and gaps: - (narow), # (wide) 107 // width controls in drawMask function (X and W enums) 108 Sym('0', bitsStr!"---##-#--"), 109 Sym('1', bitsStr!"#--#----#"), 110 Sym('2', bitsStr!"--##----#"), 111 Sym('3', bitsStr!"#-##-----"), 112 Sym('4', bitsStr!"---##---#"), 113 Sym('5', bitsStr!"#--##----"), 114 Sym('6', bitsStr!"--###----"), 115 Sym('7', bitsStr!"---#--#-#"), 116 Sym('8', bitsStr!"#--#--#--"), 117 Sym('9', bitsStr!"--##--#--"), 118 Sym('A', bitsStr!"#----#--#"), 119 Sym('B', bitsStr!"--#--#--#"), 120 Sym('C', bitsStr!"#-#--#---"), 121 Sym('D', bitsStr!"----##--#"), 122 Sym('E', bitsStr!"#---##---"), 123 Sym('F', bitsStr!"--#-##---"), 124 Sym('G', bitsStr!"-----##-#"), 125 Sym('H', bitsStr!"#----##--"), 126 Sym('I', bitsStr!"--#--##--"), 127 Sym('J', bitsStr!"----###--"), 128 Sym('K', bitsStr!"#------##"), 129 Sym('L', bitsStr!"--#----##"), 130 Sym('M', bitsStr!"#-#----#-"), 131 Sym('N', bitsStr!"----#--##"), 132 Sym('O', bitsStr!"#---#--#-"), 133 Sym('P', bitsStr!"--#-#--#-"), 134 Sym('Q', bitsStr!"------###"), 135 Sym('R', bitsStr!"#-----##-"), 136 Sym('S', bitsStr!"--#---##-"), 137 Sym('T', bitsStr!"----#-##-"), 138 Sym('U', bitsStr!"##------#"), 139 Sym('V', bitsStr!"-##-----#"), 140 Sym('W', bitsStr!"###------"), 141 Sym('X', bitsStr!"-#--#---#"), 142 Sym('Y', bitsStr!"##--#----"), 143 Sym('Z', bitsStr!"-##-#----"), 144 Sym('-', bitsStr!"-#----#-#"), 145 Sym('.', bitsStr!"##----#--"), 146 Sym(' ', bitsStr!"-##---#--"), 147 Sym('$', bitsStr!"-#-#-#---"), 148 Sym('/', bitsStr!"-#-#---#-"), 149 Sym('+', bitsStr!"-#---#-#-"), 150 Sym('%', bitsStr!"---#-#-#-"), 151 Sym('*', bitsStr!"-#--#-#--") 152 ];