1 /// Interleaved 2 of 5 2 module barcode.itf; 3 4 import std.algorithm; 5 import std.exception; 6 import std..string; 7 import std.range; 8 import std.array; 9 import std.typecons : tuple; 10 import std.ascii; 11 import std.conv : to; 12 13 import barcode.types; 14 import barcode.util; 15 16 /// 17 class ITF : BarCodeEncoder 18 { 19 protected: 20 21 // used flags of width lines and gaps: - (narow), # (wide) 22 // width controls in drawMask function (X and W enums) 23 enum start = bitsStr!"----"; 24 enum stop = bitsStr!"#--"; 25 26 enum Bits!ubyte[10] modules = [ 27 bitsStr!"--##-", 28 bitsStr!"#---#", 29 bitsStr!"-#--#", 30 bitsStr!"##---", 31 bitsStr!"--#-#", 32 bitsStr!"#-#--", 33 bitsStr!"-##--", 34 bitsStr!"---##", 35 bitsStr!"#--#-", 36 bitsStr!"-#-#-", 37 ]; 38 39 public: 40 pure: 41 /// 42 this(AppendCheckSum acs=AppendCheckSum.no) { appendCheckSum = acs; } 43 44 /// 45 AppendCheckSum appendCheckSum; 46 47 /// 48 override BarCode encode(string sdata) 49 { 50 enforce(sdata.all!isDigit, "all symbols must be a numbers"); 51 52 auto data = sdata.map!(a=>cast(ubyte)(a-'0')).array; 53 54 if (appendCheckSum) data ~= checkSum(data); 55 if (data.length%2) data = [ubyte(0)] ~ data; 56 57 assert (data.length%2 == 0); 58 59 BitArray ret; 60 ret.addBits(start.drawMask); 61 62 for (auto i = 0; i < data.length; i+=2) 63 ret.addBits(combine(modules[data[i]], modules[data[i+1]]).drawMask); 64 65 ret.addBits(stop.drawMask); 66 return BarCode(ret.length, ret, "itf"); 67 } 68 } 69 70 private: 71 72 Bits!ulong combine(A, B)(auto ref const Bits!A a, auto ref const Bits!B b) 73 { 74 enforce(a.count == b.count); 75 76 uint val; 77 78 foreach (i; 0..a.count) 79 val |= (b[i] | (a[i] << 1)) << (i*2); 80 81 return Bits!ulong(a.count*2, val); 82 } 83 84 @safe 85 unittest 86 { 87 assert (combine(bitsStr!"##", bitsStr!"--") == bitsStr!"#-#-"); 88 assert (combine(bitsStr!"#-", bitsStr!"-#") == bitsStr!"#--#"); 89 assert (combine(bitsStr!"#", bitsStr!"-") == bitsStr!"#-"); 90 } 91 92 ubyte checkSum(ubyte[] data) pure @safe 93 { 94 uint a, b; 95 96 foreach (i, ch; data) 97 if (i%2) a += ch; 98 else b += ch; 99 100 if (data.length%2) b *= 3; 101 else a *= 3; 102 103 return (10 - (a+b)%10)%10; 104 } 105 106 @safe 107 unittest 108 { 109 assert(checkSum("1937".map!(a=>cast(ubyte)(a-'0')).array) == 8); 110 } 111 112 Bits!ulong drawMask(T)(auto ref const Bits!T mask, bool bar=true) 113 { 114 enum X = 1; 115 enum W = 3; 116 117 uint val, cur; 118 119 bool black = !(bar ^ (mask.count%2)); 120 121 foreach (i; 0 .. mask.count) 122 { 123 foreach (k; 0 .. (mask[i] ? W : X)) 124 val |= black << cur++; 125 black = !black; 126 } 127 128 return Bits!ulong(cur, val); 129 } 130 131 @safe 132 unittest 133 { 134 immutable v1 = ITF.start.drawMask; 135 assert(v1 == bitsStr!"#-#-"); 136 const v2 = ITF.stop.drawMask; 137 assert(v2 == bitsStr!"###-#"); 138 auto v3 = ITF.stop.drawMask(false); 139 assert(v3 == bitsStr!"---#-"); 140 }