mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-25 10:56:35 +08:00
添加项目文件。
This commit is contained in:
281
zxing.core/xx/qrcode/decoder/BitMatrixParser.cs
Normal file
281
zxing.core/xx/qrcode/decoder/BitMatrixParser.cs
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using ZXing.Common;
|
||||
|
||||
namespace ZXing.QrCode.Internal
|
||||
{
|
||||
/// <author>Sean Owen</author>
|
||||
sealed class BitMatrixParser
|
||||
{
|
||||
private readonly BitMatrix bitMatrix;
|
||||
private Version parsedVersion;
|
||||
private FormatInformation parsedFormatInfo;
|
||||
private bool mirrored;
|
||||
|
||||
/// <param name="bitMatrix">{@link BitMatrix} to parse</param>
|
||||
/// <throws>ReaderException if dimension is not >= 21 and 1 mod 4</throws>
|
||||
internal static BitMatrixParser createBitMatrixParser(BitMatrix bitMatrix)
|
||||
{
|
||||
int dimension = bitMatrix.Height;
|
||||
if (dimension < 21 || (dimension & 0x03) != 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new BitMatrixParser(bitMatrix);
|
||||
}
|
||||
|
||||
private BitMatrixParser(BitMatrix bitMatrix)
|
||||
{
|
||||
// Should only be called from createBitMatrixParser with the important checks before
|
||||
this.bitMatrix = bitMatrix;
|
||||
}
|
||||
|
||||
/// <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> <p>Reads version information from one of its two locations within the QR Code.</p>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns> {@link Version} encapsulating the QR Code's version
|
||||
/// </returns>
|
||||
/// <throws> ReaderException if both version information locations cannot be parsed as </throws>
|
||||
/// <summary> the valid encoding of version information
|
||||
/// </summary>
|
||||
internal Version readVersion()
|
||||
{
|
||||
if (parsedVersion != null)
|
||||
{
|
||||
return parsedVersion;
|
||||
}
|
||||
|
||||
int dimension = bitMatrix.Height;
|
||||
|
||||
int provisionalVersion = (dimension - 17) >> 2;
|
||||
if (provisionalVersion <= 6)
|
||||
{
|
||||
return Version.getVersionForNumber(provisionalVersion);
|
||||
}
|
||||
|
||||
// Read top-right version info: 3 wide by 6 tall
|
||||
int versionBits = 0;
|
||||
int ijMin = dimension - 11;
|
||||
for (int j = 5; j >= 0; j--)
|
||||
{
|
||||
for (int i = dimension - 9; i >= ijMin; i--)
|
||||
{
|
||||
versionBits = copyBit(i, j, versionBits);
|
||||
}
|
||||
}
|
||||
|
||||
parsedVersion = Version.decodeVersionInformation(versionBits);
|
||||
if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension)
|
||||
{
|
||||
return parsedVersion;
|
||||
}
|
||||
|
||||
// Hmm, failed. Try bottom left: 6 wide by 3 tall
|
||||
versionBits = 0;
|
||||
for (int i = 5; i >= 0; i--)
|
||||
{
|
||||
for (int j = dimension - 9; j >= ijMin; j--)
|
||||
{
|
||||
versionBits = copyBit(i, j, versionBits);
|
||||
}
|
||||
}
|
||||
|
||||
parsedVersion = Version.decodeVersionInformation(versionBits);
|
||||
if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension)
|
||||
{
|
||||
return parsedVersion;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int copyBit(int i, int j, int versionBits)
|
||||
{
|
||||
bool bit = mirrored ? bitMatrix[j, i] : bitMatrix[i, j];
|
||||
return bit ? (versionBits << 1) | 0x1 : versionBits << 1;
|
||||
}
|
||||
|
||||
/// <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.
|
||||
DataMask dataMask = DataMask.forReference(formatInfo.DataMask);
|
||||
int dimension = bitMatrix.Height;
|
||||
dataMask.unmaskBitMatrix(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert the mask removal done while reading the code words. The bit matrix should revert to its original state.
|
||||
*/
|
||||
internal void remask()
|
||||
{
|
||||
if (parsedFormatInfo == null)
|
||||
{
|
||||
return; // We have no format information, and have no data mask
|
||||
}
|
||||
DataMask dataMask = DataMask.forReference(parsedFormatInfo.DataMask);
|
||||
int dimension = bitMatrix.Height;
|
||||
dataMask.unmaskBitMatrix(bitMatrix, dimension);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/** Mirror the bit matrix in order to attempt a second reading. */
|
||||
internal void mirror()
|
||||
{
|
||||
for (int x = 0; x < bitMatrix.Width; x++)
|
||||
{
|
||||
for (int y = x + 1; y < bitMatrix.Height; y++)
|
||||
{
|
||||
if (bitMatrix[x, y] != bitMatrix[y, x])
|
||||
{
|
||||
bitMatrix.flip(y, x);
|
||||
bitMatrix.flip(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
146
zxing.core/xx/qrcode/decoder/DataBlock.cs
Normal file
146
zxing.core/xx/qrcode/decoder/DataBlock.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace ZXing.QrCode.Internal
|
||||
{
|
||||
/// <summary> <p>Encapsulates a block of data within a QR Code. QR Codes may split their data into
|
||||
/// multiple blocks, each of which is a unit of data and error-correction codewords. Each
|
||||
/// is represented by an instance of this class.</p>
|
||||
///
|
||||
/// </summary>
|
||||
/// <author> Sean Owen
|
||||
/// </author>
|
||||
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
|
||||
/// </author>
|
||||
internal sealed class DataBlock
|
||||
{
|
||||
private readonly int numDataCodewords;
|
||||
private readonly byte[] codewords;
|
||||
|
||||
private DataBlock(int numDataCodewords, byte[] codewords)
|
||||
{
|
||||
this.numDataCodewords = numDataCodewords;
|
||||
this.codewords = codewords;
|
||||
}
|
||||
|
||||
/// <summary> <p>When QR Codes use multiple data blocks, they are actually interleaved.
|
||||
/// That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
|
||||
/// method will separate the data into original blocks.</p>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="rawCodewords">bytes as read directly from the QR Code
|
||||
/// </param>
|
||||
/// <param name="version">version of the QR Code
|
||||
/// </param>
|
||||
/// <param name="ecLevel">error-correction level of the QR Code
|
||||
/// </param>
|
||||
/// <returns> {@link DataBlock}s containing original bytes, "de-interleaved" from representation in the
|
||||
/// QR Code
|
||||
/// </returns>
|
||||
internal static DataBlock[] getDataBlocks(byte[] rawCodewords, Version version, ErrorCorrectionLevel ecLevel)
|
||||
{
|
||||
|
||||
if (rawCodewords.Length != version.TotalCodewords)
|
||||
{
|
||||
throw new System.ArgumentException();
|
||||
}
|
||||
|
||||
// Figure out the number and size of data blocks used by this version and
|
||||
// error correction level
|
||||
Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);
|
||||
|
||||
// First count the total number of data blocks
|
||||
int totalBlocks = 0;
|
||||
Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();
|
||||
foreach (var ecBlock in ecBlockArray)
|
||||
{
|
||||
totalBlocks += ecBlock.Count;
|
||||
}
|
||||
|
||||
// Now establish DataBlocks of the appropriate size and number of data codewords
|
||||
DataBlock[] result = new DataBlock[totalBlocks];
|
||||
int numResultBlocks = 0;
|
||||
foreach (var ecBlock in ecBlockArray)
|
||||
{
|
||||
for (int i = 0; i < ecBlock.Count; i++)
|
||||
{
|
||||
int numDataCodewords = ecBlock.DataCodewords;
|
||||
int numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords;
|
||||
result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]);
|
||||
}
|
||||
}
|
||||
|
||||
// All blocks have the same amount of data, except that the last n
|
||||
// (where n may be 0) have 1 more byte. Figure out where these start.
|
||||
int shorterBlocksTotalCodewords = result[0].codewords.Length;
|
||||
int longerBlocksStartAt = result.Length - 1;
|
||||
while (longerBlocksStartAt >= 0)
|
||||
{
|
||||
int numCodewords = result[longerBlocksStartAt].codewords.Length;
|
||||
if (numCodewords == shorterBlocksTotalCodewords)
|
||||
{
|
||||
break;
|
||||
}
|
||||
longerBlocksStartAt--;
|
||||
}
|
||||
longerBlocksStartAt++;
|
||||
|
||||
int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock;
|
||||
// The last elements of result may be 1 element longer;
|
||||
// first fill out as many elements as all of them have
|
||||
int rawCodewordsOffset = 0;
|
||||
for (int i = 0; i < shorterBlocksNumDataCodewords; i++)
|
||||
{
|
||||
for (int j = 0; j < numResultBlocks; j++)
|
||||
{
|
||||
result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
}
|
||||
// Fill out the last data block in the longer ones
|
||||
for (int j = longerBlocksStartAt; j < numResultBlocks; j++)
|
||||
{
|
||||
result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
// Now add in error correction blocks
|
||||
int max = result[0].codewords.Length;
|
||||
for (int i = shorterBlocksNumDataCodewords; i < max; i++)
|
||||
{
|
||||
for (int j = 0; j < numResultBlocks; j++)
|
||||
{
|
||||
int iOffset = j < longerBlocksStartAt ? i : i + 1;
|
||||
result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int NumDataCodewords
|
||||
{
|
||||
get
|
||||
{
|
||||
return numDataCodewords;
|
||||
}
|
||||
}
|
||||
|
||||
internal byte[] Codewords
|
||||
{
|
||||
get
|
||||
{
|
||||
return codewords;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
165
zxing.core/xx/qrcode/decoder/DataMask.cs
Normal file
165
zxing.core/xx/qrcode/decoder/DataMask.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using ZXing.Common;
|
||||
|
||||
namespace ZXing.QrCode.Internal
|
||||
{
|
||||
/// <summary> <p>Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations
|
||||
/// of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix,
|
||||
/// including areas used for finder patterns, timing patterns, etc. These areas should be unused
|
||||
/// after the point they are unmasked anyway.</p>
|
||||
///
|
||||
/// <p>Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position
|
||||
/// and j is row position. In fact, as the text says, i is row position and j is column position.</p>
|
||||
///
|
||||
/// </summary>
|
||||
/// <author> Sean Owen
|
||||
/// </author>
|
||||
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
|
||||
/// </author>
|
||||
abstract class DataMask
|
||||
{
|
||||
/// <summary> See ISO 18004:2006 6.8.1</summary>
|
||||
private static readonly DataMask[] DATA_MASKS = new DataMask[]
|
||||
{
|
||||
new DataMask000(),
|
||||
new DataMask001(),
|
||||
new DataMask010(),
|
||||
new DataMask011(),
|
||||
new DataMask100(),
|
||||
new DataMask101(),
|
||||
new DataMask110(),
|
||||
new DataMask111()
|
||||
};
|
||||
|
||||
private DataMask()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary> <p>Implementations of this method reverse the data masking process applied to a QR Code and
|
||||
/// make its bits ready to read.</p>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="bits">representation of QR Code bits
|
||||
/// </param>
|
||||
/// <param name="dimension">dimension of QR Code, represented by bits, being unmasked
|
||||
/// </param>
|
||||
internal void unmaskBitMatrix(BitMatrix bits, int dimension)
|
||||
{
|
||||
for (int i = 0; i < dimension; i++)
|
||||
{
|
||||
for (int j = 0; j < dimension; j++)
|
||||
{
|
||||
if (isMasked(i, j))
|
||||
{
|
||||
bits.flip(j, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract bool isMasked(int i, int j);
|
||||
|
||||
/// <param name="reference">a value between 0 and 7 indicating one of the eight possible
|
||||
/// data mask patterns a QR Code may use
|
||||
/// </param>
|
||||
/// <returns> {@link DataMask} encapsulating the data mask pattern
|
||||
/// </returns>
|
||||
internal static DataMask forReference(int reference)
|
||||
{
|
||||
if (reference < 0 || reference > 7)
|
||||
{
|
||||
throw new System.ArgumentException();
|
||||
}
|
||||
return DATA_MASKS[reference];
|
||||
}
|
||||
|
||||
/// <summary> 000: mask bits for which (x + y) mod 2 == 0</summary>
|
||||
private sealed class DataMask000 : DataMask
|
||||
{
|
||||
internal override bool isMasked(int i, int j)
|
||||
{
|
||||
return ((i + j) & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> 001: mask bits for which x mod 2 == 0</summary>
|
||||
private sealed class DataMask001 : DataMask
|
||||
{
|
||||
internal override bool isMasked(int i, int j)
|
||||
{
|
||||
return (i & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> 010: mask bits for which y mod 3 == 0</summary>
|
||||
private sealed class DataMask010 : DataMask
|
||||
{
|
||||
internal override bool isMasked(int i, int j)
|
||||
{
|
||||
return j % 3 == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> 011: mask bits for which (x + y) mod 3 == 0</summary>
|
||||
private sealed class DataMask011 : DataMask
|
||||
{
|
||||
internal override bool isMasked(int i, int j)
|
||||
{
|
||||
return (i + j) % 3 == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> 100: mask bits for which (x/2 + y/3) mod 2 == 0</summary>
|
||||
private sealed class DataMask100 : DataMask
|
||||
{
|
||||
internal override bool isMasked(int i, int j)
|
||||
{
|
||||
return ((((int)((uint)i >> 1)) + (j / 3)) & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> 101: mask bits for which xy mod 2 + xy mod 3 == 0</summary>
|
||||
private sealed class DataMask101 : DataMask
|
||||
{
|
||||
internal override bool isMasked(int i, int j)
|
||||
{
|
||||
int temp = i * j;
|
||||
return (temp & 0x01) + (temp % 3) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0</summary>
|
||||
private sealed class DataMask110 : DataMask
|
||||
{
|
||||
internal override bool isMasked(int i, int j)
|
||||
{
|
||||
int temp = i * j;
|
||||
return (((temp & 0x01) + (temp % 3)) & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0</summary>
|
||||
private sealed class DataMask111 : DataMask
|
||||
{
|
||||
internal override bool isMasked(int i, int j)
|
||||
{
|
||||
return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
524
zxing.core/xx/qrcode/decoder/DecodedBitStreamParser.cs
Normal file
524
zxing.core/xx/qrcode/decoder/DecodedBitStreamParser.cs
Normal file
@@ -0,0 +1,524 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using ZXing.Common;
|
||||
|
||||
namespace ZXing.QrCode.Internal
|
||||
{
|
||||
/// <summary> <p>QR Codes can encode text as bits in one of several modes, and can use multiple modes
|
||||
/// in one QR Code. This class decodes the bits back into text.</p>
|
||||
///
|
||||
/// <p>See ISO 18004:2006, 6.4.3 - 6.4.7</p>
|
||||
/// <author>Sean Owen</author>
|
||||
/// </summary>
|
||||
internal static class DecodedBitStreamParser
|
||||
{
|
||||
/// <summary>
|
||||
/// See ISO 18004:2006, 6.4.4 Table 5
|
||||
/// </summary>
|
||||
private static readonly char[] ALPHANUMERIC_CHARS = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
|
||||
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
' ', '$', '%', '*', '+', '-', '.', '/', ':'
|
||||
};
|
||||
private const int GB2312_SUBSET = 1;
|
||||
|
||||
internal static DecoderResult decode(byte[] bytes,
|
||||
Version version,
|
||||
ErrorCorrectionLevel ecLevel,
|
||||
IDictionary<DecodeHintType, object> hints)
|
||||
{
|
||||
var bits = new BitSource(bytes);
|
||||
var result = new StringBuilder(50);
|
||||
var byteSegments = new List<byte[]>(1);
|
||||
var symbolSequence = -1;
|
||||
var parityData = -1;
|
||||
|
||||
try
|
||||
{
|
||||
CharacterSetECI currentCharacterSetECI = null;
|
||||
bool fc1InEffect = false;
|
||||
Mode mode;
|
||||
do
|
||||
{
|
||||
// While still another segment to read...
|
||||
if (bits.available() < 4)
|
||||
{
|
||||
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
|
||||
mode = Mode.TERMINATOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (mode != Mode.TERMINATOR)
|
||||
{
|
||||
if (mode == Mode.FNC1_FIRST_POSITION || mode == Mode.FNC1_SECOND_POSITION)
|
||||
{
|
||||
// We do little with FNC1 except alter the parsed result a bit according to the spec
|
||||
fc1InEffect = true;
|
||||
}
|
||||
else if (mode == Mode.STRUCTURED_APPEND)
|
||||
{
|
||||
if (bits.available() < 16)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// not really supported; but sequence number and parity is added later to the result metadata
|
||||
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
|
||||
symbolSequence = bits.readBits(8);
|
||||
parityData = bits.readBits(8);
|
||||
}
|
||||
else if (mode == Mode.ECI)
|
||||
{
|
||||
// Count doesn't apply to ECI
|
||||
int value = parseECIValue(bits);
|
||||
currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
|
||||
if (currentCharacterSetECI == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// First handle Hanzi mode which does not start with character count
|
||||
if (mode == Mode.HANZI)
|
||||
{
|
||||
//chinese mode contains a sub set indicator right after mode indicator
|
||||
int subset = bits.readBits(4);
|
||||
int countHanzi = bits.readBits(mode.getCharacterCountBits(version));
|
||||
if (subset == GB2312_SUBSET)
|
||||
{
|
||||
if (!decodeHanziSegment(bits, result, countHanzi))
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// "Normal" QR code modes:
|
||||
// How many characters will follow, encoded in this mode?
|
||||
int count = bits.readBits(mode.getCharacterCountBits(version));
|
||||
if (mode == Mode.NUMERIC)
|
||||
{
|
||||
if (!decodeNumericSegment(bits, result, count))
|
||||
return null;
|
||||
}
|
||||
else if (mode == Mode.ALPHANUMERIC)
|
||||
{
|
||||
if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect))
|
||||
return null;
|
||||
}
|
||||
else if (mode == Mode.BYTE)
|
||||
{
|
||||
if (!decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints))
|
||||
return null;
|
||||
}
|
||||
else if (mode == Mode.KANJI)
|
||||
{
|
||||
if (!decodeKanjiSegment(bits, result, count))
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (mode != Mode.TERMINATOR);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// from readBits() calls
|
||||
return null;
|
||||
}
|
||||
|
||||
#if WindowsCE
|
||||
var resultString = result.ToString().Replace("\n", "\r\n");
|
||||
#else
|
||||
var resultString = result.ToString().Replace("\r\n", "\n").Replace("\n", Environment.NewLine);
|
||||
#endif
|
||||
return new DecoderResult(bytes,
|
||||
resultString,
|
||||
byteSegments.Count == 0 ? null : byteSegments,
|
||||
ecLevel == null ? null : ecLevel.ToString(),
|
||||
symbolSequence, parityData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See specification GBT 18284-2000
|
||||
/// </summary>
|
||||
/// <param name="bits">The bits.</param>
|
||||
/// <param name="result">The result.</param>
|
||||
/// <param name="count">The count.</param>
|
||||
/// <returns></returns>
|
||||
private static bool decodeHanziSegment(BitSource bits,
|
||||
StringBuilder result,
|
||||
int count)
|
||||
{
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if (count * 13 > bits.available())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
||||
// and decode as GB2312 afterwards
|
||||
byte[] buffer = new byte[2 * count];
|
||||
int offset = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
// Each 13 bits encodes a 2-byte character
|
||||
int twoBytes = bits.readBits(13);
|
||||
int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060);
|
||||
if (assembledTwoBytes < 0x003BF)
|
||||
{
|
||||
// In the 0xA1A1 to 0xAAFE range
|
||||
assembledTwoBytes += 0x0A1A1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In the 0xB0A1 to 0xFAFE range
|
||||
assembledTwoBytes += 0x0A6A1;
|
||||
}
|
||||
buffer[offset] = (byte)((assembledTwoBytes >> 8) & 0xFF);
|
||||
buffer[offset + 1] = (byte)(assembledTwoBytes & 0xFF);
|
||||
offset += 2;
|
||||
count--;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result.Append(Encoding.GetEncoding(StringUtils.GB2312).GetString(buffer, 0, buffer.Length));
|
||||
}
|
||||
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH)
|
||||
catch (ArgumentException)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Silverlight only supports a limited number of character sets, trying fallback to UTF-8
|
||||
result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool decodeKanjiSegment(BitSource bits,
|
||||
StringBuilder result,
|
||||
int count)
|
||||
{
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if (count * 13 > bits.available())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
||||
// and decode as Shift_JIS afterwards
|
||||
byte[] buffer = new byte[2 * count];
|
||||
int offset = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
// Each 13 bits encodes a 2-byte character
|
||||
int twoBytes = bits.readBits(13);
|
||||
int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);
|
||||
if (assembledTwoBytes < 0x01F00)
|
||||
{
|
||||
// In the 0x8140 to 0x9FFC range
|
||||
assembledTwoBytes += 0x08140;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In the 0xE040 to 0xEBBF range
|
||||
assembledTwoBytes += 0x0C140;
|
||||
}
|
||||
buffer[offset] = (byte)(assembledTwoBytes >> 8);
|
||||
buffer[offset + 1] = (byte)assembledTwoBytes;
|
||||
offset += 2;
|
||||
count--;
|
||||
}
|
||||
// Shift_JIS may not be supported in some environments:
|
||||
try
|
||||
{
|
||||
result.Append(Encoding.GetEncoding(StringUtils.SHIFT_JIS).GetString(buffer, 0, buffer.Length));
|
||||
}
|
||||
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH)
|
||||
catch (ArgumentException)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Silverlight only supports a limited number of character sets, trying fallback to UTF-8
|
||||
result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool decodeByteSegment(BitSource bits,
|
||||
StringBuilder result,
|
||||
int count,
|
||||
CharacterSetECI currentCharacterSetECI,
|
||||
IList<byte[]> byteSegments,
|
||||
IDictionary<DecodeHintType, object> hints)
|
||||
{
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if (count << 3 > bits.available())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] readBytes = new byte[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
readBytes[i] = (byte)bits.readBits(8);
|
||||
}
|
||||
String encoding;
|
||||
if (currentCharacterSetECI == null)
|
||||
{
|
||||
// The spec isn't clear on this mode; see
|
||||
// section 6.4.5: t does not say which encoding to assuming
|
||||
// upon decoding. I have seen ISO-8859-1 used as well as
|
||||
// Shift_JIS -- without anything like an ECI designator to
|
||||
// give a hint.
|
||||
encoding = StringUtils.guessEncoding(readBytes, hints);
|
||||
}
|
||||
else
|
||||
{
|
||||
encoding = currentCharacterSetECI.EncodingName;
|
||||
}
|
||||
try
|
||||
{
|
||||
result.Append(Encoding.GetEncoding(encoding).GetString(readBytes, 0, readBytes.Length));
|
||||
}
|
||||
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH)
|
||||
catch (ArgumentException)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Silverlight only supports a limited number of character sets, trying fallback to UTF-8
|
||||
result.Append(Encoding.GetEncoding("UTF-8").GetString(readBytes, 0, readBytes.Length));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if WindowsCE
|
||||
catch (PlatformNotSupportedException)
|
||||
{
|
||||
try
|
||||
{
|
||||
// WindowsCE doesn't support all encodings. But it is device depended.
|
||||
// So we try here the some different ones
|
||||
if (encoding == "ISO-8859-1")
|
||||
{
|
||||
result.Append(Encoding.GetEncoding(1252).GetString(readBytes, 0, readBytes.Length));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Append(Encoding.GetEncoding("UTF-8").GetString(readBytes, 0, readBytes.Length));
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
byteSegments.Add(readBytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static char toAlphaNumericChar(int value)
|
||||
{
|
||||
if (value >= ALPHANUMERIC_CHARS.Length)
|
||||
{
|
||||
throw FormatException.Instance;
|
||||
}
|
||||
return ALPHANUMERIC_CHARS[value];
|
||||
}
|
||||
|
||||
private static bool decodeAlphanumericSegment(BitSource bits,
|
||||
StringBuilder result,
|
||||
int count,
|
||||
bool fc1InEffect)
|
||||
{
|
||||
// Read two characters at a time
|
||||
int start = result.Length;
|
||||
while (count > 1)
|
||||
{
|
||||
if (bits.available() < 11)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int nextTwoCharsBits = bits.readBits(11);
|
||||
result.Append(toAlphaNumericChar(nextTwoCharsBits / 45));
|
||||
result.Append(toAlphaNumericChar(nextTwoCharsBits % 45));
|
||||
count -= 2;
|
||||
}
|
||||
if (count == 1)
|
||||
{
|
||||
// special case: one character left
|
||||
if (bits.available() < 6)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
result.Append(toAlphaNumericChar(bits.readBits(6)));
|
||||
}
|
||||
|
||||
// See section 6.4.8.1, 6.4.8.2
|
||||
if (fc1InEffect)
|
||||
{
|
||||
// We need to massage the result a bit if in an FNC1 mode:
|
||||
for (int i = start; i < result.Length; i++)
|
||||
{
|
||||
if (result[i] == '%')
|
||||
{
|
||||
if (i < result.Length - 1 && result[i + 1] == '%')
|
||||
{
|
||||
// %% is rendered as %
|
||||
result.Remove(i + 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// In alpha mode, % should be converted to FNC1 separator 0x1D
|
||||
result.Remove(i, 1);
|
||||
result.Insert(i, new[] { (char)0x1D });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool decodeNumericSegment(BitSource bits,
|
||||
StringBuilder result,
|
||||
int count)
|
||||
{
|
||||
// Read three digits at a time
|
||||
while (count >= 3)
|
||||
{
|
||||
// Each 10 bits encodes three digits
|
||||
if (bits.available() < 10)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int threeDigitsBits = bits.readBits(10);
|
||||
if (threeDigitsBits >= 1000)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
result.Append(toAlphaNumericChar(threeDigitsBits / 100));
|
||||
result.Append(toAlphaNumericChar((threeDigitsBits / 10) % 10));
|
||||
result.Append(toAlphaNumericChar(threeDigitsBits % 10));
|
||||
|
||||
count -= 3;
|
||||
}
|
||||
if (count == 2)
|
||||
{
|
||||
// Two digits left over to read, encoded in 7 bits
|
||||
if (bits.available() < 7)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int twoDigitsBits = bits.readBits(7);
|
||||
if (twoDigitsBits >= 100)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
result.Append(toAlphaNumericChar(twoDigitsBits / 10));
|
||||
result.Append(toAlphaNumericChar(twoDigitsBits % 10));
|
||||
}
|
||||
else if (count == 1)
|
||||
{
|
||||
// One digit left over to read
|
||||
if (bits.available() < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int digitBits = bits.readBits(4);
|
||||
if (digitBits >= 10)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
result.Append(toAlphaNumericChar(digitBits));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int parseECIValue(BitSource bits)
|
||||
{
|
||||
int firstByte = bits.readBits(8);
|
||||
if ((firstByte & 0x80) == 0)
|
||||
{
|
||||
// just one byte
|
||||
return firstByte & 0x7F;
|
||||
}
|
||||
if ((firstByte & 0xC0) == 0x80)
|
||||
{
|
||||
// two bytes
|
||||
int secondByte = bits.readBits(8);
|
||||
return ((firstByte & 0x3F) << 8) | secondByte;
|
||||
}
|
||||
if ((firstByte & 0xE0) == 0xC0)
|
||||
{
|
||||
// three bytes
|
||||
int secondThirdBytes = bits.readBits(16);
|
||||
return ((firstByte & 0x1F) << 16) | secondThirdBytes;
|
||||
}
|
||||
throw new ArgumentException("Bad ECI bits starting with byte " + firstByte);
|
||||
}
|
||||
}
|
||||
}
|
||||
195
zxing.core/xx/qrcode/decoder/Decoder.cs
Normal file
195
zxing.core/xx/qrcode/decoder/Decoder.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ZXing.Common;
|
||||
using ZXing.Common.ReedSolomon;
|
||||
|
||||
namespace ZXing.QrCode.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// <p>The main class which implements QR Code decoding -- as opposed to locating and extracting
|
||||
/// the QR Code from an image.</p>
|
||||
/// </summary>
|
||||
/// <author>
|
||||
/// Sean Owen
|
||||
/// </author>
|
||||
public sealed class Decoder
|
||||
{
|
||||
private readonly ReedSolomonDecoder rsDecoder;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Decoder"/> class.
|
||||
/// </summary>
|
||||
public Decoder()
|
||||
{
|
||||
rsDecoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>Convenience method that can decode a QR Code represented as a 2D array of booleans.
|
||||
/// "true" is taken to mean a black module.</p>
|
||||
/// </summary>
|
||||
/// <param name="image">booleans representing white/black QR Code modules</param>
|
||||
/// <param name="hints">decoding hints that should be used to influence decoding</param>
|
||||
/// <returns>
|
||||
/// text and bytes encoded within the QR Code
|
||||
/// </returns>
|
||||
public DecoderResult decode(bool[][] image, IDictionary<DecodeHintType, object> hints)
|
||||
{
|
||||
var dimension = image.Length;
|
||||
var bits = new BitMatrix(dimension);
|
||||
for (int i = 0; i < dimension; i++)
|
||||
{
|
||||
for (int j = 0; j < dimension; j++)
|
||||
{
|
||||
bits[j, i] = image[i][j];
|
||||
}
|
||||
}
|
||||
return decode(bits, hints);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p>
|
||||
/// </summary>
|
||||
/// <param name="bits">booleans representing white/black QR Code modules</param>
|
||||
/// <param name="hints">decoding hints that should be used to influence decoding</param>
|
||||
/// <returns>
|
||||
/// text and bytes encoded within the QR Code
|
||||
/// </returns>
|
||||
public DecoderResult decode(BitMatrix bits, IDictionary<DecodeHintType, object> hints)
|
||||
{
|
||||
// Construct a parser and read version, error-correction level
|
||||
var parser = BitMatrixParser.createBitMatrixParser(bits);
|
||||
if (parser == null)
|
||||
return null;
|
||||
|
||||
var result = decode(parser, hints);
|
||||
if (result == null)
|
||||
{
|
||||
// Revert the bit matrix
|
||||
parser.remask();
|
||||
|
||||
// Will be attempting a mirrored reading of the version and format info.
|
||||
parser.setMirror(true);
|
||||
|
||||
// Preemptively read the version.
|
||||
var version = parser.readVersion();
|
||||
if (version == null)
|
||||
return null;
|
||||
|
||||
// Preemptively read the format information.
|
||||
var formatinfo = parser.readFormatInformation();
|
||||
if (formatinfo == null)
|
||||
return null;
|
||||
|
||||
/*
|
||||
* Since we're here, this means we have successfully detected some kind
|
||||
* of version and format information when mirrored. This is a good sign,
|
||||
* that the QR code may be mirrored, and we should try once more with a
|
||||
* mirrored content.
|
||||
*/
|
||||
// Prepare for a mirrored reading.
|
||||
parser.mirror();
|
||||
|
||||
result = decode(parser, hints);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
// Success! Notify the caller that the code was mirrored.
|
||||
result.Other = new QRCodeDecoderMetaData(true);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private DecoderResult decode(BitMatrixParser parser, IDictionary<DecodeHintType, object> hints)
|
||||
{
|
||||
Version version = parser.readVersion();
|
||||
if (version == null)
|
||||
return null;
|
||||
var formatinfo = parser.readFormatInformation();
|
||||
if (formatinfo == null)
|
||||
return null;
|
||||
ErrorCorrectionLevel ecLevel = formatinfo.ErrorCorrectionLevel;
|
||||
|
||||
// Read codewords
|
||||
byte[] codewords = parser.readCodewords();
|
||||
if (codewords == null)
|
||||
return null;
|
||||
// Separate into data blocks
|
||||
DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel);
|
||||
|
||||
// Count total number of data bytes
|
||||
int totalBytes = 0;
|
||||
foreach (var dataBlock in dataBlocks)
|
||||
{
|
||||
totalBytes += dataBlock.NumDataCodewords;
|
||||
}
|
||||
byte[] resultBytes = new byte[totalBytes];
|
||||
int resultOffset = 0;
|
||||
|
||||
// Error-correct and copy data blocks together into a stream of bytes
|
||||
foreach (var dataBlock in dataBlocks)
|
||||
{
|
||||
byte[] codewordBytes = dataBlock.Codewords;
|
||||
int numDataCodewords = dataBlock.NumDataCodewords;
|
||||
if (!correctErrors(codewordBytes, numDataCodewords))
|
||||
return null;
|
||||
for (int i = 0; i < numDataCodewords; i++)
|
||||
{
|
||||
resultBytes[resultOffset++] = codewordBytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the contents of that stream of bytes
|
||||
return DecodedBitStreamParser.decode(resultBytes, version, ecLevel, hints);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
||||
/// correct the errors in-place using Reed-Solomon error correction.</p>
|
||||
/// </summary>
|
||||
/// <param name="codewordBytes">data and error correction codewords</param>
|
||||
/// <param name="numDataCodewords">number of codewords that are data bytes</param>
|
||||
/// <returns></returns>
|
||||
private bool correctErrors(byte[] codewordBytes, int numDataCodewords)
|
||||
{
|
||||
int numCodewords = codewordBytes.Length;
|
||||
// First read into an array of ints
|
||||
int[] codewordsInts = new int[numCodewords];
|
||||
for (int i = 0; i < numCodewords; i++)
|
||||
{
|
||||
codewordsInts[i] = codewordBytes[i] & 0xFF;
|
||||
}
|
||||
int numECCodewords = codewordBytes.Length - numDataCodewords;
|
||||
|
||||
if (!rsDecoder.decode(codewordsInts, numECCodewords))
|
||||
return false;
|
||||
|
||||
// Copy back into array of bytes -- only need to worry about the bytes that were data
|
||||
// We don't care about errors in the error-correction codewords
|
||||
for (int i = 0; i < numDataCodewords; i++)
|
||||
{
|
||||
codewordBytes[i] = (byte)codewordsInts[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
109
zxing.core/xx/qrcode/decoder/ErrorCorrectionLevel.cs
Normal file
109
zxing.core/xx/qrcode/decoder/ErrorCorrectionLevel.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace ZXing.QrCode.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// <p>See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels
|
||||
/// defined by the QR code standard.</p>
|
||||
/// </summary>
|
||||
/// <author>Sean Owen</author>
|
||||
public sealed class ErrorCorrectionLevel
|
||||
{
|
||||
/// <summary> L = ~7% correction</summary>
|
||||
public static readonly ErrorCorrectionLevel L = new ErrorCorrectionLevel(0, 0x01, "L");
|
||||
/// <summary> M = ~15% correction</summary>
|
||||
public static readonly ErrorCorrectionLevel M = new ErrorCorrectionLevel(1, 0x00, "M");
|
||||
/// <summary> Q = ~25% correction</summary>
|
||||
public static readonly ErrorCorrectionLevel Q = new ErrorCorrectionLevel(2, 0x03, "Q");
|
||||
/// <summary> H = ~30% correction</summary>
|
||||
public static readonly ErrorCorrectionLevel H = new ErrorCorrectionLevel(3, 0x02, "H");
|
||||
|
||||
private static readonly ErrorCorrectionLevel[] FOR_BITS = new [] { M, L, H, Q };
|
||||
|
||||
private readonly int bits;
|
||||
|
||||
private ErrorCorrectionLevel(int ordinal, int bits, String name)
|
||||
{
|
||||
this.ordinal_Renamed_Field = ordinal;
|
||||
this.bits = bits;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bits.
|
||||
/// </summary>
|
||||
public int Bits
|
||||
{
|
||||
get
|
||||
{
|
||||
return bits;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
public String Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly int ordinal_Renamed_Field;
|
||||
private readonly String name;
|
||||
|
||||
/// <summary>
|
||||
/// Ordinals this instance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int ordinal()
|
||||
{
|
||||
return ordinal_Renamed_Field;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String"/> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String"/> that represents this instance.
|
||||
/// </returns>
|
||||
public override String ToString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fors the bits.
|
||||
/// </summary>
|
||||
/// <param name="bits">int containing the two bits encoding a QR Code's error correction level</param>
|
||||
/// <returns>
|
||||
/// <see cref="ErrorCorrectionLevel"/> representing the encoded error correction level
|
||||
/// </returns>
|
||||
public static ErrorCorrectionLevel forBits(int bits)
|
||||
{
|
||||
if (bits < 0 || bits >= FOR_BITS.Length)
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
return FOR_BITS[bits];
|
||||
}
|
||||
}
|
||||
}
|
||||
197
zxing.core/xx/qrcode/decoder/FormatInformation.cs
Normal file
197
zxing.core/xx/qrcode/decoder/FormatInformation.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace ZXing.QrCode.Internal
|
||||
{
|
||||
|
||||
/// <summary> <p>Encapsulates a QR Code's format information, including the data mask used and
|
||||
/// error correction level.</p>
|
||||
///
|
||||
/// </summary>
|
||||
/// <author> Sean Owen
|
||||
/// </author>
|
||||
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
|
||||
/// </author>
|
||||
/// <seealso cref="DataMask">
|
||||
/// </seealso>
|
||||
/// <seealso cref="ErrorCorrectionLevel">
|
||||
/// </seealso>
|
||||
sealed class FormatInformation
|
||||
{
|
||||
private const int FORMAT_INFO_MASK_QR = 0x5412;
|
||||
|
||||
/// <summary> See ISO 18004:2006, Annex C, Table C.1</summary>
|
||||
private static readonly int[][] FORMAT_INFO_DECODE_LOOKUP = new int[][]
|
||||
{
|
||||
new [] { 0x5412, 0x00 },
|
||||
new [] { 0x5125, 0x01 },
|
||||
new [] { 0x5E7C, 0x02 },
|
||||
new [] { 0x5B4B, 0x03 },
|
||||
new [] { 0x45F9, 0x04 },
|
||||
new [] { 0x40CE, 0x05 },
|
||||
new [] { 0x4F97, 0x06 },
|
||||
new [] { 0x4AA0, 0x07 },
|
||||
new [] { 0x77C4, 0x08 },
|
||||
new [] { 0x72F3, 0x09 },
|
||||
new [] { 0x7DAA, 0x0A },
|
||||
new [] { 0x789D, 0x0B },
|
||||
new [] { 0x662F, 0x0C },
|
||||
new [] { 0x6318, 0x0D },
|
||||
new [] { 0x6C41, 0x0E },
|
||||
new [] { 0x6976, 0x0F },
|
||||
new [] { 0x1689, 0x10 },
|
||||
new [] { 0x13BE, 0x11 },
|
||||
new [] { 0x1CE7, 0x12 },
|
||||
new [] { 0x19D0, 0x13 },
|
||||
new [] { 0x0762, 0x14 },
|
||||
new [] { 0x0255, 0x15 },
|
||||
new [] { 0x0D0C, 0x16 },
|
||||
new [] { 0x083B, 0x17 },
|
||||
new [] { 0x355F, 0x18 },
|
||||
new [] { 0x3068, 0x19 },
|
||||
new [] { 0x3F31, 0x1A },
|
||||
new [] { 0x3A06, 0x1B },
|
||||
new [] { 0x24B4, 0x1C },
|
||||
new [] { 0x2183, 0x1D },
|
||||
new [] { 0x2EDA, 0x1E },
|
||||
new [] { 0x2BED, 0x1F }
|
||||
};
|
||||
|
||||
/// <summary> Offset i holds the number of 1 bits in the binary representation of i</summary>
|
||||
private static readonly int[] BITS_SET_IN_HALF_BYTE = new []
|
||||
{ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
|
||||
|
||||
private readonly ErrorCorrectionLevel errorCorrectionLevel;
|
||||
private readonly byte dataMask;
|
||||
|
||||
private FormatInformation(int formatInfo)
|
||||
{
|
||||
// Bits 3,4
|
||||
errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03);
|
||||
// Bottom 3 bits
|
||||
dataMask = (byte)(formatInfo & 0x07);
|
||||
}
|
||||
|
||||
internal static int numBitsDiffering(int a, int b)
|
||||
{
|
||||
a ^= b; // a now has a 1 bit exactly where its bit differs with b's
|
||||
// Count bits set quickly with a series of lookups:
|
||||
return BITS_SET_IN_HALF_BYTE[a & 0x0F] +
|
||||
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 4)) & 0x0F)] +
|
||||
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 8)) & 0x0F)] +
|
||||
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 12)) & 0x0F)] +
|
||||
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 16)) & 0x0F)] +
|
||||
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 20)) & 0x0F)] +
|
||||
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 24)) & 0x0F)] +
|
||||
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 28)) & 0x0F)];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the format information.
|
||||
/// </summary>
|
||||
/// <param name="maskedFormatInfo1">format info indicator, with mask still applied</param>
|
||||
/// <param name="maskedFormatInfo2">The masked format info2.</param>
|
||||
/// <returns>
|
||||
/// information about the format it specifies, or <code>null</code>
|
||||
/// 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 static FormatInformation doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2)
|
||||
{
|
||||
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
|
||||
int bestDifference = Int32.MaxValue;
|
||||
int bestFormatInfo = 0;
|
||||
foreach (var decodeInfo in FORMAT_INFO_DECODE_LOOKUP)
|
||||
{
|
||||
int targetInfo = decodeInfo[0];
|
||||
if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2)
|
||||
{
|
||||
// Found an exact match
|
||||
return new FormatInformation(decodeInfo[1]);
|
||||
}
|
||||
int bitsDifference = numBitsDiffering(maskedFormatInfo1, targetInfo);
|
||||
if (bitsDifference < bestDifference)
|
||||
{
|
||||
bestFormatInfo = decodeInfo[1];
|
||||
bestDifference = bitsDifference;
|
||||
}
|
||||
if (maskedFormatInfo1 != maskedFormatInfo2)
|
||||
{
|
||||
// also try the other option
|
||||
bitsDifference = numBitsDiffering(maskedFormatInfo2, targetInfo);
|
||||
if (bitsDifference < bestDifference)
|
||||
{
|
||||
bestFormatInfo = decodeInfo[1];
|
||||
bestDifference = bitsDifference;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
|
||||
// differing means we found a match
|
||||
if (bestDifference <= 3)
|
||||
{
|
||||
return new FormatInformation(bestFormatInfo);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal ErrorCorrectionLevel ErrorCorrectionLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return errorCorrectionLevel;
|
||||
}
|
||||
}
|
||||
|
||||
internal byte DataMask
|
||||
{
|
||||
get
|
||||
{
|
||||
return dataMask;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (errorCorrectionLevel.ordinal() << 3) | dataMask;
|
||||
}
|
||||
|
||||
public override bool Equals(Object o)
|
||||
{
|
||||
if (!(o is FormatInformation))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var other = (FormatInformation)o;
|
||||
return errorCorrectionLevel == other.errorCorrectionLevel && dataMask == other.dataMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
179
zxing.core/xx/qrcode/decoder/Mode.cs
Normal file
179
zxing.core/xx/qrcode/decoder/Mode.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace ZXing.QrCode.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// <p>See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which
|
||||
/// data can be encoded to bits in the QR code standard.</p>
|
||||
/// </summary>
|
||||
/// <author>Sean Owen</author>
|
||||
public sealed class Mode
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
public String Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// No, we can't use an enum here. J2ME doesn't support it.
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly Mode TERMINATOR = new Mode(new int[] { 0, 0, 0 }, 0x00, "TERMINATOR"); // Not really a mode...
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly Mode NUMERIC = new Mode(new int[] { 10, 12, 14 }, 0x01, "NUMERIC");
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly Mode ALPHANUMERIC = new Mode(new int[] { 9, 11, 13 }, 0x02, "ALPHANUMERIC");
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly Mode STRUCTURED_APPEND = new Mode(new int[] { 0, 0, 0 }, 0x03, "STRUCTURED_APPEND"); // Not supported
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly Mode BYTE = new Mode(new int[] { 8, 16, 16 }, 0x04, "BYTE");
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly Mode ECI = new Mode(null, 0x07, "ECI"); // character counts don't apply
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly Mode KANJI = new Mode(new int[] { 8, 10, 12 }, 0x08, "KANJI");
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly Mode FNC1_FIRST_POSITION = new Mode(null, 0x05, "FNC1_FIRST_POSITION");
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly Mode FNC1_SECOND_POSITION = new Mode(null, 0x09, "FNC1_SECOND_POSITION");
|
||||
/// <summary>See GBT 18284-2000; "Hanzi" is a transliteration of this mode name.</summary>
|
||||
public static readonly Mode HANZI = new Mode(new int[] { 8, 10, 12 }, 0x0D, "HANZI");
|
||||
|
||||
private readonly int[] characterCountBitsForVersions;
|
||||
private readonly int bits;
|
||||
private readonly String name;
|
||||
|
||||
private Mode(int[] characterCountBitsForVersions, int bits, System.String name)
|
||||
{
|
||||
this.characterCountBitsForVersions = characterCountBitsForVersions;
|
||||
this.bits = bits;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fors the bits.
|
||||
/// </summary>
|
||||
/// <param name="bits">four bits encoding a QR Code data mode</param>
|
||||
/// <returns>
|
||||
/// <see cref="Mode"/> encoded by these bits
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentException">if bits do not correspond to a known mode</exception>
|
||||
public static Mode forBits(int bits)
|
||||
{
|
||||
switch (bits)
|
||||
{
|
||||
case 0x0:
|
||||
return TERMINATOR;
|
||||
case 0x1:
|
||||
return NUMERIC;
|
||||
case 0x2:
|
||||
return ALPHANUMERIC;
|
||||
case 0x3:
|
||||
return STRUCTURED_APPEND;
|
||||
case 0x4:
|
||||
return BYTE;
|
||||
case 0x5:
|
||||
return FNC1_FIRST_POSITION;
|
||||
case 0x7:
|
||||
return ECI;
|
||||
case 0x8:
|
||||
return KANJI;
|
||||
case 0x9:
|
||||
return FNC1_SECOND_POSITION;
|
||||
case 0xD:
|
||||
// 0xD is defined in GBT 18284-2000, may not be supported in foreign country
|
||||
return HANZI;
|
||||
default:
|
||||
throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <param name="version">version in question
|
||||
/// </param>
|
||||
/// <returns> number of bits used, in this QR Code symbol {@link Version}, to encode the
|
||||
/// count of characters that will follow encoded in this {@link Mode}
|
||||
/// </returns>
|
||||
public int getCharacterCountBits(Version version)
|
||||
{
|
||||
if (characterCountBitsForVersions == null)
|
||||
{
|
||||
throw new ArgumentException("Character count doesn't apply to this mode");
|
||||
}
|
||||
int number = version.VersionNumber;
|
||||
int offset;
|
||||
if (number <= 9)
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
else if (number <= 26)
|
||||
{
|
||||
offset = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 2;
|
||||
}
|
||||
return characterCountBitsForVersions[offset];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bits.
|
||||
/// </summary>
|
||||
public int Bits
|
||||
{
|
||||
get
|
||||
{
|
||||
return bits;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String"/> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String"/> that represents this instance.
|
||||
/// </returns>
|
||||
public override String ToString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
zxing.core/xx/qrcode/decoder/QRCodeDecoderMetaData.cs
Normal file
60
zxing.core/xx/qrcode/decoder/QRCodeDecoderMetaData.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace ZXing.QrCode.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the
|
||||
/// decoding caller. Callers are expected to process this.
|
||||
/// </summary>
|
||||
public sealed class QRCodeDecoderMetaData
|
||||
{
|
||||
private readonly bool mirrored;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QRCodeDecoderMetaData"/> class.
|
||||
/// </summary>
|
||||
/// <param name="mirrored">if set to <c>true</c> [mirrored].</param>
|
||||
public QRCodeDecoderMetaData(bool mirrored)
|
||||
{
|
||||
this.mirrored = mirrored;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// true if the QR Code was mirrored.
|
||||
/// </summary>
|
||||
public bool IsMirrored
|
||||
{
|
||||
get { return mirrored; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply the result points' order correction due to mirroring.
|
||||
/// </summary>
|
||||
/// <param name="points">Array of points to apply mirror correction to.</param>
|
||||
public void applyMirroredCorrection(ResultPoint[] points)
|
||||
{
|
||||
if (!mirrored || points == null || points.Length < 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ResultPoint bottomLeft = points[0];
|
||||
points[0] = points[2];
|
||||
points[2] = bottomLeft;
|
||||
// No need to 'fix' top-left and alignment pattern.
|
||||
}
|
||||
}
|
||||
}
|
||||
685
zxing.core/xx/qrcode/decoder/Version.cs
Normal file
685
zxing.core/xx/qrcode/decoder/Version.cs
Normal file
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
using ZXing.Common;
|
||||
|
||||
namespace ZXing.QrCode.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// See ISO 18004:2006 Annex D
|
||||
/// </summary>
|
||||
/// <author>Sean Owen</author>
|
||||
public sealed class Version
|
||||
{
|
||||
/// <summary> See ISO 18004:2006 Annex D.
|
||||
/// Element i represents the raw version bits that specify version i + 7
|
||||
/// </summary>
|
||||
private static readonly int[] VERSION_DECODE_INFO = new[]
|
||||
{
|
||||
0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6,
|
||||
0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78,
|
||||
0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683,
|
||||
0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
|
||||
0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250,
|
||||
0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B,
|
||||
0x2542E, 0x26A64, 0x27541, 0x28C69
|
||||
};
|
||||
|
||||
private static readonly Version[] VERSIONS = buildVersions();
|
||||
|
||||
private readonly int versionNumber;
|
||||
private readonly int[] alignmentPatternCenters;
|
||||
private readonly ECBlocks[] ecBlocks;
|
||||
private readonly int totalCodewords;
|
||||
|
||||
private Version(int versionNumber, int[] alignmentPatternCenters, params ECBlocks[] ecBlocks)
|
||||
{
|
||||
this.versionNumber = versionNumber;
|
||||
this.alignmentPatternCenters = alignmentPatternCenters;
|
||||
this.ecBlocks = ecBlocks;
|
||||
int total = 0;
|
||||
int ecCodewords = ecBlocks[0].ECCodewordsPerBlock;
|
||||
ECB[] ecbArray = ecBlocks[0].getECBlocks();
|
||||
foreach (var ecBlock in ecbArray)
|
||||
{
|
||||
total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords);
|
||||
}
|
||||
this.totalCodewords = total;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version number.
|
||||
/// </summary>
|
||||
public int VersionNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
return versionNumber;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the alignment pattern centers.
|
||||
/// </summary>
|
||||
public int[] AlignmentPatternCenters
|
||||
{
|
||||
get
|
||||
{
|
||||
return alignmentPatternCenters;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total codewords.
|
||||
/// </summary>
|
||||
public int TotalCodewords
|
||||
{
|
||||
get
|
||||
{
|
||||
return totalCodewords;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dimension for version.
|
||||
/// </summary>
|
||||
public int DimensionForVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return 17 + 4 * versionNumber;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the EC blocks for level.
|
||||
/// </summary>
|
||||
/// <param name="ecLevel">The ec level.</param>
|
||||
/// <returns></returns>
|
||||
public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel)
|
||||
{
|
||||
return ecBlocks[ecLevel.ordinal()];
|
||||
}
|
||||
|
||||
/// <summary> <p>Deduces version information purely from QR Code dimensions.</p>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dimension">dimension in modules
|
||||
/// </param>
|
||||
/// <returns><see cref="Version" /> for a QR Code of that dimension or null</returns>
|
||||
public static Version getProvisionalVersionForDimension(int dimension)
|
||||
{
|
||||
if (dimension % 4 != 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
return getVersionForNumber((dimension - 17) >> 2);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version for number.
|
||||
/// </summary>
|
||||
/// <param name="versionNumber">The version number.</param>
|
||||
/// <returns></returns>
|
||||
public static Version getVersionForNumber(int versionNumber)
|
||||
{
|
||||
if (versionNumber < 1 || versionNumber > 40)
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
return VERSIONS[versionNumber - 1];
|
||||
}
|
||||
|
||||
internal static Version decodeVersionInformation(int versionBits)
|
||||
{
|
||||
int bestDifference = 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 8 bits.
|
||||
if (bestDifference <= 3)
|
||||
{
|
||||
return getVersionForNumber(bestVersion);
|
||||
}
|
||||
// If we didn't find a close enough match, fail
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary> See ISO 18004:2006 Annex E</summary>
|
||||
internal BitMatrix buildFunctionPattern()
|
||||
{
|
||||
int dimension = DimensionForVersion;
|
||||
BitMatrix bitMatrix = new BitMatrix(dimension);
|
||||
|
||||
// Top left finder pattern + separator + format
|
||||
bitMatrix.setRegion(0, 0, 9, 9);
|
||||
// Top right finder pattern + separator + format
|
||||
bitMatrix.setRegion(dimension - 8, 0, 8, 9);
|
||||
// Bottom left finder pattern + separator + format
|
||||
bitMatrix.setRegion(0, dimension - 8, 9, 8);
|
||||
|
||||
// Alignment patterns
|
||||
int max = alignmentPatternCenters.Length;
|
||||
for (int x = 0; x < max; x++)
|
||||
{
|
||||
int i = alignmentPatternCenters[x] - 2;
|
||||
for (int y = 0; y < max; y++)
|
||||
{
|
||||
if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0))
|
||||
{
|
||||
// No alignment patterns near the three finder paterns
|
||||
continue;
|
||||
}
|
||||
bitMatrix.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5);
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical timing pattern
|
||||
bitMatrix.setRegion(6, 9, 1, dimension - 17);
|
||||
// Horizontal timing pattern
|
||||
bitMatrix.setRegion(9, 6, dimension - 17, 1);
|
||||
|
||||
if (versionNumber > 6)
|
||||
{
|
||||
// Version info, top right
|
||||
bitMatrix.setRegion(dimension - 11, 0, 3, 6);
|
||||
// Version info, bottom left
|
||||
bitMatrix.setRegion(0, dimension - 11, 6, 3);
|
||||
}
|
||||
|
||||
return bitMatrix;
|
||||
}
|
||||
|
||||
/// <summary> <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
|
||||
/// use blocks of differing sizes within one version, so, this encapsulates the parameters for
|
||||
/// each set of blocks. It also holds the number of error-correction codewords per block since it
|
||||
/// will be the same across all blocks within one version.</p>
|
||||
/// </summary>
|
||||
public sealed class ECBlocks
|
||||
{
|
||||
private readonly int ecCodewordsPerBlock;
|
||||
private readonly ECB[] ecBlocks;
|
||||
|
||||
internal ECBlocks(int ecCodewordsPerBlock, params ECB[] ecBlocks)
|
||||
{
|
||||
this.ecCodewordsPerBlock = ecCodewordsPerBlock;
|
||||
this.ecBlocks = ecBlocks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the EC codewords per block.
|
||||
/// </summary>
|
||||
public int ECCodewordsPerBlock
|
||||
{
|
||||
get
|
||||
{
|
||||
return ecCodewordsPerBlock;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the num blocks.
|
||||
/// </summary>
|
||||
public int NumBlocks
|
||||
{
|
||||
get
|
||||
{
|
||||
int total = 0;
|
||||
foreach (var ecBlock in ecBlocks)
|
||||
{
|
||||
total += ecBlock.Count;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total EC codewords.
|
||||
/// </summary>
|
||||
public int TotalECCodewords
|
||||
{
|
||||
get
|
||||
{
|
||||
return ecCodewordsPerBlock * NumBlocks;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the EC blocks.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ECB[] getECBlocks()
|
||||
{
|
||||
return ecBlocks;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> <p>Encapsualtes the parameters for one error-correction block in one symbol version.
|
||||
/// This includes the number of data codewords, and the number of times a block with these
|
||||
/// parameters is used consecutively in the QR code version's format.</p>
|
||||
/// </summary>
|
||||
public sealed class ECB
|
||||
{
|
||||
private readonly int count;
|
||||
private readonly int dataCodewords;
|
||||
|
||||
internal ECB(int count, int dataCodewords)
|
||||
{
|
||||
this.count = count;
|
||||
this.dataCodewords = dataCodewords;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the count.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the data codewords.
|
||||
/// </summary>
|
||||
public int DataCodewords
|
||||
{
|
||||
get
|
||||
{
|
||||
return dataCodewords;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String"/> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String"/> that represents this instance.
|
||||
/// </returns>
|
||||
public override String ToString()
|
||||
{
|
||||
return Convert.ToString(versionNumber);
|
||||
}
|
||||
|
||||
/// <summary> See ISO 18004:2006 6.5.1 Table 9</summary>
|
||||
private static Version[] buildVersions()
|
||||
{
|
||||
return new Version[]
|
||||
{
|
||||
new Version(1, new int[] {},
|
||||
new ECBlocks(7, new ECB(1, 19)),
|
||||
new ECBlocks(10, new ECB(1, 16)),
|
||||
new ECBlocks(13, new ECB(1, 13)),
|
||||
new ECBlocks(17, new ECB(1, 9))),
|
||||
new Version(2, new int[] {6, 18},
|
||||
new ECBlocks(10, new ECB(1, 34)),
|
||||
new ECBlocks(16, new ECB(1, 28)),
|
||||
new ECBlocks(22, new ECB(1, 22)),
|
||||
new ECBlocks(28, new ECB(1, 16))),
|
||||
new Version(3, new int[] {6, 22},
|
||||
new ECBlocks(15, new ECB(1, 55)),
|
||||
new ECBlocks(26, new ECB(1, 44)),
|
||||
new ECBlocks(18, new ECB(2, 17)),
|
||||
new ECBlocks(22, new ECB(2, 13))),
|
||||
new Version(4, new int[] {6, 26},
|
||||
new ECBlocks(20, new ECB(1, 80)),
|
||||
new ECBlocks(18, new ECB(2, 32)),
|
||||
new ECBlocks(26, new ECB(2, 24)),
|
||||
new ECBlocks(16, new ECB(4, 9))),
|
||||
new Version(5, new int[] {6, 30},
|
||||
new ECBlocks(26, new ECB(1, 108)),
|
||||
new ECBlocks(24, new ECB(2, 43)),
|
||||
new ECBlocks(18, new ECB(2, 15),
|
||||
new ECB(2, 16)),
|
||||
new ECBlocks(22, new ECB(2, 11),
|
||||
new ECB(2, 12))),
|
||||
new Version(6, new int[] {6, 34},
|
||||
new ECBlocks(18, new ECB(2, 68)),
|
||||
new ECBlocks(16, new ECB(4, 27)),
|
||||
new ECBlocks(24, new ECB(4, 19)),
|
||||
new ECBlocks(28, new ECB(4, 15))),
|
||||
new Version(7, new int[] {6, 22, 38},
|
||||
new ECBlocks(20, new ECB(2, 78)),
|
||||
new ECBlocks(18, new ECB(4, 31)),
|
||||
new ECBlocks(18, new ECB(2, 14),
|
||||
new ECB(4, 15)),
|
||||
new ECBlocks(26, new ECB(4, 13),
|
||||
new ECB(1, 14))),
|
||||
new Version(8, new int[] {6, 24, 42},
|
||||
new ECBlocks(24, new ECB(2, 97)),
|
||||
new ECBlocks(22, new ECB(2, 38),
|
||||
new ECB(2, 39)),
|
||||
new ECBlocks(22, new ECB(4, 18),
|
||||
new ECB(2, 19)),
|
||||
new ECBlocks(26, new ECB(4, 14),
|
||||
new ECB(2, 15))),
|
||||
new Version(9, new int[] {6, 26, 46},
|
||||
new ECBlocks(30, new ECB(2, 116)),
|
||||
new ECBlocks(22, new ECB(3, 36),
|
||||
new ECB(2, 37)),
|
||||
new ECBlocks(20, new ECB(4, 16),
|
||||
new ECB(4, 17)),
|
||||
new ECBlocks(24, new ECB(4, 12),
|
||||
new ECB(4, 13))),
|
||||
new Version(10, new int[] {6, 28, 50},
|
||||
new ECBlocks(18, new ECB(2, 68),
|
||||
new ECB(2, 69)),
|
||||
new ECBlocks(26, new ECB(4, 43),
|
||||
new ECB(1, 44)),
|
||||
new ECBlocks(24, new ECB(6, 19),
|
||||
new ECB(2, 20)),
|
||||
new ECBlocks(28, new ECB(6, 15),
|
||||
new ECB(2, 16))),
|
||||
new Version(11, new int[] {6, 30, 54},
|
||||
new ECBlocks(20, new ECB(4, 81)),
|
||||
new ECBlocks(30, new ECB(1, 50),
|
||||
new ECB(4, 51)),
|
||||
new ECBlocks(28, new ECB(4, 22),
|
||||
new ECB(4, 23)),
|
||||
new ECBlocks(24, new ECB(3, 12),
|
||||
new ECB(8, 13))),
|
||||
new Version(12, new int[] {6, 32, 58},
|
||||
new ECBlocks(24, new ECB(2, 92),
|
||||
new ECB(2, 93)),
|
||||
new ECBlocks(22, new ECB(6, 36),
|
||||
new ECB(2, 37)),
|
||||
new ECBlocks(26, new ECB(4, 20),
|
||||
new ECB(6, 21)),
|
||||
new ECBlocks(28, new ECB(7, 14),
|
||||
new ECB(4, 15))),
|
||||
new Version(13, new int[] {6, 34, 62},
|
||||
new ECBlocks(26, new ECB(4, 107)),
|
||||
new ECBlocks(22, new ECB(8, 37),
|
||||
new ECB(1, 38)),
|
||||
new ECBlocks(24, new ECB(8, 20),
|
||||
new ECB(4, 21)),
|
||||
new ECBlocks(22, new ECB(12, 11),
|
||||
new ECB(4, 12))),
|
||||
new Version(14, new int[] {6, 26, 46, 66},
|
||||
new ECBlocks(30, new ECB(3, 115),
|
||||
new ECB(1, 116)),
|
||||
new ECBlocks(24, new ECB(4, 40),
|
||||
new ECB(5, 41)),
|
||||
new ECBlocks(20, new ECB(11, 16),
|
||||
new ECB(5, 17)),
|
||||
new ECBlocks(24, new ECB(11, 12),
|
||||
new ECB(5, 13))),
|
||||
new Version(15, new int[] {6, 26, 48, 70},
|
||||
new ECBlocks(22, new ECB(5, 87),
|
||||
new ECB(1, 88)),
|
||||
new ECBlocks(24, new ECB(5, 41),
|
||||
new ECB(5, 42)),
|
||||
new ECBlocks(30, new ECB(5, 24),
|
||||
new ECB(7, 25)),
|
||||
new ECBlocks(24, new ECB(11, 12),
|
||||
new ECB(7, 13))),
|
||||
new Version(16, new int[] {6, 26, 50, 74},
|
||||
new ECBlocks(24, new ECB(5, 98),
|
||||
new ECB(1, 99)),
|
||||
new ECBlocks(28, new ECB(7, 45),
|
||||
new ECB(3, 46)),
|
||||
new ECBlocks(24, new ECB(15, 19),
|
||||
new ECB(2, 20)),
|
||||
new ECBlocks(30, new ECB(3, 15),
|
||||
new ECB(13, 16))),
|
||||
new Version(17, new int[] {6, 30, 54, 78},
|
||||
new ECBlocks(28, new ECB(1, 107),
|
||||
new ECB(5, 108)),
|
||||
new ECBlocks(28, new ECB(10, 46),
|
||||
new ECB(1, 47)),
|
||||
new ECBlocks(28, new ECB(1, 22),
|
||||
new ECB(15, 23)),
|
||||
new ECBlocks(28, new ECB(2, 14),
|
||||
new ECB(17, 15))),
|
||||
new Version(18, new int[] {6, 30, 56, 82},
|
||||
new ECBlocks(30, new ECB(5, 120),
|
||||
new ECB(1, 121)),
|
||||
new ECBlocks(26, new ECB(9, 43),
|
||||
new ECB(4, 44)),
|
||||
new ECBlocks(28, new ECB(17, 22),
|
||||
new ECB(1, 23)),
|
||||
new ECBlocks(28, new ECB(2, 14),
|
||||
new ECB(19, 15))),
|
||||
new Version(19, new int[] {6, 30, 58, 86},
|
||||
new ECBlocks(28, new ECB(3, 113),
|
||||
new ECB(4, 114)),
|
||||
new ECBlocks(26, new ECB(3, 44),
|
||||
new ECB(11, 45)),
|
||||
new ECBlocks(26, new ECB(17, 21),
|
||||
new ECB(4, 22)),
|
||||
new ECBlocks(26, new ECB(9, 13),
|
||||
new ECB(16, 14))),
|
||||
new Version(20, new int[] {6, 34, 62, 90},
|
||||
new ECBlocks(28, new ECB(3, 107),
|
||||
new ECB(5, 108)),
|
||||
new ECBlocks(26, new ECB(3, 41),
|
||||
new ECB(13, 42)),
|
||||
new ECBlocks(30, new ECB(15, 24),
|
||||
new ECB(5, 25)),
|
||||
new ECBlocks(28, new ECB(15, 15),
|
||||
new ECB(10, 16))),
|
||||
new Version(21, new int[] {6, 28, 50, 72, 94},
|
||||
new ECBlocks(28, new ECB(4, 116),
|
||||
new ECB(4, 117)),
|
||||
new ECBlocks(26, new ECB(17, 42)),
|
||||
new ECBlocks(28, new ECB(17, 22),
|
||||
new ECB(6, 23)),
|
||||
new ECBlocks(30, new ECB(19, 16),
|
||||
new ECB(6, 17))),
|
||||
new Version(22, new int[] {6, 26, 50, 74, 98},
|
||||
new ECBlocks(28, new ECB(2, 111),
|
||||
new ECB(7, 112)),
|
||||
new ECBlocks(28, new ECB(17, 46)),
|
||||
new ECBlocks(30, new ECB(7, 24),
|
||||
new ECB(16, 25)),
|
||||
new ECBlocks(24, new ECB(34, 13))),
|
||||
new Version(23, new int[] {6, 30, 54, 78, 102},
|
||||
new ECBlocks(30, new ECB(4, 121),
|
||||
new ECB(5, 122)),
|
||||
new ECBlocks(28, new ECB(4, 47),
|
||||
new ECB(14, 48)),
|
||||
new ECBlocks(30, new ECB(11, 24),
|
||||
new ECB(14, 25)),
|
||||
new ECBlocks(30, new ECB(16, 15),
|
||||
new ECB(14, 16))),
|
||||
new Version(24, new int[] {6, 28, 54, 80, 106},
|
||||
new ECBlocks(30, new ECB(6, 117),
|
||||
new ECB(4, 118)),
|
||||
new ECBlocks(28, new ECB(6, 45),
|
||||
new ECB(14, 46)),
|
||||
new ECBlocks(30, new ECB(11, 24),
|
||||
new ECB(16, 25)),
|
||||
new ECBlocks(30, new ECB(30, 16),
|
||||
new ECB(2, 17))),
|
||||
new Version(25, new int[] {6, 32, 58, 84, 110},
|
||||
new ECBlocks(26, new ECB(8, 106),
|
||||
new ECB(4, 107)),
|
||||
new ECBlocks(28, new ECB(8, 47),
|
||||
new ECB(13, 48)),
|
||||
new ECBlocks(30, new ECB(7, 24),
|
||||
new ECB(22, 25)),
|
||||
new ECBlocks(30, new ECB(22, 15),
|
||||
new ECB(13, 16))),
|
||||
new Version(26, new int[] {6, 30, 58, 86, 114},
|
||||
new ECBlocks(28, new ECB(10, 114),
|
||||
new ECB(2, 115)),
|
||||
new ECBlocks(28, new ECB(19, 46),
|
||||
new ECB(4, 47)),
|
||||
new ECBlocks(28, new ECB(28, 22),
|
||||
new ECB(6, 23)),
|
||||
new ECBlocks(30, new ECB(33, 16),
|
||||
new ECB(4, 17))),
|
||||
new Version(27, new int[] {6, 34, 62, 90, 118},
|
||||
new ECBlocks(30, new ECB(8, 122),
|
||||
new ECB(4, 123)),
|
||||
new ECBlocks(28, new ECB(22, 45),
|
||||
new ECB(3, 46)),
|
||||
new ECBlocks(30, new ECB(8, 23),
|
||||
new ECB(26, 24)),
|
||||
new ECBlocks(30, new ECB(12, 15),
|
||||
new ECB(28, 16))),
|
||||
new Version(28, new int[] {6, 26, 50, 74, 98, 122},
|
||||
new ECBlocks(30, new ECB(3, 117),
|
||||
new ECB(10, 118)),
|
||||
new ECBlocks(28, new ECB(3, 45),
|
||||
new ECB(23, 46)),
|
||||
new ECBlocks(30, new ECB(4, 24),
|
||||
new ECB(31, 25)),
|
||||
new ECBlocks(30, new ECB(11, 15),
|
||||
new ECB(31, 16))),
|
||||
new Version(29, new int[] {6, 30, 54, 78, 102, 126},
|
||||
new ECBlocks(30, new ECB(7, 116),
|
||||
new ECB(7, 117)),
|
||||
new ECBlocks(28, new ECB(21, 45),
|
||||
new ECB(7, 46)),
|
||||
new ECBlocks(30, new ECB(1, 23),
|
||||
new ECB(37, 24)),
|
||||
new ECBlocks(30, new ECB(19, 15),
|
||||
new ECB(26, 16))),
|
||||
new Version(30, new int[] {6, 26, 52, 78, 104, 130},
|
||||
new ECBlocks(30, new ECB(5, 115),
|
||||
new ECB(10, 116)),
|
||||
new ECBlocks(28, new ECB(19, 47),
|
||||
new ECB(10, 48)),
|
||||
new ECBlocks(30, new ECB(15, 24),
|
||||
new ECB(25, 25)),
|
||||
new ECBlocks(30, new ECB(23, 15),
|
||||
new ECB(25, 16))),
|
||||
new Version(31, new int[] {6, 30, 56, 82, 108, 134},
|
||||
new ECBlocks(30, new ECB(13, 115),
|
||||
new ECB(3, 116)),
|
||||
new ECBlocks(28, new ECB(2, 46),
|
||||
new ECB(29, 47)),
|
||||
new ECBlocks(30, new ECB(42, 24),
|
||||
new ECB(1, 25)),
|
||||
new ECBlocks(30, new ECB(23, 15),
|
||||
new ECB(28, 16))),
|
||||
new Version(32, new int[] {6, 34, 60, 86, 112, 138},
|
||||
new ECBlocks(30, new ECB(17, 115)),
|
||||
new ECBlocks(28, new ECB(10, 46),
|
||||
new ECB(23, 47)),
|
||||
new ECBlocks(30, new ECB(10, 24),
|
||||
new ECB(35, 25)),
|
||||
new ECBlocks(30, new ECB(19, 15),
|
||||
new ECB(35, 16))),
|
||||
new Version(33, new int[] {6, 30, 58, 86, 114, 142},
|
||||
new ECBlocks(30, new ECB(17, 115),
|
||||
new ECB(1, 116)),
|
||||
new ECBlocks(28, new ECB(14, 46),
|
||||
new ECB(21, 47)),
|
||||
new ECBlocks(30, new ECB(29, 24),
|
||||
new ECB(19, 25)),
|
||||
new ECBlocks(30, new ECB(11, 15),
|
||||
new ECB(46, 16))),
|
||||
new Version(34, new int[] {6, 34, 62, 90, 118, 146},
|
||||
new ECBlocks(30, new ECB(13, 115),
|
||||
new ECB(6, 116)),
|
||||
new ECBlocks(28, new ECB(14, 46),
|
||||
new ECB(23, 47)),
|
||||
new ECBlocks(30, new ECB(44, 24),
|
||||
new ECB(7, 25)),
|
||||
new ECBlocks(30, new ECB(59, 16),
|
||||
new ECB(1, 17))),
|
||||
new Version(35, new int[] {6, 30, 54, 78, 102, 126, 150},
|
||||
new ECBlocks(30, new ECB(12, 121),
|
||||
new ECB(7, 122)),
|
||||
new ECBlocks(28, new ECB(12, 47),
|
||||
new ECB(26, 48)),
|
||||
new ECBlocks(30, new ECB(39, 24),
|
||||
new ECB(14, 25)),
|
||||
new ECBlocks(30, new ECB(22, 15),
|
||||
new ECB(41, 16))),
|
||||
new Version(36, new int[] {6, 24, 50, 76, 102, 128, 154},
|
||||
new ECBlocks(30, new ECB(6, 121),
|
||||
new ECB(14, 122)),
|
||||
new ECBlocks(28, new ECB(6, 47),
|
||||
new ECB(34, 48)),
|
||||
new ECBlocks(30, new ECB(46, 24),
|
||||
new ECB(10, 25)),
|
||||
new ECBlocks(30, new ECB(2, 15),
|
||||
new ECB(64, 16))),
|
||||
new Version(37, new int[] {6, 28, 54, 80, 106, 132, 158},
|
||||
new ECBlocks(30, new ECB(17, 122),
|
||||
new ECB(4, 123)),
|
||||
new ECBlocks(28, new ECB(29, 46),
|
||||
new ECB(14, 47)),
|
||||
new ECBlocks(30, new ECB(49, 24),
|
||||
new ECB(10, 25)),
|
||||
new ECBlocks(30, new ECB(24, 15),
|
||||
new ECB(46, 16))),
|
||||
new Version(38, new int[] {6, 32, 58, 84, 110, 136, 162},
|
||||
new ECBlocks(30, new ECB(4, 122),
|
||||
new ECB(18, 123)),
|
||||
new ECBlocks(28, new ECB(13, 46),
|
||||
new ECB(32, 47)),
|
||||
new ECBlocks(30, new ECB(48, 24),
|
||||
new ECB(14, 25)),
|
||||
new ECBlocks(30, new ECB(42, 15),
|
||||
new ECB(32, 16))),
|
||||
new Version(39, new int[] {6, 26, 54, 82, 110, 138, 166},
|
||||
new ECBlocks(30, new ECB(20, 117),
|
||||
new ECB(4, 118)),
|
||||
new ECBlocks(28, new ECB(40, 47),
|
||||
new ECB(7, 48)),
|
||||
new ECBlocks(30, new ECB(43, 24),
|
||||
new ECB(22, 25)),
|
||||
new ECBlocks(30, new ECB(10, 15),
|
||||
new ECB(67, 16))),
|
||||
new Version(40, new int[] {6, 30, 58, 86, 114, 142, 170},
|
||||
new ECBlocks(30, new ECB(19, 118),
|
||||
new ECB(6, 119)),
|
||||
new ECBlocks(28, new ECB(18, 47),
|
||||
new ECB(31, 48)),
|
||||
new ECBlocks(30, new ECB(34, 24),
|
||||
new ECB(34, 25)),
|
||||
new ECBlocks(30, new ECB(20, 15),
|
||||
new ECB(61, 16)))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user