mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-30 13:13:24 +08:00
添加项目文件。
This commit is contained in:
52
zxing.core/xx/aztec/encoder/AztecCode.cs
Normal file
52
zxing.core/xx/aztec/encoder/AztecCode.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
using ZXing.Common;
|
||||
|
||||
namespace ZXing.Aztec.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Aztec 2D code representation
|
||||
/// </summary>
|
||||
/// <author>Rustam Abdullaev</author>
|
||||
public sealed class AztecCode
|
||||
{
|
||||
/// <summary>
|
||||
/// Compact or full symbol indicator
|
||||
/// </summary>
|
||||
public bool isCompact { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size in pixels (width and height)
|
||||
/// </summary>
|
||||
public int Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of levels
|
||||
/// </summary>
|
||||
public int Layers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of data codewords
|
||||
/// </summary>
|
||||
public int CodeWords { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The symbol image
|
||||
/// </summary>
|
||||
public BitMatrix Matrix { get; set; }
|
||||
}
|
||||
}
|
||||
86
zxing.core/xx/aztec/encoder/AztecEncodingOptions.cs
Normal file
86
zxing.core/xx/aztec/encoder/AztecEncodingOptions.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing.Net 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.Aztec
|
||||
{
|
||||
/// <summary>
|
||||
/// The class holds the available options for the <see cref="AztecWriter" />
|
||||
/// </summary>
|
||||
public class AztecEncodingOptions : EncodingOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Representing the minimal percentage of error correction words.
|
||||
/// Note: an Aztec symbol should have a minimum of 25% EC words.
|
||||
/// </summary>
|
||||
public int? ErrorCorrection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Hints.ContainsKey(EncodeHintType.ERROR_CORRECTION))
|
||||
{
|
||||
return (int)Hints[EncodeHintType.ERROR_CORRECTION];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
if (Hints.ContainsKey(EncodeHintType.ERROR_CORRECTION))
|
||||
Hints.Remove(EncodeHintType.ERROR_CORRECTION);
|
||||
}
|
||||
else
|
||||
{
|
||||
Hints[EncodeHintType.ERROR_CORRECTION] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the required number of layers for an Aztec code:
|
||||
/// a negative number (-1, -2, -3, -4) specifies a compact Aztec code
|
||||
/// 0 indicates to use the minimum number of layers (the default)
|
||||
/// a positive number (1, 2, .. 32) specifies a normal (non-compact) Aztec code
|
||||
/// </summary>
|
||||
public int? Layers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Hints.ContainsKey(EncodeHintType.AZTEC_LAYERS))
|
||||
{
|
||||
return (int)Hints[EncodeHintType.AZTEC_LAYERS];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
if (Hints.ContainsKey(EncodeHintType.AZTEC_LAYERS))
|
||||
Hints.Remove(EncodeHintType.AZTEC_LAYERS);
|
||||
}
|
||||
else
|
||||
{
|
||||
Hints[EncodeHintType.AZTEC_LAYERS] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
zxing.core/xx/aztec/encoder/BinaryShiftToken.cs
Normal file
70
zxing.core/xx/aztec/encoder/BinaryShiftToken.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
using ZXing.Common;
|
||||
|
||||
namespace ZXing.Aztec.Internal
|
||||
{
|
||||
public sealed class BinaryShiftToken : Token
|
||||
{
|
||||
private readonly short binaryShiftStart;
|
||||
private readonly short binaryShiftByteCount;
|
||||
|
||||
public BinaryShiftToken(Token previous,
|
||||
int binaryShiftStart,
|
||||
int binaryShiftByteCount)
|
||||
: base(previous)
|
||||
{
|
||||
this.binaryShiftStart = (short) binaryShiftStart;
|
||||
this.binaryShiftByteCount = (short) binaryShiftByteCount;
|
||||
}
|
||||
|
||||
public override void appendTo(BitArray bitArray, byte[] text)
|
||||
{
|
||||
for (int i = 0; i < binaryShiftByteCount; i++)
|
||||
{
|
||||
if (i == 0 || (i == 31 && binaryShiftByteCount <= 62))
|
||||
{
|
||||
// We need a header before the first character, and before
|
||||
// character 31 when the total byte code is <= 62
|
||||
bitArray.appendBits(31, 5); // BINARY_SHIFT
|
||||
if (binaryShiftByteCount > 62)
|
||||
{
|
||||
bitArray.appendBits(binaryShiftByteCount - 31, 16);
|
||||
}
|
||||
else if (i == 0)
|
||||
{
|
||||
// 1 <= binaryShiftByteCode <= 62
|
||||
bitArray.appendBits(Math.Min(binaryShiftByteCount, (short) 31), 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 32 <= binaryShiftCount <= 62 and i == 31
|
||||
bitArray.appendBits(binaryShiftByteCount - 31, 5);
|
||||
}
|
||||
}
|
||||
bitArray.appendBits(text[binaryShiftStart + i], 8);
|
||||
}
|
||||
}
|
||||
|
||||
public override String ToString()
|
||||
{
|
||||
return "<" + binaryShiftStart + "::" + (binaryShiftStart + binaryShiftByteCount - 1) + '>';
|
||||
}
|
||||
}
|
||||
}
|
||||
428
zxing.core/xx/aztec/encoder/Encoder.cs
Normal file
428
zxing.core/xx/aztec/encoder/Encoder.cs
Normal file
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
using ZXing.Common;
|
||||
using ZXing.Common.ReedSolomon;
|
||||
|
||||
namespace ZXing.Aztec.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates Aztec 2D barcodes.
|
||||
/// </summary>
|
||||
/// <author>Rustam Abdullaev</author>
|
||||
public static class Encoder
|
||||
{
|
||||
public const int DEFAULT_EC_PERCENT = 33; // default minimal percentage of error check words
|
||||
public const int DEFAULT_AZTEC_LAYERS = 0;
|
||||
private const int MAX_NB_BITS = 32;
|
||||
private const int MAX_NB_BITS_COMPACT = 4;
|
||||
|
||||
private static readonly int[] WORD_SIZE = {
|
||||
4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
12, 12, 12, 12, 12, 12, 12, 12, 12, 12
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Encodes the given binary content as an Aztec symbol
|
||||
/// </summary>
|
||||
/// <param name="data">input data string</param>
|
||||
/// <returns>Aztec symbol matrix with metadata</returns>
|
||||
|
||||
public static AztecCode encode(byte[] data)
|
||||
{
|
||||
return encode(data, DEFAULT_EC_PERCENT, DEFAULT_AZTEC_LAYERS);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes the given binary content as an Aztec symbol
|
||||
/// </summary>
|
||||
/// <param name="data">input data string</param>
|
||||
/// <param name="minECCPercent">minimal percentage of error check words (According to ISO/IEC 24778:2008,
|
||||
/// a minimum of 23% + 3 words is recommended)</param>
|
||||
/// <param name="userSpecifiedLayers">if non-zero, a user-specified value for the number of layers</param>
|
||||
/// <returns>
|
||||
/// Aztec symbol matrix with metadata
|
||||
/// </returns>
|
||||
public static AztecCode encode(byte[] data, int minECCPercent, int userSpecifiedLayers)
|
||||
{
|
||||
// High-level encode
|
||||
var bits = new HighLevelEncoder(data).encode();
|
||||
|
||||
// stuff bits and choose symbol size
|
||||
int eccBits = bits.Size*minECCPercent/100 + 11;
|
||||
int totalSizeBits = bits.Size + eccBits;
|
||||
bool compact;
|
||||
int layers;
|
||||
int totalBitsInLayer;
|
||||
int wordSize;
|
||||
BitArray stuffedBits;
|
||||
|
||||
if (userSpecifiedLayers != DEFAULT_AZTEC_LAYERS)
|
||||
{
|
||||
compact = userSpecifiedLayers < 0;
|
||||
layers = Math.Abs(userSpecifiedLayers);
|
||||
if (layers > (compact ? MAX_NB_BITS_COMPACT : MAX_NB_BITS))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
String.Format("Illegal value {0} for layers", userSpecifiedLayers));
|
||||
}
|
||||
totalBitsInLayer = TotalBitsInLayer(layers, compact);
|
||||
wordSize = WORD_SIZE[layers];
|
||||
int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer%wordSize);
|
||||
stuffedBits = stuffBits(bits, wordSize);
|
||||
if (stuffedBits.Size + eccBits > usableBitsInLayers)
|
||||
{
|
||||
throw new ArgumentException("Data to large for user specified layer");
|
||||
}
|
||||
if (compact && stuffedBits.Size > wordSize*64)
|
||||
{
|
||||
// Compact format only allows 64 data words, though C4 can hold more words than that
|
||||
throw new ArgumentException("Data to large for user specified layer");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wordSize = 0;
|
||||
stuffedBits = null;
|
||||
// We look at the possible table sizes in the order Compact1, Compact2, Compact3,
|
||||
// Compact4, Normal4,... Normal(i) for i < 4 isn't typically used since Compact(i+1)
|
||||
// is the same size, but has more data.
|
||||
for (int i = 0;; i++)
|
||||
{
|
||||
if (i > MAX_NB_BITS)
|
||||
{
|
||||
throw new ArgumentException("Data too large for an Aztec code");
|
||||
}
|
||||
compact = i <= 3;
|
||||
layers = compact ? i + 1 : i;
|
||||
totalBitsInLayer = TotalBitsInLayer(layers, compact);
|
||||
if (totalSizeBits > totalBitsInLayer)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// [Re]stuff the bits if this is the first opportunity, or if the
|
||||
// wordSize has changed
|
||||
if (wordSize != WORD_SIZE[layers])
|
||||
{
|
||||
wordSize = WORD_SIZE[layers];
|
||||
stuffedBits = stuffBits(bits, wordSize);
|
||||
}
|
||||
if (stuffedBits == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer%wordSize);
|
||||
if (compact && stuffedBits.Size > wordSize*64)
|
||||
{
|
||||
// Compact format only allows 64 data words, though C4 can hold more words than that
|
||||
continue;
|
||||
}
|
||||
if (stuffedBits.Size + eccBits <= usableBitsInLayers)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BitArray messageBits = generateCheckWords(stuffedBits, totalBitsInLayer, wordSize);
|
||||
|
||||
// generate mode message
|
||||
int messageSizeInWords = stuffedBits.Size / wordSize;
|
||||
var modeMessage = generateModeMessage(compact, layers, messageSizeInWords);
|
||||
|
||||
// allocate symbol
|
||||
var baseMatrixSize = compact ? 11 + layers*4 : 14 + layers*4; // not including alignment lines
|
||||
var alignmentMap = new int[baseMatrixSize];
|
||||
int matrixSize;
|
||||
if (compact)
|
||||
{
|
||||
// no alignment marks in compact mode, alignmentMap is a no-op
|
||||
matrixSize = baseMatrixSize;
|
||||
for (int i = 0; i < alignmentMap.Length; i++)
|
||||
{
|
||||
alignmentMap[i] = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
matrixSize = baseMatrixSize + 1 + 2*((baseMatrixSize/2 - 1)/15);
|
||||
int origCenter = baseMatrixSize/2;
|
||||
int center = matrixSize/2;
|
||||
for (int i = 0; i < origCenter; i++)
|
||||
{
|
||||
int newOffset = i + i/15;
|
||||
alignmentMap[origCenter - i - 1] = center - newOffset - 1;
|
||||
alignmentMap[origCenter + i] = center + newOffset + 1;
|
||||
}
|
||||
}
|
||||
var matrix = new BitMatrix(matrixSize);
|
||||
|
||||
// draw data bits
|
||||
for (int i = 0, rowOffset = 0; i < layers; i++)
|
||||
{
|
||||
int rowSize = compact ? (layers - i)*4 + 9 : (layers - i)*4 + 12;
|
||||
for (int j = 0; j < rowSize; j++)
|
||||
{
|
||||
int columnOffset = j*2;
|
||||
for (int k = 0; k < 2; k++)
|
||||
{
|
||||
if (messageBits[rowOffset + columnOffset + k])
|
||||
{
|
||||
matrix[alignmentMap[i*2 + k], alignmentMap[i*2 + j]] = true;
|
||||
}
|
||||
if (messageBits[rowOffset + rowSize*2 + columnOffset + k])
|
||||
{
|
||||
matrix[alignmentMap[i*2 + j], alignmentMap[baseMatrixSize - 1 - i*2 - k]] = true;
|
||||
}
|
||||
if (messageBits[rowOffset + rowSize*4 + columnOffset + k])
|
||||
{
|
||||
matrix[alignmentMap[baseMatrixSize - 1 - i*2 - k], alignmentMap[baseMatrixSize - 1 - i*2 - j]] = true;
|
||||
}
|
||||
if (messageBits[rowOffset + rowSize*6 + columnOffset + k])
|
||||
{
|
||||
matrix[alignmentMap[baseMatrixSize - 1 - i*2 - j], alignmentMap[i*2 + k]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
rowOffset += rowSize*8;
|
||||
}
|
||||
|
||||
// draw mode message
|
||||
drawModeMessage(matrix, compact, matrixSize, modeMessage);
|
||||
|
||||
// draw alignment marks
|
||||
if (compact)
|
||||
{
|
||||
drawBullsEye(matrix, matrixSize/2, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawBullsEye(matrix, matrixSize/2, 7);
|
||||
for (int i = 0, j = 0; i < baseMatrixSize/2 - 1; i += 15, j += 16)
|
||||
{
|
||||
for (int k = (matrixSize/2) & 1; k < matrixSize; k += 2)
|
||||
{
|
||||
matrix[matrixSize/2 - j, k] = true;
|
||||
matrix[matrixSize/2 + j, k] = true;
|
||||
matrix[k, matrixSize/2 - j] = true;
|
||||
matrix[k, matrixSize/2 + j] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new AztecCode
|
||||
{
|
||||
isCompact = compact,
|
||||
Size = matrixSize,
|
||||
Layers = layers,
|
||||
CodeWords = messageSizeInWords,
|
||||
Matrix = matrix
|
||||
};
|
||||
}
|
||||
|
||||
private static void drawBullsEye(BitMatrix matrix, int center, int size)
|
||||
{
|
||||
for (var i = 0; i < size; i += 2)
|
||||
{
|
||||
for (var j = center - i; j <= center + i; j++)
|
||||
{
|
||||
matrix[j, center - i] = true;
|
||||
matrix[j, center + i] = true;
|
||||
matrix[center - i, j] = true;
|
||||
matrix[center + i, j] = true;
|
||||
}
|
||||
}
|
||||
matrix[center - size, center - size] = true;
|
||||
matrix[center - size + 1, center - size] = true;
|
||||
matrix[center - size, center - size + 1] = true;
|
||||
matrix[center + size, center - size] = true;
|
||||
matrix[center + size, center - size + 1] = true;
|
||||
matrix[center + size, center + size - 1] = true;
|
||||
}
|
||||
|
||||
internal static BitArray generateModeMessage(bool compact, int layers, int messageSizeInWords)
|
||||
{
|
||||
var modeMessage = new BitArray();
|
||||
if (compact)
|
||||
{
|
||||
modeMessage.appendBits(layers - 1, 2);
|
||||
modeMessage.appendBits(messageSizeInWords - 1, 6);
|
||||
modeMessage = generateCheckWords(modeMessage, 28, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
modeMessage.appendBits(layers - 1, 5);
|
||||
modeMessage.appendBits(messageSizeInWords - 1, 11);
|
||||
modeMessage = generateCheckWords(modeMessage, 40, 4);
|
||||
}
|
||||
return modeMessage;
|
||||
}
|
||||
|
||||
private static void drawModeMessage(BitMatrix matrix, bool compact, int matrixSize, BitArray modeMessage)
|
||||
{
|
||||
int center = matrixSize / 2;
|
||||
|
||||
if (compact)
|
||||
{
|
||||
for (var i = 0; i < 7; i++)
|
||||
{
|
||||
int offset = center - 3 + i;
|
||||
if (modeMessage[i])
|
||||
{
|
||||
matrix[offset, center - 5] = true;
|
||||
}
|
||||
if (modeMessage[i + 7])
|
||||
{
|
||||
matrix[center + 5, offset] = true;
|
||||
}
|
||||
if (modeMessage[20 - i])
|
||||
{
|
||||
matrix[offset, center + 5] = true;
|
||||
}
|
||||
if (modeMessage[27 - i])
|
||||
{
|
||||
matrix[center - 5, offset] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
int offset = center - 5 + i + i / 5;
|
||||
if (modeMessage[i])
|
||||
{
|
||||
matrix[offset, center - 7] = true;
|
||||
}
|
||||
if (modeMessage[i + 10])
|
||||
{
|
||||
matrix[center + 7, offset] = true;
|
||||
}
|
||||
if (modeMessage[29 - i])
|
||||
{
|
||||
matrix[offset, center + 7] = true;
|
||||
}
|
||||
if (modeMessage[39 - i])
|
||||
{
|
||||
matrix[center - 7, offset] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static BitArray generateCheckWords(BitArray bitArray, int totalBits, int wordSize)
|
||||
{
|
||||
if (bitArray.Size % wordSize != 0)
|
||||
throw new InvalidOperationException("size of bit array is not a multiple of the word size");
|
||||
|
||||
// bitArray is guaranteed to be a multiple of the wordSize, so no padding needed
|
||||
int messageSizeInWords = bitArray.Size / wordSize;
|
||||
|
||||
var rs = new ReedSolomonEncoder(getGF(wordSize));
|
||||
var totalWords = totalBits / wordSize;
|
||||
var messageWords = bitsToWords(bitArray, wordSize, totalWords);
|
||||
rs.encode(messageWords, totalWords - messageSizeInWords);
|
||||
|
||||
var startPad = totalBits % wordSize;
|
||||
var messageBits = new BitArray();
|
||||
messageBits.appendBits(0, startPad);
|
||||
foreach (var messageWord in messageWords)
|
||||
{
|
||||
messageBits.appendBits(messageWord, wordSize);
|
||||
}
|
||||
return messageBits;
|
||||
}
|
||||
|
||||
private static int[] bitsToWords(BitArray stuffedBits, int wordSize, int totalWords)
|
||||
{
|
||||
var message = new int[totalWords];
|
||||
int i;
|
||||
int n;
|
||||
for (i = 0, n = stuffedBits.Size / wordSize; i < n; i++)
|
||||
{
|
||||
int value = 0;
|
||||
for (int j = 0; j < wordSize; j++)
|
||||
{
|
||||
value |= stuffedBits[i * wordSize + j] ? (1 << wordSize - j - 1) : 0;
|
||||
}
|
||||
message[i] = value;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
private static GenericGF getGF(int wordSize)
|
||||
{
|
||||
switch (wordSize)
|
||||
{
|
||||
case 4:
|
||||
return GenericGF.AZTEC_PARAM;
|
||||
case 6:
|
||||
return GenericGF.AZTEC_DATA_6;
|
||||
case 8:
|
||||
return GenericGF.AZTEC_DATA_8;
|
||||
case 10:
|
||||
return GenericGF.AZTEC_DATA_10;
|
||||
case 12:
|
||||
return GenericGF.AZTEC_DATA_12;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal static BitArray stuffBits(BitArray bits, int wordSize)
|
||||
{
|
||||
var @out = new BitArray();
|
||||
|
||||
int n = bits.Size;
|
||||
int mask = (1 << wordSize) - 2;
|
||||
for (int i = 0; i < n; i += wordSize)
|
||||
{
|
||||
int word = 0;
|
||||
for (int j = 0; j < wordSize; j++)
|
||||
{
|
||||
if (i + j >= n || bits[i + j])
|
||||
{
|
||||
word |= 1 << (wordSize - 1 - j);
|
||||
}
|
||||
}
|
||||
if ((word & mask) == mask)
|
||||
{
|
||||
@out.appendBits(word & mask, wordSize);
|
||||
i--;
|
||||
}
|
||||
else if ((word & mask) == 0)
|
||||
{
|
||||
@out.appendBits(word | 1, wordSize);
|
||||
i--;
|
||||
}
|
||||
else
|
||||
{
|
||||
@out.appendBits(word, wordSize);
|
||||
}
|
||||
}
|
||||
|
||||
return @out;
|
||||
}
|
||||
|
||||
private static int TotalBitsInLayer(int layers, bool compact)
|
||||
{
|
||||
return ((compact ? 88 : 112) + 16 * layers) * layers;
|
||||
}
|
||||
}
|
||||
}
|
||||
379
zxing.core/xx/aztec/encoder/HighLevelEncoder.cs
Normal file
379
zxing.core/xx/aztec/encoder/HighLevelEncoder.cs
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using ZXing.Common;
|
||||
|
||||
namespace ZXing.Aztec.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// This produces nearly optimal encodings of text into the first-level of
|
||||
/// encoding used by Aztec code.
|
||||
/// It uses a dynamic algorithm. For each prefix of the string, it determines
|
||||
/// a set of encodings that could lead to this prefix. We repeatedly add a
|
||||
/// character and generate a new set of optimal encodings until we have read
|
||||
/// through the entire input.
|
||||
/// @author Frank Yellin
|
||||
/// @author Rustam Abdullaev
|
||||
/// </summary>
|
||||
public sealed class HighLevelEncoder
|
||||
{
|
||||
|
||||
internal static String[] MODE_NAMES = {"UPPER", "LOWER", "DIGIT", "MIXED", "PUNCT"};
|
||||
|
||||
internal const int MODE_UPPER = 0; // 5 bits
|
||||
internal const int MODE_LOWER = 1; // 5 bits
|
||||
internal const int MODE_DIGIT = 2; // 4 bits
|
||||
internal const int MODE_MIXED = 3; // 5 bits
|
||||
internal const int MODE_PUNCT = 4; // 5 bits
|
||||
|
||||
// The Latch Table shows, for each pair of Modes, the optimal method for
|
||||
// getting from one mode to another. In the worst possible case, this can
|
||||
// be up to 14 bits. In the best possible case, we are already there!
|
||||
// The high half-word of each entry gives the number of bits.
|
||||
// The low half-word of each entry are the actual bits necessary to change
|
||||
internal static readonly int[][] LATCH_TABLE = new int[][]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
0,
|
||||
(5 << 16) + 28, // UPPER -> LOWER
|
||||
(5 << 16) + 30, // UPPER -> DIGIT
|
||||
(5 << 16) + 29, // UPPER -> MIXED
|
||||
(10 << 16) + (29 << 5) + 30, // UPPER -> MIXED -> PUNCT
|
||||
},
|
||||
new[]
|
||||
{
|
||||
(9 << 16) + (30 << 4) + 14, // LOWER -> DIGIT -> UPPER
|
||||
0,
|
||||
(5 << 16) + 30, // LOWER -> DIGIT
|
||||
(5 << 16) + 29, // LOWER -> MIXED
|
||||
(10 << 16) + (29 << 5) + 30, // LOWER -> MIXED -> PUNCT
|
||||
},
|
||||
new[]
|
||||
{
|
||||
(4 << 16) + 14, // DIGIT -> UPPER
|
||||
(9 << 16) + (14 << 5) + 28, // DIGIT -> UPPER -> LOWER
|
||||
0,
|
||||
(9 << 16) + (14 << 5) + 29, // DIGIT -> UPPER -> MIXED
|
||||
(14 << 16) + (14 << 10) + (29 << 5) + 30,
|
||||
// DIGIT -> UPPER -> MIXED -> PUNCT
|
||||
},
|
||||
new[]
|
||||
{
|
||||
(5 << 16) + 29, // MIXED -> UPPER
|
||||
(5 << 16) + 28, // MIXED -> LOWER
|
||||
(10 << 16) + (29 << 5) + 30, // MIXED -> UPPER -> DIGIT
|
||||
0,
|
||||
(5 << 16) + 30, // MIXED -> PUNCT
|
||||
},
|
||||
new[]
|
||||
{
|
||||
(5 << 16) + 31, // PUNCT -> UPPER
|
||||
(10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> LOWER
|
||||
(10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> DIGIT
|
||||
(10 << 16) + (31 << 5) + 29, // PUNCT -> UPPER -> MIXED
|
||||
0,
|
||||
},
|
||||
};
|
||||
|
||||
// A reverse mapping from [mode][char] to the encoding for that character
|
||||
// in that mode. An entry of 0 indicates no mapping exists.
|
||||
internal static readonly int[][] CHAR_MAP = new int[5][];
|
||||
// A map showing the available shift codes. (The shifts to BINARY are not shown
|
||||
internal static readonly int[][] SHIFT_TABLE = new int[6][]; // mode shift codes, per table
|
||||
private readonly byte[] text;
|
||||
|
||||
static HighLevelEncoder()
|
||||
{
|
||||
CHAR_MAP[0] = new int[256];
|
||||
CHAR_MAP[1] = new int[256];
|
||||
CHAR_MAP[2] = new int[256];
|
||||
CHAR_MAP[3] = new int[256];
|
||||
CHAR_MAP[4] = new int[256];
|
||||
|
||||
SHIFT_TABLE[0] = new int[6];
|
||||
SHIFT_TABLE[1] = new int[6];
|
||||
SHIFT_TABLE[2] = new int[6];
|
||||
SHIFT_TABLE[3] = new int[6];
|
||||
SHIFT_TABLE[4] = new int[6];
|
||||
SHIFT_TABLE[5] = new int[6];
|
||||
|
||||
CHAR_MAP[MODE_UPPER][' '] = 1;
|
||||
for (int c = 'A'; c <= 'Z'; c++)
|
||||
{
|
||||
CHAR_MAP[MODE_UPPER][c] = c - 'A' + 2;
|
||||
}
|
||||
CHAR_MAP[MODE_LOWER][' '] = 1;
|
||||
for (int c = 'a'; c <= 'z'; c++)
|
||||
{
|
||||
CHAR_MAP[MODE_LOWER][c] = c - 'a' + 2;
|
||||
}
|
||||
CHAR_MAP[MODE_DIGIT][' '] = 1;
|
||||
for (int c = '0'; c <= '9'; c++)
|
||||
{
|
||||
CHAR_MAP[MODE_DIGIT][c] = c - '0' + 2;
|
||||
}
|
||||
CHAR_MAP[MODE_DIGIT][','] = 12;
|
||||
CHAR_MAP[MODE_DIGIT]['.'] = 13;
|
||||
int[] mixedTable = {
|
||||
'\0', ' ', 1, 2, 3, 4, 5, 6, 7, '\b', '\t', '\n', 11, '\f', '\r',
|
||||
27, 28, 29, 30, 31, '@', '\\', '^', '_', '`', '|', '~', 127
|
||||
};
|
||||
for (int i = 0; i < mixedTable.Length; i++)
|
||||
{
|
||||
CHAR_MAP[MODE_MIXED][mixedTable[i]] = i;
|
||||
}
|
||||
int[] punctTable =
|
||||
{
|
||||
'\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'',
|
||||
'(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?',
|
||||
'[', ']', '{', '}'
|
||||
};
|
||||
for (int i = 0; i < punctTable.Length; i++)
|
||||
{
|
||||
if (punctTable[i] > 0)
|
||||
{
|
||||
CHAR_MAP[MODE_PUNCT][punctTable[i]] = i;
|
||||
}
|
||||
}
|
||||
foreach (int[] table in SHIFT_TABLE)
|
||||
{
|
||||
SupportClass.Fill(table, -1);
|
||||
}
|
||||
SHIFT_TABLE[MODE_UPPER][MODE_PUNCT] = 0;
|
||||
|
||||
SHIFT_TABLE[MODE_LOWER][MODE_PUNCT] = 0;
|
||||
SHIFT_TABLE[MODE_LOWER][MODE_UPPER] = 28;
|
||||
|
||||
SHIFT_TABLE[MODE_MIXED][MODE_PUNCT] = 0;
|
||||
|
||||
SHIFT_TABLE[MODE_DIGIT][MODE_PUNCT] = 0;
|
||||
SHIFT_TABLE[MODE_DIGIT][MODE_UPPER] = 15;
|
||||
}
|
||||
|
||||
public HighLevelEncoder(byte[] text)
|
||||
{
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the text represented by this High Level Encoder into a BitArray.
|
||||
/// </summary>
|
||||
/// <returns>text represented by this encoder encoded as a <see cref="BitArray"/></returns>
|
||||
public BitArray encode()
|
||||
{
|
||||
ICollection<State> states = new Collection<State>();
|
||||
states.Add(State.INITIAL_STATE);
|
||||
for (int index = 0; index < text.Length; index++)
|
||||
{
|
||||
int pairCode;
|
||||
// don't remove the (int) type cast, mono compiler needs it
|
||||
int nextChar = (index + 1 < text.Length) ? (int)text[index + 1] : 0;
|
||||
switch (text[index])
|
||||
{
|
||||
case (byte)'\r':
|
||||
pairCode = nextChar == '\n' ? 2 : 0;
|
||||
break;
|
||||
case (byte)'.':
|
||||
pairCode = nextChar == ' ' ? 3 : 0;
|
||||
break;
|
||||
case (byte)',':
|
||||
pairCode = nextChar == ' ' ? 4 : 0;
|
||||
break;
|
||||
case (byte)':':
|
||||
pairCode = nextChar == ' ' ? 5 : 0;
|
||||
break;
|
||||
default:
|
||||
pairCode = 0;
|
||||
break;
|
||||
}
|
||||
if (pairCode > 0)
|
||||
{
|
||||
// We have one of the four special PUNCT pairs. Treat them specially.
|
||||
// Get a new set of states for the two new characters.
|
||||
states = updateStateListForPair(states, index, pairCode);
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get a new set of states for the new character.
|
||||
states = updateStateListForChar(states, index);
|
||||
}
|
||||
}
|
||||
// We are left with a set of states. Find the shortest one.
|
||||
State minState = null;
|
||||
foreach (var state in states)
|
||||
{
|
||||
if (minState == null)
|
||||
{
|
||||
minState = state;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state.BitCount < minState.BitCount)
|
||||
{
|
||||
minState = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
State minState = Collections.min(states, new Comparator<State>() {
|
||||
@Override
|
||||
public int compare(State a, State b) {
|
||||
return a.getBitCount() - b.getBitCount();
|
||||
}
|
||||
});
|
||||
*/
|
||||
// Convert it to a bit array, and return.
|
||||
return minState.toBitArray(text);
|
||||
}
|
||||
|
||||
// We update a set of states for a new character by updating each state
|
||||
// for the new character, merging the results, and then removing the
|
||||
// non-optimal states.
|
||||
private ICollection<State> updateStateListForChar(IEnumerable<State> states, int index)
|
||||
{
|
||||
var result = new LinkedList<State>();
|
||||
foreach (State state in states)
|
||||
{
|
||||
updateStateForChar(state, index, result);
|
||||
}
|
||||
return simplifyStates(result);
|
||||
}
|
||||
|
||||
// Return a set of states that represent the possible ways of updating this
|
||||
// state for the next character. The resulting set of states are added to
|
||||
// the "result" list.
|
||||
private void updateStateForChar(State state, int index, ICollection<State> result)
|
||||
{
|
||||
char ch = (char) (text[index] & 0xFF);
|
||||
bool charInCurrentTable = CHAR_MAP[state.Mode][ch] > 0;
|
||||
State stateNoBinary = null;
|
||||
for (int mode = 0; mode <= MODE_PUNCT; mode++)
|
||||
{
|
||||
int charInMode = CHAR_MAP[mode][ch];
|
||||
if (charInMode > 0)
|
||||
{
|
||||
if (stateNoBinary == null)
|
||||
{
|
||||
// Only create stateNoBinary the first time it's required.
|
||||
stateNoBinary = state.endBinaryShift(index);
|
||||
}
|
||||
// Try generating the character by latching to its mode
|
||||
if (!charInCurrentTable || mode == state.Mode || mode == MODE_DIGIT)
|
||||
{
|
||||
// If the character is in the current table, we don't want to latch to
|
||||
// any other mode except possibly digit (which uses only 4 bits). Any
|
||||
// other latch would be equally successful *after* this character, and
|
||||
// so wouldn't save any bits.
|
||||
State latch_state = stateNoBinary.latchAndAppend(mode, charInMode);
|
||||
result.Add(latch_state);
|
||||
}
|
||||
// Try generating the character by switching to its mode.
|
||||
if (!charInCurrentTable && SHIFT_TABLE[state.Mode][mode] >= 0)
|
||||
{
|
||||
// It never makes sense to temporarily shift to another mode if the
|
||||
// character exists in the current mode. That can never save bits.
|
||||
State shift_state = stateNoBinary.shiftAndAppend(mode, charInMode);
|
||||
result.Add(shift_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.BinaryShiftByteCount > 0 || CHAR_MAP[state.Mode][ch] == 0)
|
||||
{
|
||||
// It's never worthwhile to go into binary shift mode if you're not already
|
||||
// in binary shift mode, and the character exists in your current mode.
|
||||
// That can never save bits over just outputting the char in the current mode.
|
||||
State binaryState = state.addBinaryShiftChar(index);
|
||||
result.Add(binaryState);
|
||||
}
|
||||
}
|
||||
|
||||
private static ICollection<State> updateStateListForPair(IEnumerable<State> states, int index, int pairCode)
|
||||
{
|
||||
var result = new LinkedList<State>();
|
||||
foreach (State state in states)
|
||||
{
|
||||
updateStateForPair(state, index, pairCode, result);
|
||||
}
|
||||
return simplifyStates(result);
|
||||
}
|
||||
|
||||
private static void updateStateForPair(State state, int index, int pairCode, ICollection<State> result)
|
||||
{
|
||||
State stateNoBinary = state.endBinaryShift(index);
|
||||
// Possibility 1. Latch to MODE_PUNCT, and then append this code
|
||||
result.Add(stateNoBinary.latchAndAppend(MODE_PUNCT, pairCode));
|
||||
if (state.Mode != MODE_PUNCT)
|
||||
{
|
||||
// Possibility 2. Shift to MODE_PUNCT, and then append this code.
|
||||
// Every state except MODE_PUNCT (handled above) can shift
|
||||
result.Add(stateNoBinary.shiftAndAppend(MODE_PUNCT, pairCode));
|
||||
}
|
||||
if (pairCode == 3 || pairCode == 4)
|
||||
{
|
||||
// both characters are in DIGITS. Sometimes better to just add two digits
|
||||
State digit_state = stateNoBinary
|
||||
.latchAndAppend(MODE_DIGIT, 16 - pairCode) // period or comma in DIGIT
|
||||
.latchAndAppend(MODE_DIGIT, 1); // space in DIGIT
|
||||
result.Add(digit_state);
|
||||
}
|
||||
if (state.BinaryShiftByteCount > 0)
|
||||
{
|
||||
// It only makes sense to do the characters as binary if we're already
|
||||
// in binary mode.
|
||||
State binaryState = state.addBinaryShiftChar(index).addBinaryShiftChar(index + 1);
|
||||
result.Add(binaryState);
|
||||
}
|
||||
}
|
||||
|
||||
private static ICollection<State> simplifyStates(IEnumerable<State> states)
|
||||
{
|
||||
var result = new LinkedList<State>();
|
||||
var removeList = new List<State>();
|
||||
foreach (State newState in states)
|
||||
{
|
||||
bool add = true;
|
||||
removeList.Clear();
|
||||
foreach (var oldState in result)
|
||||
{
|
||||
if (oldState.isBetterThanOrEqualTo(newState))
|
||||
{
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
if (newState.isBetterThanOrEqualTo(oldState))
|
||||
{
|
||||
removeList.Add(oldState);
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
result.AddLast(newState);
|
||||
}
|
||||
foreach (var removeItem in removeList)
|
||||
{
|
||||
result.Remove(removeItem);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
zxing.core/xx/aztec/encoder/SimpleToken.cs
Normal file
48
zxing.core/xx/aztec/encoder/SimpleToken.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
using ZXing.Common;
|
||||
|
||||
namespace ZXing.Aztec.Internal
|
||||
{
|
||||
public sealed class SimpleToken : Token
|
||||
{
|
||||
// For normal words, indicates value and bitCount
|
||||
private readonly short value;
|
||||
private readonly short bitCount;
|
||||
|
||||
public SimpleToken(Token previous, int value, int bitCount)
|
||||
: base(previous)
|
||||
{
|
||||
this.value = (short) value;
|
||||
this.bitCount = (short) bitCount;
|
||||
}
|
||||
|
||||
public override void appendTo(BitArray bitArray, byte[] text)
|
||||
{
|
||||
bitArray.appendBits(value, bitCount);
|
||||
}
|
||||
|
||||
public override String ToString()
|
||||
{
|
||||
int value = this.value & ((1 << bitCount) - 1);
|
||||
value |= 1 << bitCount;
|
||||
return '<' + SupportClass.ToBinaryString(value | (1 << bitCount)).Substring(1) + '>';
|
||||
}
|
||||
}
|
||||
}
|
||||
197
zxing.core/xx/aztec/encoder/State.cs
Normal file
197
zxing.core/xx/aztec/encoder/State.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ZXing.Common;
|
||||
|
||||
namespace ZXing.Aztec.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// State represents all information about a sequence necessary to generate the current output.
|
||||
/// Note that a state is immutable.
|
||||
/// </summary>
|
||||
internal sealed class State
|
||||
{
|
||||
public static readonly State INITIAL_STATE = new State(Token.EMPTY, HighLevelEncoder.MODE_UPPER, 0, 0);
|
||||
|
||||
// The current mode of the encoding (or the mode to which we'll return if
|
||||
// we're in Binary Shift mode.
|
||||
private readonly int mode;
|
||||
// The list of tokens that we output. If we are in Binary Shift mode, this
|
||||
// token list does *not* yet included the token for those bytes
|
||||
private readonly Token token;
|
||||
// If non-zero, the number of most recent bytes that should be output
|
||||
// in Binary Shift mode.
|
||||
private readonly int binaryShiftByteCount;
|
||||
// The total number of bits generated (including Binary Shift).
|
||||
private readonly int bitCount;
|
||||
|
||||
public State(Token token, int mode, int binaryBytes, int bitCount)
|
||||
{
|
||||
this.token = token;
|
||||
this.mode = mode;
|
||||
this.binaryShiftByteCount = binaryBytes;
|
||||
this.bitCount = bitCount;
|
||||
// Make sure we match the token
|
||||
//int binaryShiftBitCount = (binaryShiftByteCount * 8) +
|
||||
// (binaryShiftByteCount == 0 ? 0 :
|
||||
// binaryShiftByteCount <= 31 ? 10 :
|
||||
// binaryShiftByteCount <= 62 ? 20 : 21);
|
||||
//assert this.bitCount == token.getTotalBitCount() + binaryShiftBitCount;
|
||||
}
|
||||
|
||||
public int Mode
|
||||
{
|
||||
get { return mode; }
|
||||
}
|
||||
|
||||
public Token Token
|
||||
{
|
||||
get { return token; }
|
||||
}
|
||||
|
||||
public int BinaryShiftByteCount
|
||||
{
|
||||
get { return binaryShiftByteCount; }
|
||||
}
|
||||
|
||||
public int BitCount
|
||||
{
|
||||
get { return bitCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new state representing this state with a latch to a (not
|
||||
/// necessary different) mode, and then a code.
|
||||
/// </summary>
|
||||
public State latchAndAppend(int mode, int value)
|
||||
{
|
||||
//assert binaryShiftByteCount == 0;
|
||||
int bitCount = this.bitCount;
|
||||
Token token = this.token;
|
||||
if (mode != this.mode)
|
||||
{
|
||||
int latch = HighLevelEncoder.LATCH_TABLE[this.mode][mode];
|
||||
token = token.add(latch & 0xFFFF, latch >> 16);
|
||||
bitCount += latch >> 16;
|
||||
}
|
||||
int latchModeBitCount = mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5;
|
||||
token = token.add(value, latchModeBitCount);
|
||||
return new State(token, mode, 0, bitCount + latchModeBitCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new state representing this state, with a temporary shift
|
||||
/// to a different mode to output a single value.
|
||||
/// </summary>
|
||||
public State shiftAndAppend(int mode, int value)
|
||||
{
|
||||
//assert binaryShiftByteCount == 0 && this.mode != mode;
|
||||
Token token = this.token;
|
||||
int thisModeBitCount = this.mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5;
|
||||
// Shifts exist only to UPPER and PUNCT, both with tokens size 5.
|
||||
token = token.add(HighLevelEncoder.SHIFT_TABLE[this.mode][mode], thisModeBitCount);
|
||||
token = token.add(value, 5);
|
||||
return new State(token, this.mode, 0, this.bitCount + thisModeBitCount + 5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new state representing this state, but an additional character
|
||||
/// output in Binary Shift mode.
|
||||
/// </summary>
|
||||
public State addBinaryShiftChar(int index)
|
||||
{
|
||||
Token token = this.token;
|
||||
int mode = this.mode;
|
||||
int bitCount = this.bitCount;
|
||||
if (this.mode == HighLevelEncoder.MODE_PUNCT || this.mode == HighLevelEncoder.MODE_DIGIT)
|
||||
{
|
||||
//assert binaryShiftByteCount == 0;
|
||||
int latch = HighLevelEncoder.LATCH_TABLE[mode][HighLevelEncoder.MODE_UPPER];
|
||||
token = token.add(latch & 0xFFFF, latch >> 16);
|
||||
bitCount += latch >> 16;
|
||||
mode = HighLevelEncoder.MODE_UPPER;
|
||||
}
|
||||
int deltaBitCount =
|
||||
(binaryShiftByteCount == 0 || binaryShiftByteCount == 31) ? 18 :
|
||||
(binaryShiftByteCount == 62) ? 9 : 8;
|
||||
State result = new State(token, mode, binaryShiftByteCount + 1, bitCount + deltaBitCount);
|
||||
if (result.binaryShiftByteCount == 2047 + 31)
|
||||
{
|
||||
// The string is as long as it's allowed to be. We should end it.
|
||||
result = result.endBinaryShift(index + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the state identical to this one, but we are no longer in
|
||||
/// Binary Shift mode.
|
||||
/// </summary>
|
||||
public State endBinaryShift(int index)
|
||||
{
|
||||
if (binaryShiftByteCount == 0)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
Token token = this.token;
|
||||
token = token.addBinaryShift(index - binaryShiftByteCount, binaryShiftByteCount);
|
||||
//assert token.getTotalBitCount() == this.bitCount;
|
||||
return new State(token, mode, 0, this.bitCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if "this" state is better (or equal) to be in than "that"
|
||||
/// state under all possible circumstances.
|
||||
/// </summary>
|
||||
public bool isBetterThanOrEqualTo(State other)
|
||||
{
|
||||
int mySize = this.bitCount + (HighLevelEncoder.LATCH_TABLE[this.mode][other.mode] >> 16);
|
||||
if (other.binaryShiftByteCount > 0 &&
|
||||
(this.binaryShiftByteCount == 0 || this.binaryShiftByteCount > other.binaryShiftByteCount))
|
||||
{
|
||||
mySize += 10; // Cost of entering Binary Shift mode.
|
||||
}
|
||||
return mySize <= other.bitCount;
|
||||
}
|
||||
|
||||
public BitArray toBitArray(byte[] text)
|
||||
{
|
||||
// Reverse the tokens, so that they are in the order that they should
|
||||
// be output
|
||||
var symbols = new LinkedList<Token>();
|
||||
for (Token token = endBinaryShift(text.Length).token; token != null; token = token.Previous)
|
||||
{
|
||||
symbols.AddFirst(token);
|
||||
}
|
||||
BitArray bitArray = new BitArray();
|
||||
// Add each token to the result.
|
||||
foreach (Token symbol in symbols)
|
||||
{
|
||||
symbol.appendTo(bitArray, text);
|
||||
}
|
||||
//assert bitArray.getSize() == this.bitCount;
|
||||
return bitArray;
|
||||
}
|
||||
|
||||
public override String ToString()
|
||||
{
|
||||
return String.Format("{0} bits={1} bytes={2}", HighLevelEncoder.MODE_NAMES[mode], bitCount, binaryShiftByteCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
50
zxing.core/xx/aztec/encoder/Token.cs
Normal file
50
zxing.core/xx/aztec/encoder/Token.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
using ZXing.Common;
|
||||
|
||||
namespace ZXing.Aztec.Internal
|
||||
{
|
||||
public abstract class Token
|
||||
{
|
||||
public static Token EMPTY = new SimpleToken(null, 0, 0);
|
||||
|
||||
private readonly Token previous;
|
||||
|
||||
protected Token(Token previous)
|
||||
{
|
||||
this.previous = previous;
|
||||
}
|
||||
|
||||
public Token Previous
|
||||
{
|
||||
get { return previous; }
|
||||
}
|
||||
|
||||
public Token add(int value, int bitCount)
|
||||
{
|
||||
return new SimpleToken(this, value, bitCount);
|
||||
}
|
||||
|
||||
public Token addBinaryShift(int start, int byteCount)
|
||||
{
|
||||
int bitCount = (byteCount*8) + (byteCount <= 31 ? 10 : byteCount <= 62 ? 20 : 21);
|
||||
return new BinaryShiftToken(this, start, byteCount);
|
||||
}
|
||||
|
||||
public abstract void appendTo(BitArray bitArray, byte[] text);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user