mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-06 01:06:37 +08:00
537 lines
18 KiB
C#
537 lines
18 KiB
C#
/*
|
|
* Copyright 2006-2007 Jeremias Maerki.
|
|
*
|
|
* 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.Text;
|
|
|
|
namespace ZXing.Datamatrix.Encoder
|
|
{
|
|
/// <summary>
|
|
/// DataMatrix ECC 200 data encoder following the algorithm described in ISO/IEC 16022:200(E) in
|
|
/// annex S.
|
|
/// </summary>
|
|
internal static class HighLevelEncoder
|
|
{
|
|
/// <summary>
|
|
/// Padding character
|
|
/// </summary>
|
|
public const char PAD = (char)129;
|
|
/// <summary>
|
|
/// mode latch to C40 encodation mode
|
|
/// </summary>
|
|
public const char LATCH_TO_C40 = (char)230;
|
|
/// <summary>
|
|
/// mode latch to Base 256 encodation mode
|
|
/// </summary>
|
|
public const char LATCH_TO_BASE256 = (char)231;
|
|
/// <summary>
|
|
/// FNC1 Codeword
|
|
/// </summary>
|
|
public const char FNC1 = (char)232;
|
|
/// <summary>
|
|
/// Structured Append Codeword
|
|
/// </summary>
|
|
public const char STRUCTURED_APPEND = (char)233;
|
|
/// <summary>
|
|
/// Reader Programming
|
|
/// </summary>
|
|
public const char READER_PROGRAMMING = (char)234;
|
|
/// <summary>
|
|
/// Upper Shift
|
|
/// </summary>
|
|
public const char UPPER_SHIFT = (char)235;
|
|
/// <summary>
|
|
/// 05 Macro
|
|
/// </summary>
|
|
public const char MACRO_05 = (char)236;
|
|
/// <summary>
|
|
/// 06 Macro
|
|
/// </summary>
|
|
public const char MACRO_06 = (char)237;
|
|
/// <summary>
|
|
/// mode latch to ANSI X.12 encodation mode
|
|
/// </summary>
|
|
public const char LATCH_TO_ANSIX12 = (char)238;
|
|
/// <summary>
|
|
/// mode latch to Text encodation mode
|
|
/// </summary>
|
|
public const char LATCH_TO_TEXT = (char)239;
|
|
/// <summary>
|
|
/// mode latch to EDIFACT encodation mode
|
|
/// </summary>
|
|
public const char LATCH_TO_EDIFACT = (char)240;
|
|
/// <summary>
|
|
/// ECI character (Extended Channel Interpretation)
|
|
/// </summary>
|
|
public const char ECI = (char)241;
|
|
|
|
/// <summary>
|
|
/// Unlatch from C40 encodation
|
|
/// </summary>
|
|
public const char C40_UNLATCH = (char)254;
|
|
/// <summary>
|
|
/// Unlatch from X12 encodation
|
|
/// </summary>
|
|
public const char X12_UNLATCH = (char)254;
|
|
|
|
/// <summary>
|
|
/// 05 Macro header
|
|
/// </summary>
|
|
public const String MACRO_05_HEADER = "[)>\u001E05\u001D";
|
|
/// <summary>
|
|
/// 06 Macro header
|
|
/// </summary>
|
|
public const String MACRO_06_HEADER = "[)>\u001E06\u001D";
|
|
/// <summary>
|
|
/// Macro trailer
|
|
/// </summary>
|
|
public const String MACRO_TRAILER = "\u001E\u0004";
|
|
|
|
/*
|
|
/// <summary>
|
|
/// Converts the message to a byte array using the default encoding (cp437) as defined by the
|
|
/// specification
|
|
/// </summary>
|
|
/// <param name="msg">the message</param>
|
|
/// <returns>the byte array of the message</returns>
|
|
public static byte[] getBytesForMessage(String msg)
|
|
{
|
|
return Encoding.GetEncoding("CP437").GetBytes(msg); //See 4.4.3 and annex B of ISO/IEC 15438:2001(E)
|
|
}
|
|
*/
|
|
|
|
private static char randomize253State(char ch, int codewordPosition)
|
|
{
|
|
int pseudoRandom = ((149 * codewordPosition) % 253) + 1;
|
|
int tempVariable = ch + pseudoRandom;
|
|
return tempVariable <= 254 ? (char)tempVariable : (char)(tempVariable - 254);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs message encoding of a DataMatrix message using the algorithm described in annex P
|
|
/// of ISO/IEC 16022:2000(E).
|
|
/// </summary>
|
|
/// <param name="msg">the message</param>
|
|
/// <returns>the encoded message (the char values range from 0 to 255)</returns>
|
|
public static String encodeHighLevel(String msg)
|
|
{
|
|
return encodeHighLevel(msg, SymbolShapeHint.FORCE_NONE, null, null, Encodation.ASCII);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs message encoding of a DataMatrix message using the algorithm described in annex P
|
|
/// of ISO/IEC 16022:2000(E).
|
|
/// </summary>
|
|
/// <param name="msg">the message</param>
|
|
/// <param name="shape">requested shape. May be {@code SymbolShapeHint.FORCE_NONE},{@code SymbolShapeHint.FORCE_SQUARE} or {@code SymbolShapeHint.FORCE_RECTANGLE}.</param>
|
|
/// <param name="minSize">the minimum symbol size constraint or null for no constraint</param>
|
|
/// <param name="maxSize">the maximum symbol size constraint or null for no constraint</param>
|
|
/// <returns>the encoded message (the char values range from 0 to 255)</returns>
|
|
public static String encodeHighLevel(String msg,
|
|
SymbolShapeHint shape,
|
|
Dimension minSize,
|
|
Dimension maxSize,
|
|
int defaultEncodation)
|
|
{
|
|
//the codewords 0..255 are encoded as Unicode characters
|
|
Encoder[] encoders =
|
|
{
|
|
new ASCIIEncoder(), new C40Encoder(), new TextEncoder(),
|
|
new X12Encoder(), new EdifactEncoder(), new Base256Encoder()
|
|
};
|
|
|
|
var context = new EncoderContext(msg);
|
|
context.setSymbolShape(shape);
|
|
context.setSizeConstraints(minSize, maxSize);
|
|
|
|
if (msg.StartsWith(MACRO_05_HEADER) && msg.EndsWith(MACRO_TRAILER))
|
|
{
|
|
context.writeCodeword(MACRO_05);
|
|
context.setSkipAtEnd(2);
|
|
context.Pos += MACRO_05_HEADER.Length;
|
|
}
|
|
else if (msg.StartsWith(MACRO_06_HEADER) && msg.EndsWith(MACRO_TRAILER))
|
|
{
|
|
context.writeCodeword(MACRO_06);
|
|
context.setSkipAtEnd(2);
|
|
context.Pos += MACRO_06_HEADER.Length;
|
|
}
|
|
|
|
int encodingMode = defaultEncodation; //Default mode
|
|
switch (encodingMode)
|
|
{
|
|
case Encodation.BASE256:
|
|
context.writeCodeword(HighLevelEncoder.LATCH_TO_BASE256);
|
|
break;
|
|
case Encodation.C40:
|
|
context.writeCodeword(HighLevelEncoder.LATCH_TO_C40);
|
|
break;
|
|
case Encodation.X12:
|
|
context.writeCodeword(HighLevelEncoder.LATCH_TO_ANSIX12);
|
|
break;
|
|
case Encodation.TEXT:
|
|
context.writeCodeword(HighLevelEncoder.LATCH_TO_TEXT);
|
|
break;
|
|
case Encodation.EDIFACT:
|
|
context.writeCodeword(HighLevelEncoder.LATCH_TO_EDIFACT);
|
|
break;
|
|
case Encodation.ASCII:
|
|
break;
|
|
default:
|
|
throw new InvalidOperationException("Illegal mode: " + encodingMode);
|
|
}
|
|
while (context.HasMoreCharacters)
|
|
{
|
|
encoders[encodingMode].encode(context);
|
|
if (context.NewEncoding >= 0)
|
|
{
|
|
encodingMode = context.NewEncoding;
|
|
context.resetEncoderSignal();
|
|
}
|
|
}
|
|
int len = context.Codewords.Length;
|
|
context.updateSymbolInfo();
|
|
int capacity = context.SymbolInfo.dataCapacity;
|
|
if (len < capacity)
|
|
{
|
|
if (encodingMode != Encodation.ASCII && encodingMode != Encodation.BASE256)
|
|
{
|
|
context.writeCodeword('\u00fe'); //Unlatch (254)
|
|
}
|
|
}
|
|
//Padding
|
|
StringBuilder codewords = context.Codewords;
|
|
if (codewords.Length < capacity)
|
|
{
|
|
codewords.Append(PAD);
|
|
}
|
|
while (codewords.Length < capacity)
|
|
{
|
|
codewords.Append(randomize253State(PAD, codewords.Length + 1));
|
|
}
|
|
|
|
return context.Codewords.ToString();
|
|
}
|
|
|
|
internal static int lookAheadTest(String msg, int startpos, int currentMode)
|
|
{
|
|
if (startpos >= msg.Length)
|
|
{
|
|
return currentMode;
|
|
}
|
|
float[] charCounts;
|
|
//step J
|
|
if (currentMode == Encodation.ASCII)
|
|
{
|
|
charCounts = new [] { 0, 1, 1, 1, 1, 1.25f };
|
|
}
|
|
else
|
|
{
|
|
charCounts = new [] { 1, 2, 2, 2, 2, 2.25f };
|
|
charCounts[currentMode] = 0;
|
|
}
|
|
|
|
int charsProcessed = 0;
|
|
while (true)
|
|
{
|
|
//step K
|
|
if ((startpos + charsProcessed) == msg.Length)
|
|
{
|
|
var min = Int32.MaxValue;
|
|
var mins = new byte[6];
|
|
var intCharCounts = new int[6];
|
|
min = findMinimums(charCounts, intCharCounts, min, mins);
|
|
var minCount = getMinimumCount(mins);
|
|
|
|
if (intCharCounts[Encodation.ASCII] == min)
|
|
{
|
|
return Encodation.ASCII;
|
|
}
|
|
if (minCount == 1 && mins[Encodation.BASE256] > 0)
|
|
{
|
|
return Encodation.BASE256;
|
|
}
|
|
if (minCount == 1 && mins[Encodation.EDIFACT] > 0)
|
|
{
|
|
return Encodation.EDIFACT;
|
|
}
|
|
if (minCount == 1 && mins[Encodation.TEXT] > 0)
|
|
{
|
|
return Encodation.TEXT;
|
|
}
|
|
if (minCount == 1 && mins[Encodation.X12] > 0)
|
|
{
|
|
return Encodation.X12;
|
|
}
|
|
return Encodation.C40;
|
|
}
|
|
|
|
char c = msg[startpos + charsProcessed];
|
|
charsProcessed++;
|
|
|
|
//step L
|
|
if (isDigit(c))
|
|
{
|
|
charCounts[Encodation.ASCII] += 0.5f;
|
|
}
|
|
else if (isExtendedASCII(c))
|
|
{
|
|
charCounts[Encodation.ASCII] = (int)Math.Ceiling(charCounts[Encodation.ASCII]);
|
|
charCounts[Encodation.ASCII] += 2;
|
|
}
|
|
else
|
|
{
|
|
charCounts[Encodation.ASCII] = (int)Math.Ceiling(charCounts[Encodation.ASCII]);
|
|
charCounts[Encodation.ASCII]++;
|
|
}
|
|
|
|
//step M
|
|
if (isNativeC40(c))
|
|
{
|
|
charCounts[Encodation.C40] += 2.0f / 3.0f;
|
|
}
|
|
else if (isExtendedASCII(c))
|
|
{
|
|
charCounts[Encodation.C40] += 8.0f / 3.0f;
|
|
}
|
|
else
|
|
{
|
|
charCounts[Encodation.C40] += 4.0f / 3.0f;
|
|
}
|
|
|
|
//step N
|
|
if (isNativeText(c))
|
|
{
|
|
charCounts[Encodation.TEXT] += 2.0f / 3.0f;
|
|
}
|
|
else if (isExtendedASCII(c))
|
|
{
|
|
charCounts[Encodation.TEXT] += 8.0f / 3.0f;
|
|
}
|
|
else
|
|
{
|
|
charCounts[Encodation.TEXT] += 4.0f / 3.0f;
|
|
}
|
|
|
|
//step O
|
|
if (isNativeX12(c))
|
|
{
|
|
charCounts[Encodation.X12] += 2.0f / 3.0f;
|
|
}
|
|
else if (isExtendedASCII(c))
|
|
{
|
|
charCounts[Encodation.X12] += 13.0f / 3.0f;
|
|
}
|
|
else
|
|
{
|
|
charCounts[Encodation.X12] += 10.0f / 3.0f;
|
|
}
|
|
|
|
//step P
|
|
if (isNativeEDIFACT(c))
|
|
{
|
|
charCounts[Encodation.EDIFACT] += 3.0f / 4.0f;
|
|
}
|
|
else if (isExtendedASCII(c))
|
|
{
|
|
charCounts[Encodation.EDIFACT] += 17.0f / 4.0f;
|
|
}
|
|
else
|
|
{
|
|
charCounts[Encodation.EDIFACT] += 13.0f / 4.0f;
|
|
}
|
|
|
|
// step Q
|
|
if (isSpecialB256(c))
|
|
{
|
|
charCounts[Encodation.BASE256] += 4;
|
|
}
|
|
else
|
|
{
|
|
charCounts[Encodation.BASE256]++;
|
|
}
|
|
|
|
//step R
|
|
if (charsProcessed >= 4)
|
|
{
|
|
var intCharCounts = new int[6];
|
|
var mins = new byte[6];
|
|
findMinimums(charCounts, intCharCounts, Int32.MaxValue, mins);
|
|
int minCount = getMinimumCount(mins);
|
|
|
|
if (intCharCounts[Encodation.ASCII] < intCharCounts[Encodation.BASE256]
|
|
&& intCharCounts[Encodation.ASCII] < intCharCounts[Encodation.C40]
|
|
&& intCharCounts[Encodation.ASCII] < intCharCounts[Encodation.TEXT]
|
|
&& intCharCounts[Encodation.ASCII] < intCharCounts[Encodation.X12]
|
|
&& intCharCounts[Encodation.ASCII] < intCharCounts[Encodation.EDIFACT])
|
|
{
|
|
return Encodation.ASCII;
|
|
}
|
|
if (intCharCounts[Encodation.BASE256] < intCharCounts[Encodation.ASCII]
|
|
|| (mins[Encodation.C40] + mins[Encodation.TEXT] + mins[Encodation.X12] + mins[Encodation.EDIFACT]) == 0)
|
|
{
|
|
return Encodation.BASE256;
|
|
}
|
|
if (minCount == 1 && mins[Encodation.EDIFACT] > 0)
|
|
{
|
|
return Encodation.EDIFACT;
|
|
}
|
|
if (minCount == 1 && mins[Encodation.TEXT] > 0)
|
|
{
|
|
return Encodation.TEXT;
|
|
}
|
|
if (minCount == 1 && mins[Encodation.X12] > 0)
|
|
{
|
|
return Encodation.X12;
|
|
}
|
|
if (intCharCounts[Encodation.C40] + 1 < intCharCounts[Encodation.ASCII]
|
|
&& intCharCounts[Encodation.C40] + 1 < intCharCounts[Encodation.BASE256]
|
|
&& intCharCounts[Encodation.C40] + 1 < intCharCounts[Encodation.EDIFACT]
|
|
&& intCharCounts[Encodation.C40] + 1 < intCharCounts[Encodation.TEXT])
|
|
{
|
|
if (intCharCounts[Encodation.C40] < intCharCounts[Encodation.X12])
|
|
{
|
|
return Encodation.C40;
|
|
}
|
|
if (intCharCounts[Encodation.C40] == intCharCounts[Encodation.X12])
|
|
{
|
|
int p = startpos + charsProcessed + 1;
|
|
while (p < msg.Length)
|
|
{
|
|
char tc = msg[p];
|
|
if (isX12TermSep(tc))
|
|
{
|
|
return Encodation.X12;
|
|
}
|
|
if (!isNativeX12(tc))
|
|
{
|
|
break;
|
|
}
|
|
p++;
|
|
}
|
|
return Encodation.C40;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static int findMinimums(float[] charCounts, int[] intCharCounts, int min, byte[] mins)
|
|
{
|
|
SupportClass.Fill(mins, (byte)0);
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
intCharCounts[i] = (int)Math.Ceiling(charCounts[i]);
|
|
int current = intCharCounts[i];
|
|
if (min > current)
|
|
{
|
|
min = current;
|
|
SupportClass.Fill(mins, (byte)0);
|
|
}
|
|
if (min == current)
|
|
{
|
|
mins[i]++;
|
|
|
|
}
|
|
}
|
|
return min;
|
|
}
|
|
|
|
private static int getMinimumCount(byte[] mins)
|
|
{
|
|
int minCount = 0;
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
minCount += mins[i];
|
|
}
|
|
return minCount;
|
|
}
|
|
|
|
internal static bool isDigit(char ch)
|
|
{
|
|
return ch >= '0' && ch <= '9';
|
|
}
|
|
|
|
internal static bool isExtendedASCII(char ch)
|
|
{
|
|
return ch >= 128 && ch <= 255;
|
|
}
|
|
|
|
internal static bool isNativeC40(char ch)
|
|
{
|
|
return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
|
|
}
|
|
|
|
internal static bool isNativeText(char ch)
|
|
{
|
|
return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z');
|
|
}
|
|
|
|
internal static bool isNativeX12(char ch)
|
|
{
|
|
return isX12TermSep(ch) || (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
|
|
}
|
|
|
|
internal static bool isX12TermSep(char ch)
|
|
{
|
|
return (ch == '\r') //CR
|
|
|| (ch == '*')
|
|
|| (ch == '>');
|
|
}
|
|
|
|
internal static bool isNativeEDIFACT(char ch)
|
|
{
|
|
return ch >= ' ' && ch <= '^';
|
|
}
|
|
|
|
internal static bool isSpecialB256(char ch)
|
|
{
|
|
return false; //TODO NOT IMPLEMENTED YET!!!
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the number of consecutive characters that are encodable using numeric compaction.
|
|
/// </summary>
|
|
/// <param name="msg">the message</param>
|
|
/// <param name="startpos">the start position within the message</param>
|
|
/// <returns>the requested character count</returns>
|
|
public static int determineConsecutiveDigitCount(String msg, int startpos)
|
|
{
|
|
int count = 0;
|
|
int len = msg.Length;
|
|
int idx = startpos;
|
|
if (idx < len)
|
|
{
|
|
char ch = msg[idx];
|
|
while (isDigit(ch) && idx < len)
|
|
{
|
|
count++;
|
|
idx++;
|
|
if (idx < len)
|
|
{
|
|
ch = msg[idx];
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
internal static void illegalCharacter(char c)
|
|
{
|
|
throw new ArgumentException(String.Format("Illegal character: {0} (0x{1:X})", c, (int)c));
|
|
}
|
|
}
|
|
} |