/// <summary> /// Main constructor /// </summary> /// <param name="codewords">the codewords to place</param> /// <param name="numcols">the number of columns</param> /// <param name="numrows">the number of rows</param> public DefaultPlacement(String codewords, int numcols, int numrows) { this.codewords = codewords; this.numcols = numcols; this.numrows = numrows; this.bits = new byte[numcols * numrows]; SupportClass.Fill(this.bits, (byte)2); //Initialize with "not set" value }
/// <summary> /// Finds the guard pattern. Uses System.Linq.Enumerable.Repeat to fill in counters. This might be a performance issue? /// </summary> /// <returns>start/end horizontal offset of guard pattern, as an array of two ints.</returns> /// <param name="matrix">matrix row of black/white values to search</param> /// <param name="column">column x position to start search.</param> /// <param name="row">row y position to start search.</param> /// <param name="width">width the number of pixels to search on this row.</param> /// <param name="whiteFirst">If set to <c>true</c> search the white patterns first.</param> /// <param name="pattern">pattern of counts of number of black and white pixels that are being searched for as a pattern.</param> /// <param name="counters">counters array of counters, as long as pattern, to re-use .</param> private static int[] findGuardPattern( BitMatrix matrix, int column, int row, int width, bool whiteFirst, int[] pattern, int[] counters) { SupportClass.Fill(counters, 0); var patternStart = column; var pixelDrift = 0; // if there are black pixels left of the current pixel shift to the left, but only for MAX_PIXEL_DRIFT pixels while (matrix[patternStart, row] && patternStart > 0 && pixelDrift++ < MAX_PIXEL_DRIFT) { patternStart--; } var x = patternStart; var counterPosition = 0; var patternLength = pattern.Length; for (var isWhite = whiteFirst; x < width; x++) { var pixel = matrix[x, row]; if (pixel != isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { return(new int[] { patternStart, x }); } patternStart += counters[0] + counters[1]; Array.Copy(counters, 2, counters, 0, counterPosition - 1); counters[counterPosition - 1] = 0; counters[counterPosition] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } if (counterPosition == patternLength - 1 && patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { return(new int[] { patternStart, x - 1 }); } return(null); }
private static int findMinimums(float[] charCounts, int[] intCharCounts, int min, byte[] mins) { SupportClass.Fill(mins, (byte)0); for (int i = 0; i < 6; i++) { intCharCounts[i] = (int)Math.Ceiling(charCounts[i]); int current = intCharCounts[i]; if (min > current) { min = current; SupportClass.Fill(mins, (byte)0); } if (min == current) { mins[i]++; } } return(min); }
/// <summary> ///Performs RS error correction on an array of bits. /// </summary> /// <param name="rawbits">The rawbits.</param> /// <returns>the corrected array</returns> private CorrectedBitsResult correctBits(bool[] rawbits) { GenericGF gf; int codewordSize; if (ddata.NbLayers <= 2) { codewordSize = 6; gf = GenericGF.AZTEC_DATA_6; } else if (ddata.NbLayers <= 8) { codewordSize = 8; gf = GenericGF.AZTEC_DATA_8; } else if (ddata.NbLayers <= 22) { codewordSize = 10; gf = GenericGF.AZTEC_DATA_10; } else { codewordSize = 12; gf = GenericGF.AZTEC_DATA_12; } int numDataCodewords = ddata.NbDatablocks; int numCodewords = rawbits.Length / codewordSize; if (numCodewords < numDataCodewords) { return(null); } int offset = rawbits.Length % codewordSize; int numECCodewords = numCodewords - numDataCodewords; int[] dataWords = new int[numCodewords]; for (int i = 0; i < numCodewords; i++, offset += codewordSize) { dataWords[i] = readCode(rawbits, offset, codewordSize); } var rsDecoder = new ReedSolomonDecoder(gf); if (!rsDecoder.decode(dataWords, numECCodewords)) { return(null); } // Now perform the unstuffing operation. // First, count how many bits are going to be thrown out as stuffing int mask = (1 << codewordSize) - 1; int stuffedBits = 0; for (int i = 0; i < numDataCodewords; i++) { int dataWord = dataWords[i]; if (dataWord == 0 || dataWord == mask) { return(null); } else if (dataWord == 1 || dataWord == mask - 1) { stuffedBits++; } } // Now, actually unpack the bits and remove the stuffing bool[] correctedBits = new bool[numDataCodewords * codewordSize - stuffedBits]; int index = 0; for (int i = 0; i < numDataCodewords; i++) { int dataWord = dataWords[i]; if (dataWord == 1 || dataWord == mask - 1) { // next codewordSize-1 bits are all zeros or all ones SupportClass.Fill(correctedBits, index, index + codewordSize - 1, dataWord > 1); index += codewordSize - 1; } else { for (int bit = codewordSize - 1; bit >= 0; --bit) { correctedBits[index++] = (dataWord & (1 << bit)) != 0; } } } if (index != correctedBits.Length) { return(null); } return(new CorrectedBitsResult(correctedBits, 100 * (numCodewords - numDataCodewords) / numCodewords)); }
static HighLevelEncoder() { CHAR_MAP[0] = new int[256]; CHAR_MAP[1] = new int[256]; CHAR_MAP[2] = new int[256]; CHAR_MAP[3] = new int[256]; CHAR_MAP[4] = new int[256]; SHIFT_TABLE[0] = new int[6]; SHIFT_TABLE[1] = new int[6]; SHIFT_TABLE[2] = new int[6]; SHIFT_TABLE[3] = new int[6]; SHIFT_TABLE[4] = new int[6]; SHIFT_TABLE[5] = new int[6]; CHAR_MAP[MODE_UPPER][' '] = 1; for (int c = 'A'; c <= 'Z'; c++) { CHAR_MAP[MODE_UPPER][c] = c - 'A' + 2; } CHAR_MAP[MODE_LOWER][' '] = 1; for (int c = 'a'; c <= 'z'; c++) { CHAR_MAP[MODE_LOWER][c] = c - 'a' + 2; } CHAR_MAP[MODE_DIGIT][' '] = 1; for (int c = '0'; c <= '9'; c++) { CHAR_MAP[MODE_DIGIT][c] = c - '0' + 2; } CHAR_MAP[MODE_DIGIT][','] = 12; CHAR_MAP[MODE_DIGIT]['.'] = 13; int[] mixedTable = { '\0', ' ', 1, 2, 3, 4, 5, 6, 7, '\b', '\t', '\n', 11, '\f', '\r', 27, 28, 29, 30, 31, '@', '\\', '^', '_', '`', '|', '~', 127 }; for (int i = 0; i < mixedTable.Length; i++) { CHAR_MAP[MODE_MIXED][mixedTable[i]] = i; } int[] punctTable = { '\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}' }; for (int i = 0; i < punctTable.Length; i++) { if (punctTable[i] > 0) { CHAR_MAP[MODE_PUNCT][punctTable[i]] = i; } } foreach (int[] table in SHIFT_TABLE) { SupportClass.Fill(table, -1); } SHIFT_TABLE[MODE_UPPER][MODE_PUNCT] = 0; SHIFT_TABLE[MODE_LOWER][MODE_PUNCT] = 0; SHIFT_TABLE[MODE_LOWER][MODE_UPPER] = 28; SHIFT_TABLE[MODE_MIXED][MODE_PUNCT] = 0; SHIFT_TABLE[MODE_DIGIT][MODE_PUNCT] = 0; SHIFT_TABLE[MODE_DIGIT][MODE_UPPER] = 15; }
internal DataCharacter decodeDataCharacter(BitArray row, FinderPattern pattern, bool isOddPattern, bool leftChar) { int[] counters = getDataCharacterCounters(); SupportClass.Fill(counters, 0); if (leftChar) { if (!recordPatternInReverse(row, pattern.StartEnd[0], counters)) { return(null); } } else { if (!recordPattern(row, pattern.StartEnd[1], counters)) { return(null); } // reverse it for (int i = 0, j = counters.Length - 1; i < j; i++, j--) { int temp = counters[i]; counters[i] = counters[j]; counters[j] = temp; } } //counters[] has the pixels of the module const int numModules = 17; //left and right data characters have all the same length float elementWidth = (float)ZXing.Common.Detector.MathUtils.sum(counters) / (float)numModules; // Sanity check: element width for pattern and the character should match float expectedElementWidth = (pattern.StartEnd[1] - pattern.StartEnd[0]) / 15.0f; if (Math.Abs(elementWidth - expectedElementWidth) / expectedElementWidth > 0.3f) { return(null); } int[] oddCounts = getOddCounts(); int[] evenCounts = getEvenCounts(); float[] oddRoundingErrors = getOddRoundingErrors(); float[] evenRoundingErrors = getEvenRoundingErrors(); for (int i = 0; i < counters.Length; i++) { float divided = 1.0f * counters[i] / elementWidth; int rounded = (int)(divided + 0.5f); // Round if (rounded < 1) { if (divided < 0.3f) { return(null); } rounded = 1; } else if (rounded > 8) { if (divided > 8.7f) { return(null); } rounded = 8; } int offset = i >> 1; if ((i & 0x01) == 0) { oddCounts[offset] = rounded; oddRoundingErrors[offset] = divided - rounded; } else { evenCounts[offset] = rounded; evenRoundingErrors[offset] = divided - rounded; } } if (!adjustOddEvenCounts(numModules)) { return(null); } int weightRowNumber = 4 * pattern.Value + (isOddPattern ? 0 : 2) + (leftChar ? 0 : 1) - 1; int oddSum = 0; int oddChecksumPortion = 0; for (int i = oddCounts.Length - 1; i >= 0; i--) { if (isNotA1left(pattern, isOddPattern, leftChar)) { int weight = WEIGHTS[weightRowNumber][2 * i]; oddChecksumPortion += oddCounts[i] * weight; } oddSum += oddCounts[i]; } int evenChecksumPortion = 0; for (int i = evenCounts.Length - 1; i >= 0; i--) { if (isNotA1left(pattern, isOddPattern, leftChar)) { int weight = WEIGHTS[weightRowNumber][2 * i + 1]; evenChecksumPortion += evenCounts[i] * weight; } } int checksumPortion = oddChecksumPortion + evenChecksumPortion; if ((oddSum & 0x01) != 0 || oddSum > 13 || oddSum < 4) { return(null); } int group = (13 - oddSum) / 2; int oddWidest = SYMBOL_WIDEST[group]; int evenWidest = 9 - oddWidest; int vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, true); int vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, false); int tEven = EVEN_TOTAL_SUBSET[group]; int gSum = GSUM[group]; int value = vOdd * tEven + vEven + gSum; return(new DataCharacter(value, checksumPortion)); }
private static readonly int[] NB_BITS_COMPACT; // total bits per full symbol for a given number of layers static Encoder() { CHAR_MAP[TABLE_UPPER][' '] = 1; for (int c = 'A'; c <= 'Z'; c++) { CHAR_MAP[TABLE_UPPER][c] = c - 'A' + 2; } CHAR_MAP[TABLE_LOWER][' '] = 1; for (int c = 'a'; c <= 'z'; c++) { CHAR_MAP[TABLE_LOWER][c] = c - 'a' + 2; } CHAR_MAP[TABLE_DIGIT][' '] = 1; for (int c = '0'; c <= '9'; c++) { CHAR_MAP[TABLE_DIGIT][c] = c - '0' + 2; } CHAR_MAP[TABLE_DIGIT][','] = 12; CHAR_MAP[TABLE_DIGIT]['.'] = 13; int[] mixedTable = { '\0', ' ', 1, 2, 3, 4, 5, 6, 7, '\b', '\t', '\n', 11, '\f', '\r', 27, 28, 29, 30, 31, '@', '\\', '^', '_', '`', '|', '~', 127 }; for (int i = 0; i < mixedTable.Length; i++) { CHAR_MAP[TABLE_MIXED][mixedTable[i]] = i; } int[] punctTable = { '\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}' }; for (int i = 0; i < punctTable.Length; i++) { if (punctTable[i] > 0) { CHAR_MAP[TABLE_PUNCT][punctTable[i]] = i; } } foreach (int[] table in SHIFT_TABLE) { SupportClass.Fill(table, -1); } foreach (int[] table in LATCH_TABLE) { SupportClass.Fill(table, -1); } SHIFT_TABLE[TABLE_UPPER][TABLE_PUNCT] = 0; LATCH_TABLE[TABLE_UPPER][TABLE_LOWER] = 28; LATCH_TABLE[TABLE_UPPER][TABLE_MIXED] = 29; LATCH_TABLE[TABLE_UPPER][TABLE_DIGIT] = 30; SHIFT_TABLE[TABLE_UPPER][TABLE_BINARY] = 31; SHIFT_TABLE[TABLE_LOWER][TABLE_PUNCT] = 0; SHIFT_TABLE[TABLE_LOWER][TABLE_UPPER] = 28; LATCH_TABLE[TABLE_LOWER][TABLE_MIXED] = 29; LATCH_TABLE[TABLE_LOWER][TABLE_DIGIT] = 30; SHIFT_TABLE[TABLE_LOWER][TABLE_BINARY] = 31; SHIFT_TABLE[TABLE_MIXED][TABLE_PUNCT] = 0; LATCH_TABLE[TABLE_MIXED][TABLE_LOWER] = 28; LATCH_TABLE[TABLE_MIXED][TABLE_UPPER] = 29; LATCH_TABLE[TABLE_MIXED][TABLE_PUNCT] = 30; SHIFT_TABLE[TABLE_MIXED][TABLE_BINARY] = 31; LATCH_TABLE[TABLE_PUNCT][TABLE_UPPER] = 31; SHIFT_TABLE[TABLE_DIGIT][TABLE_PUNCT] = 0; LATCH_TABLE[TABLE_DIGIT][TABLE_UPPER] = 30; SHIFT_TABLE[TABLE_DIGIT][TABLE_UPPER] = 31; NB_BITS_COMPACT = new int[5]; for (int i = 1; i < NB_BITS_COMPACT.Length; i++) { NB_BITS_COMPACT[i] = (88 + 16 * i) * i; } NB_BITS = new int[33]; for (int i = 1; i < NB_BITS.Length; i++) { NB_BITS[i] = (112 + 16 * i) * i; } }
private DataCharacter decodeDataCharacter(BitArray row, FinderPattern pattern, bool outsideChar) { int[] counters = getDataCharacterCounters(); SupportClass.Fill(counters, 0); if (outsideChar) { if (!recordPatternInReverse(row, pattern.StartEnd[0], counters)) { return(null); } } else { if (!recordPattern(row, pattern.StartEnd[1], counters)) { return(null); } // reverse it for (int i = 0, j = counters.Length - 1; i < j; i++, j--) { int temp = counters[i]; counters[i] = counters[j]; counters[j] = temp; } } int numModules = outsideChar ? 16 : 15; float elementWidth = (float)ZXing.Common.Detector.MathUtils.sum(counters) / (float)numModules; int[] oddCounts = this.getOddCounts(); int[] evenCounts = this.getEvenCounts(); float[] oddRoundingErrors = this.getOddRoundingErrors(); float[] evenRoundingErrors = this.getEvenRoundingErrors(); for (int i = 0; i < counters.Length; i++) { float value = (float)counters[i] / elementWidth; int rounded = (int)(value + 0.5f); // Round if (rounded < 1) { rounded = 1; } else if (rounded > 8) { rounded = 8; } int offset = i >> 1; if ((i & 0x01) == 0) { oddCounts[offset] = rounded; oddRoundingErrors[offset] = value - rounded; } else { evenCounts[offset] = rounded; evenRoundingErrors[offset] = value - rounded; } } if (!adjustOddEvenCounts(outsideChar, numModules)) { return(null); } int oddSum = 0; int oddChecksumPortion = 0; for (int i = oddCounts.Length - 1; i >= 0; i--) { oddChecksumPortion *= 9; oddChecksumPortion += oddCounts[i]; oddSum += oddCounts[i]; } int evenChecksumPortion = 0; int evenSum = 0; for (int i = evenCounts.Length - 1; i >= 0; i--) { evenChecksumPortion *= 9; evenChecksumPortion += evenCounts[i]; evenSum += evenCounts[i]; } int checksumPortion = oddChecksumPortion + 3 * evenChecksumPortion; if (outsideChar) { if ((oddSum & 0x01) != 0 || oddSum > 12 || oddSum < 4) { return(null); } int group = (12 - oddSum) / 2; int oddWidest = OUTSIDE_ODD_WIDEST[group]; int evenWidest = 9 - oddWidest; int vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, false); int vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, true); int tEven = OUTSIDE_EVEN_TOTAL_SUBSET[group]; int gSum = OUTSIDE_GSUM[group]; return(new DataCharacter(vOdd * tEven + vEven + gSum, checksumPortion)); } else { if ((evenSum & 0x01) != 0 || evenSum > 10 || evenSum < 4) { return(null); } int group = (10 - evenSum) / 2; int oddWidest = INSIDE_ODD_WIDEST[group]; int evenWidest = 9 - oddWidest; int vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, true); int vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, false); int tOdd = INSIDE_ODD_TOTAL_SUBSET[group]; int gSum = INSIDE_GSUM[group]; return(new DataCharacter(vEven * tOdd + vOdd + gSum, checksumPortion)); } }
/// <summary> /// sets everything to 0 /// </summary> /// <param name="counts"></param> protected static void doClearCounts(int[] counts) { SupportClass.Fill(counts, 0); }