mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-17 14:46:36 +08:00
233 lines
7.4 KiB
C#
233 lines
7.4 KiB
C#
/*
|
|
* Copyright 2010 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.OneD
|
|
{
|
|
/// <summary>
|
|
/// This object renders a CODE128 code as a <see cref="BitMatrix" />.
|
|
///
|
|
/// <author>erik.barbara@gmail.com (Erik Barbara)</author>
|
|
/// </summary>
|
|
public sealed class Code128Writer : OneDimensionalCodeWriter
|
|
{
|
|
private const int CODE_START_B = 104;
|
|
private const int CODE_START_C = 105;
|
|
private const int CODE_CODE_B = 100;
|
|
private const int CODE_CODE_C = 99;
|
|
private const int CODE_STOP = 106;
|
|
|
|
// Dummy characters used to specify control characters in input
|
|
private const char ESCAPE_FNC_1 = '\u00f1';
|
|
private const char ESCAPE_FNC_2 = '\u00f2';
|
|
private const char ESCAPE_FNC_3 = '\u00f3';
|
|
private const char ESCAPE_FNC_4 = '\u00f4';
|
|
|
|
private const int CODE_FNC_1 = 102; // Code A, Code B, Code C
|
|
private const int CODE_FNC_2 = 97; // Code A, Code B
|
|
private const int CODE_FNC_3 = 96; // Code A, Code B
|
|
private const int CODE_FNC_4_B = 100; // Code B
|
|
|
|
private bool forceCodesetB;
|
|
|
|
public override BitMatrix encode(String contents,
|
|
BarcodeFormat format,
|
|
int width,
|
|
int height,
|
|
IDictionary<EncodeHintType, object> hints)
|
|
{
|
|
if (format != BarcodeFormat.CODE_128)
|
|
{
|
|
throw new ArgumentException("Can only encode CODE_128, but got " + format);
|
|
}
|
|
|
|
forceCodesetB = (hints != null &&
|
|
hints.ContainsKey(EncodeHintType.CODE128_FORCE_CODESET_B) &&
|
|
(bool) hints[EncodeHintType.CODE128_FORCE_CODESET_B]);
|
|
|
|
return base.encode(contents, format, width, height, hints);
|
|
}
|
|
|
|
override public bool[] encode(String contents)
|
|
{
|
|
int length = contents.Length;
|
|
// Check length
|
|
if (length < 1 || length > 80)
|
|
{
|
|
throw new ArgumentException(
|
|
"Contents length should be between 1 and 80 characters, but got " + length);
|
|
}
|
|
// Check content
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
char c = contents[i];
|
|
if (c < ' ' || c > '~')
|
|
{
|
|
switch (c)
|
|
{
|
|
case ESCAPE_FNC_1:
|
|
case ESCAPE_FNC_2:
|
|
case ESCAPE_FNC_3:
|
|
case ESCAPE_FNC_4:
|
|
break;
|
|
default:
|
|
throw new ArgumentException("Bad character in input: " + c);
|
|
}
|
|
}
|
|
}
|
|
|
|
var patterns = new List<int[]>(); // temporary storage for patterns
|
|
int checkSum = 0;
|
|
int checkWeight = 1;
|
|
int codeSet = 0; // selected code (CODE_CODE_B or CODE_CODE_C)
|
|
int position = 0; // position in contents
|
|
|
|
while (position < length)
|
|
{
|
|
//Select code to use
|
|
int requiredDigitCount = codeSet == CODE_CODE_C ? 2 : 4;
|
|
int newCodeSet;
|
|
if (isDigits(contents, position, requiredDigitCount))
|
|
{
|
|
newCodeSet = forceCodesetB ? CODE_CODE_B : CODE_CODE_C;
|
|
}
|
|
else
|
|
{
|
|
newCodeSet = CODE_CODE_B;
|
|
}
|
|
|
|
//Get the pattern index
|
|
int patternIndex;
|
|
if (newCodeSet == codeSet)
|
|
{
|
|
// Encode the current character
|
|
// First handle escapes
|
|
switch (contents[position])
|
|
{
|
|
case ESCAPE_FNC_1:
|
|
patternIndex = CODE_FNC_1;
|
|
break;
|
|
case ESCAPE_FNC_2:
|
|
patternIndex = CODE_FNC_2;
|
|
break;
|
|
case ESCAPE_FNC_3:
|
|
patternIndex = CODE_FNC_3;
|
|
break;
|
|
case ESCAPE_FNC_4:
|
|
patternIndex = CODE_FNC_4_B; // FIXME if this ever outputs Code A
|
|
break;
|
|
default:
|
|
// Then handle normal characters otherwise
|
|
if (codeSet == CODE_CODE_B)
|
|
{
|
|
patternIndex = contents[position] - ' ';
|
|
}
|
|
else
|
|
{ // CODE_CODE_C
|
|
patternIndex = Int32.Parse(contents.Substring(position, 2));
|
|
position++; // Also incremented below
|
|
}
|
|
break;
|
|
}
|
|
position++;
|
|
}
|
|
else
|
|
{
|
|
// Should we change the current code?
|
|
// Do we have a code set?
|
|
if (codeSet == 0)
|
|
{
|
|
// No, we don't have a code set
|
|
if (newCodeSet == CODE_CODE_B)
|
|
{
|
|
patternIndex = CODE_START_B;
|
|
}
|
|
else
|
|
{
|
|
// CODE_CODE_C
|
|
patternIndex = CODE_START_C;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Yes, we have a code set
|
|
patternIndex = newCodeSet;
|
|
}
|
|
codeSet = newCodeSet;
|
|
}
|
|
|
|
// Get the pattern
|
|
patterns.Add(Code128Reader.CODE_PATTERNS[patternIndex]);
|
|
|
|
// Compute checksum
|
|
checkSum += patternIndex * checkWeight;
|
|
if (position != 0)
|
|
{
|
|
checkWeight++;
|
|
}
|
|
}
|
|
|
|
// Compute and append checksum
|
|
checkSum %= 103;
|
|
patterns.Add(Code128Reader.CODE_PATTERNS[checkSum]);
|
|
|
|
// Append stop code
|
|
patterns.Add(Code128Reader.CODE_PATTERNS[CODE_STOP]);
|
|
|
|
// Compute code width
|
|
int codeWidth = 0;
|
|
foreach (int[] pattern in patterns)
|
|
{
|
|
foreach (int width in pattern)
|
|
{
|
|
codeWidth += width;
|
|
}
|
|
}
|
|
|
|
// Compute result
|
|
var result = new bool[codeWidth];
|
|
int pos = 0;
|
|
foreach (int[] pattern in patterns)
|
|
{
|
|
pos += appendPattern(result, pos, pattern, true);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static bool isDigits(String value, int start, int length)
|
|
{
|
|
int end = start + length;
|
|
int last = value.Length;
|
|
for (int i = start; i < end && i < last; i++)
|
|
{
|
|
char c = value[i];
|
|
if (c < '0' || c > '9')
|
|
{
|
|
if (c != ESCAPE_FNC_1)
|
|
{
|
|
return false;
|
|
}
|
|
end++; // ignore FNC_1
|
|
}
|
|
}
|
|
return end <= last; // end > last if we've run out of string
|
|
}
|
|
}
|
|
} |