using System; namespace DataMatrix4Net { public class DataMatrix { /// /// Public interface /// public bool isContainMatrix { get { return Matrix != null; } } public Gma.QrCodeNet.Encoding.BitMatrix Matrix; /// /// Internal member variables /// readonly SymbolSize chosenSize; readonly bool[,] visited; int width { get { return isContainMatrix ? Matrix.Width : 0; } } int height { get { return isContainMatrix ? Matrix.Height : 0; } } /// /// Data matrix constructor /// Data matrix size up to 26x26 supported, one data region. /// /// Content of the data matrix (ASCII characters only) /// Chosen data matrix size public DataMatrix(string content, SymbolSize symbolSize = SymbolSize.SquareAuto) { byte[] contentBytes = Utils.MakeByteArray(content); if (symbolSize >= 0) { chosenSize = symbolSize; } else if (symbolSize == SymbolSize.SquareAuto) { for (SymbolSize ss = 0; ss < Symbol.SymbolSquareCount; ss++) { if (contentBytes.Length <= Symbol.GetSymbolAttribute(SymbolAttribute.SymbolDataWords, ss)) { chosenSize = ss; break; } } } int w = Symbol.GetSymbolAttribute(SymbolAttribute.SymbolCols, chosenSize); int h = Symbol.GetSymbolAttribute(SymbolAttribute.SymbolRows, chosenSize); if (w == -1 || h == -1) { throw new ArgumentOutOfRangeException("symboSize"); } /// Add padding and Reed-Solomon error correction bytes to the content byte[] data = ReedSolomon.Encode(contentBytes, chosenSize); /// Create matrix, fill in frame cells Matrix = new MyBitMatrix(w, h); visited = new bool[w - 2, h - 2]; MakeFrame(chosenSize); int ix = 0; int x = 0; /// inside data region in the range 0 .. width-2 (x coordinate, frame excluded) int y = 4; /// inside data region in the range 0 .. height-2 (y coordinate, frame excluded) /// Walk through the data matrix area and fill in data bytes do { if (x == 0 && y == height - 2) { PlaceByteSpecial1(data[ix++], width, height); } else if (x == 0 && y == height - 4 && (height - 2) % 4 != 0) { PlaceByteSpecial2(data[ix++], width, height); } else if (x == 0 && y == height - 4 && (height - 2) % 8 == 4) { PlaceByteSpecial3(data[ix++], width, height); } else if (x == 2 && y == height + 2 && (height - 2) % 8 == 0) { PlaceByteSpecial4(data[ix++], width, height); } do { if (x >= 0 && y < height - 2 && !visited[x, y]) { PlaceByteStandard(data[ix++], x, y, width, height); visited[x, y] = true; } x += 2; y -= 2; } while (x < width - 2 && y >= 0); x += 3; y += 1; do { if (x < width - 2 && y >= 0 && !visited[x, y]) { PlaceByteStandard(data[ix++], x, y, width, height); visited[x, y] = true; } x -= 2; y += 2; } while (x >= 0 && y < height - 2); x += 1; y += 3; } while (ix < data.Length); } /// All matrix sizes void PlaceByteSpecial1(byte dataByte, int width, int height) { Matrix[width - 2, 4] = (dataByte & 0x01) != 0; Matrix[width - 2, 3] = (dataByte & 0x02) != 0; Matrix[width - 2, 2] = (dataByte & 0x04) != 0; Matrix[width - 2, 1] = (dataByte & 0x08) != 0; Matrix[width - 3, 1] = (dataByte & 0x10) != 0; Matrix[3, height - 2] = (dataByte & 0x20) != 0; Matrix[2, height - 2] = (dataByte & 0x40) != 0; Matrix[1, height - 2] = (dataByte & 0x80) != 0; visited[width - 3, 3] = true; visited[width - 3, 2] = true; visited[width - 3, 1] = true; visited[width - 3, 0] = true; visited[width - 4, 0] = true; visited[2, height - 3] = true; visited[1, height - 3] = true; visited[0, height - 3] = true; } void PlaceByteSpecial2(byte dataByte, int width, int height) { Matrix[width - 2, 2] = (dataByte & 0x01) != 0; Matrix[width - 2, 1] = (dataByte & 0x02) != 0; Matrix[width - 3, 1] = (dataByte & 0x04) != 0; Matrix[width - 4, 1] = (dataByte & 0x08) != 0; Matrix[width - 5, 1] = (dataByte & 0x10) != 0; Matrix[1, height - 2] = (dataByte & 0x20) != 0; Matrix[1, height - 3] = (dataByte & 0x40) != 0; Matrix[1, height - 4] = (dataByte & 0x80) != 0; visited[width - 3, 1] = true; visited[width - 3, 0] = true; visited[width - 4, 0] = true; visited[width - 5, 0] = true; visited[width - 6, 0] = true; visited[0, height - 3] = true; visited[0, height - 4] = true; visited[0, height - 5] = true; } void PlaceByteSpecial3(byte dataByte, int width, int height) { Matrix[width - 2, 2] = (dataByte & 0x01) != 0; Matrix[width - 3, 2] = (dataByte & 0x02) != 0; Matrix[width - 4, 2] = (dataByte & 0x04) != 0; Matrix[width - 2, 1] = (dataByte & 0x08) != 0; Matrix[width - 3, 1] = (dataByte & 0x10) != 0; Matrix[width - 4, 1] = (dataByte & 0x20) != 0; Matrix[width - 2, height - 2] = (dataByte & 0x40) != 0; Matrix[1, height - 2] = (dataByte & 0x80) != 0; visited[width - 3, 1] = true; visited[width - 4, 1] = true; visited[width - 5, 1] = true; visited[width - 3, 0] = true; visited[width - 4, 0] = true; visited[width - 5, 0] = true; visited[width - 3, height - 3] = true; visited[0, height - 3] = true; } void PlaceByteSpecial4(byte dataByte, int width, int height) { Matrix[width - 2, 4] = (dataByte & 0x01) != 0; Matrix[width - 2, 3] = (dataByte & 0x02) != 0; Matrix[width - 2, 2] = (dataByte & 0x04) != 0; Matrix[width - 2, 1] = (dataByte & 0x08) != 0; Matrix[width - 3, 1] = (dataByte & 0x10) != 0; Matrix[1, height - 2] = (dataByte & 0x20) != 0; Matrix[1, height - 3] = (dataByte & 0x40) != 0; Matrix[1, height - 4] = (dataByte & 0x80) != 0; visited[width - 3, 3] = true; visited[width - 3, 2] = true; visited[width - 3, 1] = true; visited[width - 3, 0] = true; visited[width - 4, 0] = true; visited[0, height - 3] = true; visited[0, height - 4] = true; visited[0, height - 5] = true; } /// /// Standard bit positioning (all matrix sizes) /// int[] xOffs = new int[8] { 1, 0, -1, 1, 0, -1, 0, -1 }; int[] yOffs = new int[8] { 1, 1, 1, 0, 0, 0, -1, -1 }; /// /// Standard placemnt of a byte into a matrix /// /// Data byte /// X-coordinate in range 0..width-2 (from left, frame excluded) /// Y-coordinate in range 0..height-2 (from top, frame excluded) /// Matrix width incl. frame /// Matrix height incl. frame void PlaceByteStandard(byte dataByte, int x, int y, int width, int height) { int mask = 1; for (int i = 0; i < 8; i++) { int xx = x + xOffs[i]; int yy = y + yOffs[i]; if (xx < 1) { xx += width - 2; yy += 4 - (width + 4) % 8; } else if (yy < 1) { xx += 4 - (height + 4) % 8; yy += height - 2; } Matrix[xx, yy] = (dataByte & mask) != 0; mask = mask << 1; } } /// /// Crate data matrix frame. /// All square data matrix sizes supported (incl. 4, 16 and 36 data regions). /// void MakeFrame(SymbolSize size) { int drw = Symbol.GetSymbolAttribute(SymbolAttribute.DataRegionCols, size); int drh = Symbol.GetSymbolAttribute(SymbolAttribute.DataRegionRows, size); int totalhdr = Symbol.GetSymbolAttribute(SymbolAttribute.HorizDataRegions, size); int totalvdr = Symbol.GetSymbolAttribute(SymbolAttribute.VertDataRegions, size); for (int hdr = 0; hdr < totalhdr; hdr++) { for (int vdr = 0; vdr < totalvdr; vdr++) { int offsx = hdr * (drw + 2); int offsy = vdr * (drh + 2); for (int i = 0; i < drw + 2; i++) { Matrix[offsx + i, offsy + drh + 1] = true; if (i % 2 == 0) Matrix[offsx + i, offsy] = true; } for (int j = 0; j < drh + 2; j++) { Matrix[offsx, offsy + j] = true; if (j % 2 == 1) Matrix[offsx + drw + 1, offsy + j] = true; } } } } } }