/// <summary> /// Determine right and left padding of float. /// </summary> /// <param name="arguments">Instead of class variables.</param> /// <param name="blankFront"></param> /// <param name="blankEnd"></param> private void FormatFloat(FormatInformation arguments, out int blankFront, out int blankEnd) { int dotPosition = arguments.Items[arguments.Index].IndexOf("."); if (dotPosition != -1) { blankFront = (arguments.IntervalMax == -1) ? 1 : (1 + arguments.IntervalMax - dotPosition); blankEnd = (arguments.FractionMax == -1) ? 0 : (arguments.FractionMax - (arguments.Items[arguments.Index].Length - (dotPosition + 1))); } else { blankFront = (arguments.IntervalMax == -1) ? 1 : 1 + (arguments.IntervalMax - arguments.Items[arguments.Index].Length); blankEnd = (arguments.FractionMax == -1) ? 0 : arguments.FractionMax; if (arguments.DotFound) { blankEnd++; } } }
internal static Version decodeVersionInformation(int versionBits) { int bestDifference = System.Int32.MaxValue; int bestVersion = 0; for (int i = 0; i < VERSION_DECODE_INFO.Length; i++) { int targetVersion = VERSION_DECODE_INFO[i]; // Do the version info bits match exactly? done. if (targetVersion == versionBits) { return(getVersionForNumber(i + 7)); } // Otherwise see if this is the closest to a real version info bit string // we have seen so far int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion); if (bitsDifference < bestDifference) { bestVersion = i + 7; bestDifference = bitsDifference; } } // We can tolerate up to 3 bits of error since no two version info codewords will // differ in less than 4 bits. if (bestDifference <= 3) { return(getVersionForNumber(bestVersion)); } // If we didn't find a close enough match, fail return(null); }
public void testBitsDiffering() { Assert.AreEqual(0, FormatInformation.numBitsDiffering(1, 1)); Assert.AreEqual(1, FormatInformation.numBitsDiffering(0, 2)); Assert.AreEqual(2, FormatInformation.numBitsDiffering(1, 2)); Assert.AreEqual(32, FormatInformation.numBitsDiffering(-1, 0)); }
/// <summary> /// Determine right and left padding of symbol. /// </summary> /// <param name="arguments">Instead of class variables.</param> /// <param name="blankFront"></param> /// <param name="blankEnd"></param> private void FormatSymbol(FormatInformation arguments, out int blankFront, out int blankEnd) { blankFront = 1; blankEnd = (arguments.IntervalMax == -1) ? 0 : (arguments.IntervalMax - arguments.Items[arguments.Index].Length); }
/// <summary> /// Determine right and left padding of integer. /// </summary> /// <param name="arguments">Instead of class variables.</param> /// <param name="blankFront"></param> /// <param name="blankEnd"></param> private void FormatInteger(FormatInformation arguments, out int blankFront, out int blankEnd) { blankFront = (arguments.IntervalMax == -1) ? 1 : (1 + arguments.IntervalMax - arguments.Items[arguments.Index].Length); blankEnd = 0; }
/// <summary> /// Execute padding on all items and make the result character array. /// </summary> /// <param name="shape"></param> /// <param name="arguments">Instead of class variables.</param> /// <returns></returns> private AType FormatArray(List <int> shape, FormatInformation arguments) { AType result = AArray.Create(ATypes.AChar); int rank = shape.Count; if (rank > 0) { for (int i = 0; i < shape[0]; i++) { if (rank > 1) { result.AddWithNoUpdate(FormatArray(shape.GetRange(1, rank - 1), arguments)); } else { result.AddRangeWithNoUpdate(FormatScalar(arguments)); } } result.UpdateInfo(); } else { result.AddRange(FormatScalar(arguments)); } return(result); }
/// <summary> /// Convert item to string. /// </summary> /// <param name="item"></param> /// <param name="info"></param> private string GetItem(AType item, FormatInformation info) { string result; switch (item.Type) { case ATypes.AInteger: result = item.asInteger.ToString(); info.IntervalMax = Math.Max(result.Length, info.IntervalMax); break; case ATypes.ASymbol: result = "`" + item.asString; info.IntervalMax = Math.Max(result.Length, info.IntervalMax); break; default: result = item.asFloat.ToString("g" + info.Precision, CultureInfo.InvariantCulture); int dotPostion = result.IndexOf("."); if (dotPostion != -1) { info.IntervalMax = Math.Max(dotPostion, info.IntervalMax); info.FractionMax = Math.Max(result.Length - (dotPostion + 1), info.FractionMax); info.DotFound = true; } else { info.IntervalMax = Math.Max(result.Length, info.IntervalMax); } break; } return(result); }
public void testDecodeWithMisread() { FormatInformation expected = FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO); Assert.AreEqual(expected, FormatInformation.decodeFormatInformation( MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x0F)); }
public void ValueNameTest() { var expected = RandomValueEx.GetRandomString(); var target = new FormatInformation(expected, null); target.ValueName.Should() .Be(expected); }
public void FormatTest() { var expected = RandomValueEx.GetRandomString(); var target = new FormatInformation("name", expected); target.Format.Should() .Be(expected); }
/// <param name="maskedFormatInfo">format info indicator, with mask still applied /// </param> /// <summary> information about the format it specifies, or <code>null</code> /// if doesn't seem to match any known pattern /// </summary> internal static FormatInformation DecodeFormatInformation(int maskedFormatInfo) { FormatInformation formatInfo = DoDecodeFormatInformation(maskedFormatInfo); return(formatInfo ?? DoDecodeFormatInformation(maskedFormatInfo ^ FORMAT_INFO_MASK_QR)); // Should return null, but, some QR codes apparently // do not mask this info. Try again by actually masking the pattern // first }
public override bool Equals(System.Object o) { if (!(o is FormatInformation)) { return(false); } FormatInformation other = (FormatInformation)o; return(this.m_ErrorCorrectionLevelInternal == other.m_ErrorCorrectionLevelInternal && this.dataMask == other.dataMask); }
public override bool Equals(object obj) { if (!(obj is FormatInformation)) { return(false); } FormatInformation other = (FormatInformation)obj; return(ErrorCorrectionLevel == other.ErrorCorrectionLevel && DataMask == other.DataMask); }
public override bool Equals(object o) { if (!(o is FormatInformation)) { return(false); } FormatInformation other = (FormatInformation)o; return(this.errorCorrectionLevel == other.errorCorrectionLevel && this.dataMask == other.dataMask); }
public void testDecode() { // Normal case FormatInformation expected = FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO); Assert.IsNotNull(expected); Assert.AreEqual((byte)0x07, expected.DataMask); Assert.AreEqual(ErrorCorrectionLevel.Q, expected.ErrorCorrectionLevel); // where the code forgot the mask! Assert.AreEqual(expected, FormatInformation.decodeFormatInformation(UNMASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO)); }
/// <param name="maskedFormatInfo1"> format info indicator, with mask still applied </param> /// <param name="maskedFormatInfo2"> second copy of same info; both are checked at the same time /// to establish best match </param> /// <returns> information about the format it specifies, or {@code null} /// if doesn't seem to match any known pattern </returns> internal static FormatInformation decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) { FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2); if (formatInfo != null) { return(formatInfo); } // Should return null, but, some QR codes apparently // do not mask this info. Try again by actually masking the pattern // first return(doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR, maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR)); }
private AType Compute(AType item, int printingPrecision) { FormatInformation formatInfo = new FormatInformation(item.Type, printingPrecision); DetectLongestSymbol(item, formatInfo); if (item.Rank < 2) { formatInfo.IntervalMax = -1; formatInfo.FractionMax = -1; } return(FormatArray(item.Shape, formatInfo)); }
/// <summary> /// Walk the whole (array) argument to find the longest interval and fraction. /// </summary> /// <param name="argument"></param> /// <param name="formatInfo"></param> private void DetectLongestSymbol(AType argument, FormatInformation formatInfo) { if (argument.IsArray) { foreach (AType item in argument) { DetectLongestSymbol(item, formatInfo); } } else { formatInfo.Items.Add(GetItem(argument, formatInfo)); } }
/// <summary> <p>Reads format information from one of its two locations within the QR Code.</p> /// /// </summary> /// <returns> {@link FormatInformation} encapsulating the QR Code's format info /// </returns> /// <throws> ReaderException if both format information locations cannot be parsed as </throws> /// <summary> the valid encoding of format information /// </summary> internal FormatInformation readFormatInformation() { if (parsedFormatInfo != null) { return parsedFormatInfo; } // Read top-left format info bits int formatInfoBits = 0; for (int i = 0; i < 6; i++) { formatInfoBits = copyBit(i, 8, formatInfoBits); } // .. and skip a bit in the timing pattern ... formatInfoBits = copyBit(7, 8, formatInfoBits); formatInfoBits = copyBit(8, 8, formatInfoBits); formatInfoBits = copyBit(8, 7, formatInfoBits); // .. and skip a bit in the timing pattern ... for (int j = 5; j >= 0; j--) { formatInfoBits = copyBit(8, j, formatInfoBits); } parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits); if (parsedFormatInfo != null) { return parsedFormatInfo; } // Hmm, failed. Try the top-right/bottom-left pattern int dimension = bitMatrix.Dimension; formatInfoBits = 0; int iMin = dimension - 8; for (int i = dimension - 1; i >= iMin; i--) { formatInfoBits = copyBit(i, 8, formatInfoBits); } for (int j = dimension - 7; j < dimension; j++) { formatInfoBits = copyBit(8, j, formatInfoBits); } parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits); if (parsedFormatInfo != null) { return parsedFormatInfo; } throw ReaderException.Instance; }
public void testDecodeWithBitDifference() { FormatInformation expected = FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO); // 1,2,3,4 bits difference Assert.AreEqual(expected, FormatInformation.decodeFormatInformation( MASKED_TEST_FORMAT_INFO ^ 0x01, MASKED_TEST_FORMAT_INFO ^ 0x01)); Assert.AreEqual(expected, FormatInformation.decodeFormatInformation( MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x03)); Assert.AreEqual(expected, FormatInformation.decodeFormatInformation( MASKED_TEST_FORMAT_INFO ^ 0x07, MASKED_TEST_FORMAT_INFO ^ 0x07)); Assert.IsNull(FormatInformation.decodeFormatInformation( MASKED_TEST_FORMAT_INFO ^ 0x0F, MASKED_TEST_FORMAT_INFO ^ 0x0F)); }
public void PlaceFormatInformation(FormatInformation formatInfo) //ToDo create DataBlock/Symbol for Format Info 1 and 2 { var fiBits = formatInfo.GetFormatInfoBits(); var fiLocations = FormatInformation.GetFormatInformationLocations(this.version, FormatInformation.FormatInfoLocation.SplitBottomLeftTopRight); for (int i = 0; i < fiLocations.Count; i++) { this.qrCodeBits[fiLocations[i].X, fiLocations[i].Y] = fiBits[i]; } fiLocations = FormatInformation.GetFormatInformationLocations(this.version, FormatInformation.FormatInfoLocation.TopLeft); for (int i = 0; i < fiLocations.Count; i++) { this.qrCodeBits[fiLocations[i].X, fiLocations[i].Y] = fiBits[i]; } }
/// <summary> <p>Reads format information from one of its two locations within the QR Code.</p> /// /// </summary> /// <returns> {@link FormatInformation} encapsulating the QR Code's format info /// </returns> /// <throws> ReaderException if both format information locations cannot be parsed as </throws> /// <summary> the valid encoding of format information /// </summary> internal FormatInformation ReadFormatInformation() { if (parsedFormatInfo != null) { return(parsedFormatInfo); } // Read top-left format info bits int formatInfoBits1 = 0; for (int i = 0; i < 6; i++) { formatInfoBits1 = CopyBit(i, 8, formatInfoBits1); } // .. and skip a bit in the timing pattern ... formatInfoBits1 = CopyBit(7, 8, formatInfoBits1); formatInfoBits1 = CopyBit(8, 8, formatInfoBits1); formatInfoBits1 = CopyBit(8, 7, formatInfoBits1); // .. and skip a bit in the timing pattern ... for (int j = 5; j >= 0; j--) { formatInfoBits1 = CopyBit(8, j, formatInfoBits1); } // Read the top-right/bottom-left pattern too int dimension = bitMatrix.Height; int formatInfoBits2 = 0; int jMin = dimension - 7; for (int j = dimension - 1; j >= jMin; j--) { formatInfoBits2 = CopyBit(8, j, formatInfoBits2); } for (int i = dimension - 8; i < dimension; i++) { formatInfoBits2 = CopyBit(i, 8, formatInfoBits2); } parsedFormatInfo = FormatInformation.DecodeFormatInformation(formatInfoBits1, formatInfoBits2); if (parsedFormatInfo != null) { return(parsedFormatInfo); } return(null); }
/// <summary> /// Execute padding on actual item (arguments.Items[index]) and /// create a character array. /// </summary> /// <param name="info">Instead of class variables.</param> /// <returns></returns> private AType[] FormatScalar(FormatInformation info) { int blankFront; int blankEnd; int counter = 0; switch (info.Type) { case ATypes.ASymbol: FormatSymbol(info, out blankFront, out blankEnd); break; case ATypes.AInteger: FormatInteger(info, out blankFront, out blankEnd); break; default: FormatFloat(info, out blankFront, out blankEnd); break; } AType[] result = new AType[blankFront + info.Items[info.Index].Length + blankEnd]; for (int i = 0; i < result.Length; i++) { if (i >= blankFront && i < blankFront + info.Items[info.Index].Length) { result[i] = AChar.Create(info.Items[info.Index][counter++]); } else { result[i] = AChar.Create(' '); } } info.Index++; return(result); }
/// <summary> /// Execute padding on all items and make the result character array. /// </summary> /// <param name="shape"></param> /// <param name="arguments">Instead of class variables.</param> /// <returns></returns> private AType FormatArray(List<int> shape, FormatInformation arguments) { AType result = AArray.Create(ATypes.AChar); int rank = shape.Count; if (rank > 0) { for (int i = 0; i < shape[0]; i++) { if (rank > 1) { result.AddWithNoUpdate(FormatArray(shape.GetRange(1, rank - 1), arguments)); } else { result.AddRangeWithNoUpdate(FormatScalar(arguments)); } } result.UpdateInfo(); } else { result.AddRange(FormatScalar(arguments)); } return result; }
/** * Prepare the parser for a mirrored operation. * This flag has effect only on the {@link #readFormatInformation()} and the * {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the * {@link #mirror()} method should be called. * * @param mirror Whether to read version and format information mirrored. */ internal void SetMirror(bool mirror) { parsedVersion = null; parsedFormatInfo = null; mirrored = mirror; }
/// <summary> <p>Reads the bits in the {@link BitMatrix} representing the finder pattern in the /// correct order in order to reconstruct the codewords bytes contained within the /// QR Code.</p> /// /// </summary> /// <returns> bytes encoded within the QR Code /// </returns> /// <throws> ReaderException if the exact number of bytes expected is not read </throws> internal byte[] ReadCodewords() { FormatInformation formatInfo = ReadFormatInformation(); if (formatInfo == null) { return(null); } Version version = ReadVersion(); if (version == null) { return(null); } // Get the data mask for the format used in this QR Code. This will exclude // some bits from reading as we wind through the bit matrix. int dimension = bitMatrix.Height; DataMask.UnmaskBitMatrix(formatInfo.DataMask, bitMatrix, dimension); BitMatrix functionPattern = version.BuildFunctionPattern(); bool readingUp = true; byte[] result = new byte[version.TotalCodewords]; int resultOffset = 0; int currentByte = 0; int bitsRead = 0; // Read columns in pairs, from right to left for (int j = dimension - 1; j > 0; j -= 2) { if (j == 6) { // Skip whole column with vertical alignment pattern; // saves time and makes the other code proceed more cleanly j--; } // Read alternatingly from bottom to top then top to bottom for (int count = 0; count < dimension; count++) { int i = readingUp ? dimension - 1 - count : count; for (int col = 0; col < 2; col++) { // Ignore bits covered by the function pattern if (!functionPattern[j - col, i]) { // Read a bit bitsRead++; currentByte <<= 1; if (bitMatrix[j - col, i]) { currentByte |= 1; } // If we've made a whole byte, save it off if (bitsRead == 8) { result[resultOffset++] = (byte)currentByte; bitsRead = 0; currentByte = 0; } } } } readingUp ^= true; // readingUp = !readingUp; // switch directions } if (resultOffset != version.TotalCodewords) { return(null); } return(result); }
/// <summary> /// Execute padding on actual item (arguments.Items[index]) and /// create a character array. /// </summary> /// <param name="info">Instead of class variables.</param> /// <returns></returns> private AType[] FormatScalar(FormatInformation info) { int blankFront; int blankEnd; int counter = 0; switch (info.Type) { case ATypes.ASymbol: FormatSymbol(info, out blankFront, out blankEnd); break; case ATypes.AInteger: FormatInteger(info, out blankFront, out blankEnd); break; default: FormatFloat(info, out blankFront, out blankEnd); break; } AType[] result = new AType[blankFront + info.Items[info.Index].Length + blankEnd]; for (int i = 0; i < result.Length; i++) { if (i >= blankFront && i < blankFront + info.Items[info.Index].Length) { result[i] = AChar.Create(info.Items[info.Index][counter++]); } else { result[i] = AChar.Create(' '); } } info.Index++; return result; }
private AType Compute(AType item, int printingPrecision) { FormatInformation formatInfo = new FormatInformation(item.Type, printingPrecision); DetectLongestSymbol(item, formatInfo); if (item.Rank < 2) { formatInfo.IntervalMax = -1; formatInfo.FractionMax = -1; } return FormatArray(item.Shape, formatInfo); }
/// <summary> /// Convert item to string. /// </summary> /// <param name="item"></param> /// <param name="info"></param> private string GetItem(AType item, FormatInformation info) { string result; switch (item.Type) { case ATypes.AInteger: result = item.asInteger.ToString(); info.IntervalMax = Math.Max(result.Length, info.IntervalMax); break; case ATypes.ASymbol: result = "`" + item.asString; info.IntervalMax = Math.Max(result.Length, info.IntervalMax); break; default: result = item.asFloat.ToString("g" + info.Precision, CultureInfo.InvariantCulture); int dotPostion = result.IndexOf("."); if (dotPostion != -1) { info.IntervalMax = Math.Max(dotPostion, info.IntervalMax); info.FractionMax = Math.Max(result.Length - (dotPostion + 1), info.FractionMax); info.DotFound = true; } else { info.IntervalMax = Math.Max(result.Length, info.IntervalMax); } break; } return result; }