/// <summary> /// Encode an array of data codeword with GaloisField 256. /// </summary> /// <param name="dataBytes">Array of data codewords for a single block.</param> /// <param name="numECBytes">Number of error correction codewords for data codewords</param> /// <param name="generatorPoly">Cached or newly create GeneratorPolynomial</param> /// <returns>Return error correction codewords array</returns> internal static byte[] Encode(byte[] dataBytes, int numECBytes, GeneratorPolynomial generatorPoly) { int dataLength = dataBytes.Length; if (generatorPoly is null) { throw new ArgumentNullException("generator", $"{nameof(GeneratorPolynomial)} var is null."); } if (dataLength == 0) { throw new ArgumentException("There is no data bytes to encode."); } if (numECBytes <= 0) { throw new ArgumentException("No Error Correction bytes."); } int[] toEncode = ConvertToIntArray(dataBytes, dataLength, numECBytes); Polynomial generator = generatorPoly.GetGenerator(numECBytes); Polynomial dataPoly = new Polynomial(generator.GField, toEncode); PolyDivideStruct divideResult = dataPoly.Divide(generator); int[] remainderCoeffs = divideResult.Remainder.Coefficients; return(ConvertTosByteArray(remainderCoeffs, numECBytes)); }
/// <summary> /// Encode an array of data codeword with GaloisField 256. /// </summary> /// <param name="dataBytes">Array of data codewords for a single block.</param> /// <param name="numECBytes">Number of error correction codewords for data codewords</param> /// <param name="generatorPoly">Cached or newly create GeneratorPolynomial</param> /// <returns>Return error correction codewords array</returns> internal static byte[] Encode(byte[] dataBytes, int numECBytes, GeneratorPolynomial generatorPoly) { int dataLength = dataBytes.Length; if(generatorPoly == null) throw new ArgumentNullException("generator", "GeneratorPolynomial var is null"); if(dataLength == 0) throw new ArgumentException("There is no data bytes to encode"); if(numECBytes <= 0) throw new ArgumentException("No Error Correction bytes"); int[] toEncode = ConvertToIntArray(dataBytes, dataLength, numECBytes); Polynomial generator = generatorPoly.GetGenerator(numECBytes); Polynomial dataPoly = new Polynomial(generator.GField, toEncode); PolyDivideStruct divideResult = dataPoly.Divide(generator); int[] remainderCoeffs = divideResult.Remainder.Coefficients; return ConvertTosByteArray(remainderCoeffs, numECBytes); }
public void PerformanceTest() { Random randomizer = new Random(); sbyte[] zxTestCase = PolynomialExtensions.GenerateSbyteArray(40, randomizer); int ecBytes = 50; byte[] testCase = PolynomialExtensions.ToByteArray(zxTestCase); Stopwatch sw = new Stopwatch(); int timesofTest = 10000; string[] timeElapsed = new string[2]; sw.Start(); GaloisField256 gf256 = GaloisField256.QRCodeGaloisField; GeneratorPolynomial generator = new GeneratorPolynomial(gf256); for(int i = 0; i < timesofTest; i++) { ReedSolomonEncoder.Encode(testCase, ecBytes, generator); } sw.Stop(); timeElapsed[0] = sw.ElapsedMilliseconds.ToString(); sw.Reset(); sw.Start(); for(int i = 0; i < timesofTest; i++) { EncoderInternal.generateECBytes(zxTestCase, ecBytes); } sw.Stop(); timeElapsed[1] = sw.ElapsedMilliseconds.ToString(); Assert.Pass("ReedSolomon performance {0} Tests~ QrCode.Net: {1} ZXing: {2}", timesofTest, timeElapsed[0], timeElapsed[1]); }
/// <summary> /// Generate error correction blocks. Then out put with codewords BitList /// ISO/IEC 18004/2006 P45, 46. Chapter 6.6 Constructing final message codewords sequence. /// </summary> /// <param name="dataCodewords">Datacodewords from DataEncodation.DataEncode</param> /// <param name="numTotalBytes">Total number of bytes</param> /// <param name="numDataBytes">Number of data bytes</param> /// <param name="numECBlocks">Number of Error Correction blocks</param> /// <returns>codewords BitList contain datacodewords and ECCodewords</returns> internal static BitList FillECCodewords(BitList dataCodewords, VersionDetail vd) { List<byte> dataCodewordsByte = dataCodewords.List; int ecBlockGroup2 = vd.ECBlockGroup2; int ecBlockGroup1 = vd.ECBlockGroup1; int numDataBytesGroup1 = vd.NumDataBytesGroup1; int numDataBytesGroup2 = vd.NumDataBytesGroup2; int ecBytesPerBlock = vd.NumECBytesPerBlock; int dataBytesOffset = 0; byte[][] dByteJArray = new byte[vd.NumECBlocks][]; byte[][] ecByteJArray = new byte[vd.NumECBlocks][]; GaloisField256 gf256 = GaloisField256.QRCodeGaloisField; GeneratorPolynomial generator = new GeneratorPolynomial(gf256); for(int blockID = 0; blockID < vd.NumECBlocks; blockID++) { if(blockID < ecBlockGroup1) { dByteJArray[blockID] = new byte[numDataBytesGroup1]; for(int index = 0; index < numDataBytesGroup1; index++) { dByteJArray[blockID][index] = dataCodewordsByte[dataBytesOffset + index]; } dataBytesOffset += numDataBytesGroup1; } else { dByteJArray[blockID] = new byte[numDataBytesGroup2]; for(int index = 0; index < numDataBytesGroup2; index++) { dByteJArray[blockID][index] = dataCodewordsByte[dataBytesOffset + index]; } dataBytesOffset += numDataBytesGroup2; } ecByteJArray[blockID] = ReedSolomonEncoder.Encode(dByteJArray[blockID], ecBytesPerBlock, generator); } if(vd.NumDataBytes != dataBytesOffset) throw new ArgumentException("Data bytes does not match offset"); BitList codewords = new BitList(); int maxDataLength = ecBlockGroup1 == vd.NumECBlocks ? numDataBytesGroup1 : numDataBytesGroup2; for(int dataID = 0; dataID < maxDataLength; dataID++) { for(int blockID = 0; blockID < vd.NumECBlocks; blockID++) { if( !(dataID == numDataBytesGroup1 && blockID < ecBlockGroup1) ) codewords.Add((int)dByteJArray[blockID][dataID], 8); } } for(int ECID = 0; ECID < ecBytesPerBlock; ECID++) { for(int blockID = 0; blockID < vd.NumECBlocks; blockID++) { codewords.Add((int)ecByteJArray[blockID][ECID], 8); } } if( vd.NumTotalBytes != codewords.Count >> 3) throw new ArgumentException(string.Format("total bytes: {0}, actual bits: {1}", vd.NumTotalBytes, codewords.Count)); return codewords; }