Stephen Furlani's C# updates, although this may get retired anyway

git-svn-id: https://zxing.googlecode.com/svn/trunk@2712 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen@gmail.com 2013-05-06 20:50:27 +00:00
parent ad1a305cf6
commit 2cdcc424b5
32 changed files with 7540 additions and 1811 deletions

View file

@ -96,6 +96,7 @@ Sean Owen (Google)
Shiyuan Guo / 郭世元
ShumovichY
Simon Flannery (Ericsson)
Stephen Furlani
Steven Parkes
stoty74
Suraj Supekar

View file

@ -1,79 +1,63 @@
/*
* 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;
/*
* 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 com.google.zxing.common
namespace ZXing.Common
{
/// <summary>
/// Encapsulates the result of decoding a matrix of bits. This typically
/// applies to 2D barcode formats. For now it contains the raw bytes obtained,
/// as well as a String interpretation of those bytes, if applicable.
/// <author>Sean Owen</author>
/// <author>Stephen Furlani (Updated to latest Core version w/ Other)</author>
///
/// </summary>
public sealed class DecoderResult
{
public byte[] RawBytes { get; private set; }
public String Text { get; private set; }
/// <summary>
/// <p>Encapsulates the result of decoding a matrix of bits. This typically
/// applies to 2D barcode formats. For now it contains the raw bytes obtained,
/// as well as a String interpretation of those bytes, if applicable.</p>
///
/// @author Sean Owen
/// </summary>
public sealed class DecoderResult
{
public IList<byte[]> ByteSegments { get; private set; }
private readonly sbyte[] rawBytes;
private readonly string text;
private readonly IList<sbyte[]> byteSegments;
private readonly string ecLevel;
public String ECLevel { get; private set; }
public DecoderResult(sbyte[] rawBytes, string text, IList<sbyte[]> byteSegments, string ecLevel)
{
this.rawBytes = rawBytes;
this.text = text;
this.byteSegments = byteSegments;
this.ecLevel = ecLevel;
}
public int ErrorsCorrected { get; set; }
public sbyte[] RawBytes
{
get
{
return rawBytes;
}
}
public int Erasures { get; set; }
public string Text
{
get
{
return text;
}
}
/// <summary>
/// Miscellanseous data value for the various decoders
/// </summary>
/// <value>The other.</value>
public object Other { get; set; }
public IList<sbyte[]> ByteSegments
{
get
{
return byteSegments;
}
}
public DecoderResult(byte[] rawBytes, String text, IList<byte[]> byteSegments, String ecLevel)
{
if (rawBytes == null && text == null)
{
throw new ArgumentException();
}
RawBytes = rawBytes;
Text = text;
ByteSegments = byteSegments;
ECLevel = ecLevel;
}
public string ECLevel
{
get
{
return ecLevel;
}
}
}
}
}

View file

@ -0,0 +1,527 @@
/*
* Copyright 2009 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.PDF417.Internal;
using System;
namespace ZXing.PDF417
{
/// <summary>
/// <author>SITA Lab (kevin.osullivan@sita.aero) </author>
/// <author>Guenther Grau </author>
/// <author>Stephen Furlani (C# Port)</author>
/// </summary>
public sealed class PDF417Common
{
public static readonly int INVALID_CODEWORD = -1;
public static readonly int NUMBER_OF_CODEWORDS = 929;
/// <summary>
/// Maximum Codewords (Data + Error).
/// </summary>
public static readonly int MAX_CODEWORDS_IN_BARCODE = NUMBER_OF_CODEWORDS - 1;
public static readonly int MIN_ROWS_IN_BARCODE = 3;
public static readonly int MAX_ROWS_IN_BARCODE = 90;
/// <summary>
/// One left row indication column + max 30 data columns + one right row indicator column
/// </summary>
public static readonly int MAX_CODEWORDS_IN_ROW = 32;
public static readonly int MODULES_IN_CODEWORD = 17;
public static readonly int MODULES_IN_STOP_PATTERN = 18;
public static readonly int BARS_IN_MODULE = 8;
private static readonly int[] EMPTY_INT_ARRAY = {};
/// <summary>
/// Initializes a new instance of the <see cref="ZXing.PDF417.PDF417Common"/> class.
/// Private, so as to force this classes singleton-ness
/// </summary>
private PDF417Common()
{
}
/// <summary>
/// Gets the bit count sum.
/// </summary>
/// <returns>The bit count sum.</returns>
/// <param name="moduleBitCount">Module bit count.</param>
public static int GetBitCountSum(int[] moduleBitCount)
{
int bitCountSum = 0;
foreach (int count in moduleBitCount)
{
bitCountSum += count;
}
return bitCountSum;
}
/// <summary>
/// Converts an ICollection<int> to an int[]
/// Carry-over from Java. Will likely remove and replace with the Generic .ToArray() method.
/// </summary>
/// <returns>The int array.</returns>
/// <param name="list">List.</param>
public static int[] ToIntArray(ICollection<int> list)
{
if (list == null || list.Count == 0)
{
return EMPTY_INT_ARRAY;
}
int[] result = new int[list.Count];
int i = 0;
foreach (int integer in list)
{
result[i++] = integer;
}
return result;
}
/// <summary>
/// Translate the symbol into a codeword
/// </summary>
/// <returns>the codeword corresponding to the symbol.</returns>
/// <param name="symbol">the symbol from the barcode..</param>
public static int GetCodeword(long symbol)
{
long sym = symbol & 0x3FFFF;
int i = FindCodewordIndex(sym);
if (i == -1)
{
return INVALID_CODEWORD;
}
return (CODEWORD_TABLE[i] - 1) % NUMBER_OF_CODEWORDS;
}
/// <summary>
/// Use a binary search to find the index of the codeword corresponding to
/// this symbol.
/// </summary>
/// <returns>the index into the codeword table.</returns>
/// <param name="symbol">the symbol from the barcode.</param>
private static int FindCodewordIndex(long symbol)
{
int first = 0;
int upto = SYMBOL_TABLE.Length;
while (first < upto)
{
// NOTE: Converted Java's '>>>' to '(int)((unit)x >>y)' in C#
// http://stackoverflow.com/q/1880172/266252
int mid = (int)((uint)(first + upto) >> 1); // Compute mid point. (i.e. bitshift == divide by 2)
if (symbol < SYMBOL_TABLE[mid])
{
upto = mid; // continue search in bottom half.
} else if (symbol > SYMBOL_TABLE[mid])
{
first = mid + 1; // continue search in top half.
} else
{
return mid; // Found it. return position
}
}
return -1;
}
/// <summary>
/// The sorted table of all possible symbols. Extracted from the PDF417
/// specification. The index of a symbol in this table corresponds to the
/// index into the codeword table.
/// </summary>
public static readonly int[] SYMBOL_TABLE = {
0x1025e, 0x1027a, 0x1029e, 0x102bc, 0x102f2, 0x102f4, 0x1032e, 0x1034e, 0x1035c, 0x10396, 0x103a6, 0x103ac,
0x10422, 0x10428, 0x10436, 0x10442, 0x10444, 0x10448, 0x10450, 0x1045e, 0x10466, 0x1046c, 0x1047a, 0x10482,
0x1049e, 0x104a0, 0x104bc, 0x104c6, 0x104d8, 0x104ee, 0x104f2, 0x104f4, 0x10504, 0x10508, 0x10510, 0x1051e,
0x10520, 0x1053c, 0x10540, 0x10578, 0x10586, 0x1058c, 0x10598, 0x105b0, 0x105be, 0x105ce, 0x105dc, 0x105e2,
0x105e4, 0x105e8, 0x105f6, 0x1062e, 0x1064e, 0x1065c, 0x1068e, 0x1069c, 0x106b8, 0x106de, 0x106fa, 0x10716,
0x10726, 0x1072c, 0x10746, 0x1074c, 0x10758, 0x1076e, 0x10792, 0x10794, 0x107a2, 0x107a4, 0x107a8, 0x107b6,
0x10822, 0x10828, 0x10842, 0x10848, 0x10850, 0x1085e, 0x10866, 0x1086c, 0x1087a, 0x10882, 0x10884, 0x10890,
0x1089e, 0x108a0, 0x108bc, 0x108c6, 0x108cc, 0x108d8, 0x108ee, 0x108f2, 0x108f4, 0x10902, 0x10908, 0x1091e,
0x10920, 0x1093c, 0x10940, 0x10978, 0x10986, 0x10998, 0x109b0, 0x109be, 0x109ce, 0x109dc, 0x109e2, 0x109e4,
0x109e8, 0x109f6, 0x10a08, 0x10a10, 0x10a1e, 0x10a20, 0x10a3c, 0x10a40, 0x10a78, 0x10af0, 0x10b06, 0x10b0c,
0x10b18, 0x10b30, 0x10b3e, 0x10b60, 0x10b7c, 0x10b8e, 0x10b9c, 0x10bb8, 0x10bc2, 0x10bc4, 0x10bc8, 0x10bd0,
0x10bde, 0x10be6, 0x10bec, 0x10c2e, 0x10c4e, 0x10c5c, 0x10c62, 0x10c64, 0x10c68, 0x10c76, 0x10c8e, 0x10c9c,
0x10cb8, 0x10cc2, 0x10cc4, 0x10cc8, 0x10cd0, 0x10cde, 0x10ce6, 0x10cec, 0x10cfa, 0x10d0e, 0x10d1c, 0x10d38,
0x10d70, 0x10d7e, 0x10d82, 0x10d84, 0x10d88, 0x10d90, 0x10d9e, 0x10da0, 0x10dbc, 0x10dc6, 0x10dcc, 0x10dd8,
0x10dee, 0x10df2, 0x10df4, 0x10e16, 0x10e26, 0x10e2c, 0x10e46, 0x10e58, 0x10e6e, 0x10e86, 0x10e8c, 0x10e98,
0x10eb0, 0x10ebe, 0x10ece, 0x10edc, 0x10f0a, 0x10f12, 0x10f14, 0x10f22, 0x10f28, 0x10f36, 0x10f42, 0x10f44,
0x10f48, 0x10f50, 0x10f5e, 0x10f66, 0x10f6c, 0x10fb2, 0x10fb4, 0x11022, 0x11028, 0x11042, 0x11048, 0x11050,
0x1105e, 0x1107a, 0x11082, 0x11084, 0x11090, 0x1109e, 0x110a0, 0x110bc, 0x110c6, 0x110cc, 0x110d8, 0x110ee,
0x110f2, 0x110f4, 0x11102, 0x1111e, 0x11120, 0x1113c, 0x11140, 0x11178, 0x11186, 0x11198, 0x111b0, 0x111be,
0x111ce, 0x111dc, 0x111e2, 0x111e4, 0x111e8, 0x111f6, 0x11208, 0x1121e, 0x11220, 0x11278, 0x112f0, 0x1130c,
0x11330, 0x1133e, 0x11360, 0x1137c, 0x1138e, 0x1139c, 0x113b8, 0x113c2, 0x113c8, 0x113d0, 0x113de, 0x113e6,
0x113ec, 0x11408, 0x11410, 0x1141e, 0x11420, 0x1143c, 0x11440, 0x11478, 0x114f0, 0x115e0, 0x1160c, 0x11618,
0x11630, 0x1163e, 0x11660, 0x1167c, 0x116c0, 0x116f8, 0x1171c, 0x11738, 0x11770, 0x1177e, 0x11782, 0x11784,
0x11788, 0x11790, 0x1179e, 0x117a0, 0x117bc, 0x117c6, 0x117cc, 0x117d8, 0x117ee, 0x1182e, 0x11834, 0x1184e,
0x1185c, 0x11862, 0x11864, 0x11868, 0x11876, 0x1188e, 0x1189c, 0x118b8, 0x118c2, 0x118c8, 0x118d0, 0x118de,
0x118e6, 0x118ec, 0x118fa, 0x1190e, 0x1191c, 0x11938, 0x11970, 0x1197e, 0x11982, 0x11984, 0x11990, 0x1199e,
0x119a0, 0x119bc, 0x119c6, 0x119cc, 0x119d8, 0x119ee, 0x119f2, 0x119f4, 0x11a0e, 0x11a1c, 0x11a38, 0x11a70,
0x11a7e, 0x11ae0, 0x11afc, 0x11b08, 0x11b10, 0x11b1e, 0x11b20, 0x11b3c, 0x11b40, 0x11b78, 0x11b8c, 0x11b98,
0x11bb0, 0x11bbe, 0x11bce, 0x11bdc, 0x11be2, 0x11be4, 0x11be8, 0x11bf6, 0x11c16, 0x11c26, 0x11c2c, 0x11c46,
0x11c4c, 0x11c58, 0x11c6e, 0x11c86, 0x11c98, 0x11cb0, 0x11cbe, 0x11cce, 0x11cdc, 0x11ce2, 0x11ce4, 0x11ce8,
0x11cf6, 0x11d06, 0x11d0c, 0x11d18, 0x11d30, 0x11d3e, 0x11d60, 0x11d7c, 0x11d8e, 0x11d9c, 0x11db8, 0x11dc4,
0x11dc8, 0x11dd0, 0x11dde, 0x11de6, 0x11dec, 0x11dfa, 0x11e0a, 0x11e12, 0x11e14, 0x11e22, 0x11e24, 0x11e28,
0x11e36, 0x11e42, 0x11e44, 0x11e50, 0x11e5e, 0x11e66, 0x11e6c, 0x11e82, 0x11e84, 0x11e88, 0x11e90, 0x11e9e,
0x11ea0, 0x11ebc, 0x11ec6, 0x11ecc, 0x11ed8, 0x11eee, 0x11f1a, 0x11f2e, 0x11f32, 0x11f34, 0x11f4e, 0x11f5c,
0x11f62, 0x11f64, 0x11f68, 0x11f76, 0x12048, 0x1205e, 0x12082, 0x12084, 0x12090, 0x1209e, 0x120a0, 0x120bc,
0x120d8, 0x120f2, 0x120f4, 0x12108, 0x1211e, 0x12120, 0x1213c, 0x12140, 0x12178, 0x12186, 0x12198, 0x121b0,
0x121be, 0x121e2, 0x121e4, 0x121e8, 0x121f6, 0x12204, 0x12210, 0x1221e, 0x12220, 0x12278, 0x122f0, 0x12306,
0x1230c, 0x12330, 0x1233e, 0x12360, 0x1237c, 0x1238e, 0x1239c, 0x123b8, 0x123c2, 0x123c8, 0x123d0, 0x123e6,
0x123ec, 0x1241e, 0x12420, 0x1243c, 0x124f0, 0x125e0, 0x12618, 0x1263e, 0x12660, 0x1267c, 0x126c0, 0x126f8,
0x12738, 0x12770, 0x1277e, 0x12782, 0x12784, 0x12790, 0x1279e, 0x127a0, 0x127bc, 0x127c6, 0x127cc, 0x127d8,
0x127ee, 0x12820, 0x1283c, 0x12840, 0x12878, 0x128f0, 0x129e0, 0x12bc0, 0x12c18, 0x12c30, 0x12c3e, 0x12c60,
0x12c7c, 0x12cc0, 0x12cf8, 0x12df0, 0x12e1c, 0x12e38, 0x12e70, 0x12e7e, 0x12ee0, 0x12efc, 0x12f04, 0x12f08,
0x12f10, 0x12f20, 0x12f3c, 0x12f40, 0x12f78, 0x12f86, 0x12f8c, 0x12f98, 0x12fb0, 0x12fbe, 0x12fce, 0x12fdc,
0x1302e, 0x1304e, 0x1305c, 0x13062, 0x13068, 0x1308e, 0x1309c, 0x130b8, 0x130c2, 0x130c8, 0x130d0, 0x130de,
0x130ec, 0x130fa, 0x1310e, 0x13138, 0x13170, 0x1317e, 0x13182, 0x13184, 0x13190, 0x1319e, 0x131a0, 0x131bc,
0x131c6, 0x131cc, 0x131d8, 0x131f2, 0x131f4, 0x1320e, 0x1321c, 0x13270, 0x1327e, 0x132e0, 0x132fc, 0x13308,
0x1331e, 0x13320, 0x1333c, 0x13340, 0x13378, 0x13386, 0x13398, 0x133b0, 0x133be, 0x133ce, 0x133dc, 0x133e2,
0x133e4, 0x133e8, 0x133f6, 0x1340e, 0x1341c, 0x13438, 0x13470, 0x1347e, 0x134e0, 0x134fc, 0x135c0, 0x135f8,
0x13608, 0x13610, 0x1361e, 0x13620, 0x1363c, 0x13640, 0x13678, 0x136f0, 0x1370c, 0x13718, 0x13730, 0x1373e,
0x13760, 0x1377c, 0x1379c, 0x137b8, 0x137c2, 0x137c4, 0x137c8, 0x137d0, 0x137de, 0x137e6, 0x137ec, 0x13816,
0x13826, 0x1382c, 0x13846, 0x1384c, 0x13858, 0x1386e, 0x13874, 0x13886, 0x13898, 0x138b0, 0x138be, 0x138ce,
0x138dc, 0x138e2, 0x138e4, 0x138e8, 0x13906, 0x1390c, 0x13930, 0x1393e, 0x13960, 0x1397c, 0x1398e, 0x1399c,
0x139b8, 0x139c8, 0x139d0, 0x139de, 0x139e6, 0x139ec, 0x139fa, 0x13a06, 0x13a0c, 0x13a18, 0x13a30, 0x13a3e,
0x13a60, 0x13a7c, 0x13ac0, 0x13af8, 0x13b0e, 0x13b1c, 0x13b38, 0x13b70, 0x13b7e, 0x13b88, 0x13b90, 0x13b9e,
0x13ba0, 0x13bbc, 0x13bcc, 0x13bd8, 0x13bee, 0x13bf2, 0x13bf4, 0x13c12, 0x13c14, 0x13c22, 0x13c24, 0x13c28,
0x13c36, 0x13c42, 0x13c48, 0x13c50, 0x13c5e, 0x13c66, 0x13c6c, 0x13c82, 0x13c84, 0x13c90, 0x13c9e, 0x13ca0,
0x13cbc, 0x13cc6, 0x13ccc, 0x13cd8, 0x13cee, 0x13d02, 0x13d04, 0x13d08, 0x13d10, 0x13d1e, 0x13d20, 0x13d3c,
0x13d40, 0x13d78, 0x13d86, 0x13d8c, 0x13d98, 0x13db0, 0x13dbe, 0x13dce, 0x13ddc, 0x13de4, 0x13de8, 0x13df6,
0x13e1a, 0x13e2e, 0x13e32, 0x13e34, 0x13e4e, 0x13e5c, 0x13e62, 0x13e64, 0x13e68, 0x13e76, 0x13e8e, 0x13e9c,
0x13eb8, 0x13ec2, 0x13ec4, 0x13ec8, 0x13ed0, 0x13ede, 0x13ee6, 0x13eec, 0x13f26, 0x13f2c, 0x13f3a, 0x13f46,
0x13f4c, 0x13f58, 0x13f6e, 0x13f72, 0x13f74, 0x14082, 0x1409e, 0x140a0, 0x140bc, 0x14104, 0x14108, 0x14110,
0x1411e, 0x14120, 0x1413c, 0x14140, 0x14178, 0x1418c, 0x14198, 0x141b0, 0x141be, 0x141e2, 0x141e4, 0x141e8,
0x14208, 0x14210, 0x1421e, 0x14220, 0x1423c, 0x14240, 0x14278, 0x142f0, 0x14306, 0x1430c, 0x14318, 0x14330,
0x1433e, 0x14360, 0x1437c, 0x1438e, 0x143c2, 0x143c4, 0x143c8, 0x143d0, 0x143e6, 0x143ec, 0x14408, 0x14410,
0x1441e, 0x14420, 0x1443c, 0x14440, 0x14478, 0x144f0, 0x145e0, 0x1460c, 0x14618, 0x14630, 0x1463e, 0x14660,
0x1467c, 0x146c0, 0x146f8, 0x1471c, 0x14738, 0x14770, 0x1477e, 0x14782, 0x14784, 0x14788, 0x14790, 0x147a0,
0x147bc, 0x147c6, 0x147cc, 0x147d8, 0x147ee, 0x14810, 0x14820, 0x1483c, 0x14840, 0x14878, 0x148f0, 0x149e0,
0x14bc0, 0x14c30, 0x14c3e, 0x14c60, 0x14c7c, 0x14cc0, 0x14cf8, 0x14df0, 0x14e38, 0x14e70, 0x14e7e, 0x14ee0,
0x14efc, 0x14f04, 0x14f08, 0x14f10, 0x14f1e, 0x14f20, 0x14f3c, 0x14f40, 0x14f78, 0x14f86, 0x14f8c, 0x14f98,
0x14fb0, 0x14fce, 0x14fdc, 0x15020, 0x15040, 0x15078, 0x150f0, 0x151e0, 0x153c0, 0x15860, 0x1587c, 0x158c0,
0x158f8, 0x159f0, 0x15be0, 0x15c70, 0x15c7e, 0x15ce0, 0x15cfc, 0x15dc0, 0x15df8, 0x15e08, 0x15e10, 0x15e20,
0x15e40, 0x15e78, 0x15ef0, 0x15f0c, 0x15f18, 0x15f30, 0x15f60, 0x15f7c, 0x15f8e, 0x15f9c, 0x15fb8, 0x1604e,
0x1605c, 0x1608e, 0x1609c, 0x160b8, 0x160c2, 0x160c4, 0x160c8, 0x160de, 0x1610e, 0x1611c, 0x16138, 0x16170,
0x1617e, 0x16184, 0x16188, 0x16190, 0x1619e, 0x161a0, 0x161bc, 0x161c6, 0x161cc, 0x161d8, 0x161f2, 0x161f4,
0x1620e, 0x1621c, 0x16238, 0x16270, 0x1627e, 0x162e0, 0x162fc, 0x16304, 0x16308, 0x16310, 0x1631e, 0x16320,
0x1633c, 0x16340, 0x16378, 0x16386, 0x1638c, 0x16398, 0x163b0, 0x163be, 0x163ce, 0x163dc, 0x163e2, 0x163e4,
0x163e8, 0x163f6, 0x1640e, 0x1641c, 0x16438, 0x16470, 0x1647e, 0x164e0, 0x164fc, 0x165c0, 0x165f8, 0x16610,
0x1661e, 0x16620, 0x1663c, 0x16640, 0x16678, 0x166f0, 0x16718, 0x16730, 0x1673e, 0x16760, 0x1677c, 0x1678e,
0x1679c, 0x167b8, 0x167c2, 0x167c4, 0x167c8, 0x167d0, 0x167de, 0x167e6, 0x167ec, 0x1681c, 0x16838, 0x16870,
0x168e0, 0x168fc, 0x169c0, 0x169f8, 0x16bf0, 0x16c10, 0x16c1e, 0x16c20, 0x16c3c, 0x16c40, 0x16c78, 0x16cf0,
0x16de0, 0x16e18, 0x16e30, 0x16e3e, 0x16e60, 0x16e7c, 0x16ec0, 0x16ef8, 0x16f1c, 0x16f38, 0x16f70, 0x16f7e,
0x16f84, 0x16f88, 0x16f90, 0x16f9e, 0x16fa0, 0x16fbc, 0x16fc6, 0x16fcc, 0x16fd8, 0x17026, 0x1702c, 0x17046,
0x1704c, 0x17058, 0x1706e, 0x17086, 0x1708c, 0x17098, 0x170b0, 0x170be, 0x170ce, 0x170dc, 0x170e8, 0x17106,
0x1710c, 0x17118, 0x17130, 0x1713e, 0x17160, 0x1717c, 0x1718e, 0x1719c, 0x171b8, 0x171c2, 0x171c4, 0x171c8,
0x171d0, 0x171de, 0x171e6, 0x171ec, 0x171fa, 0x17206, 0x1720c, 0x17218, 0x17230, 0x1723e, 0x17260, 0x1727c,
0x172c0, 0x172f8, 0x1730e, 0x1731c, 0x17338, 0x17370, 0x1737e, 0x17388, 0x17390, 0x1739e, 0x173a0, 0x173bc,
0x173cc, 0x173d8, 0x173ee, 0x173f2, 0x173f4, 0x1740c, 0x17418, 0x17430, 0x1743e, 0x17460, 0x1747c, 0x174c0,
0x174f8, 0x175f0, 0x1760e, 0x1761c, 0x17638, 0x17670, 0x1767e, 0x176e0, 0x176fc, 0x17708, 0x17710, 0x1771e,
0x17720, 0x1773c, 0x17740, 0x17778, 0x17798, 0x177b0, 0x177be, 0x177dc, 0x177e2, 0x177e4, 0x177e8, 0x17822,
0x17824, 0x17828, 0x17836, 0x17842, 0x17844, 0x17848, 0x17850, 0x1785e, 0x17866, 0x1786c, 0x17882, 0x17884,
0x17888, 0x17890, 0x1789e, 0x178a0, 0x178bc, 0x178c6, 0x178cc, 0x178d8, 0x178ee, 0x178f2, 0x178f4, 0x17902,
0x17904, 0x17908, 0x17910, 0x1791e, 0x17920, 0x1793c, 0x17940, 0x17978, 0x17986, 0x1798c, 0x17998, 0x179b0,
0x179be, 0x179ce, 0x179dc, 0x179e2, 0x179e4, 0x179e8, 0x179f6, 0x17a04, 0x17a08, 0x17a10, 0x17a1e, 0x17a20,
0x17a3c, 0x17a40, 0x17a78, 0x17af0, 0x17b06, 0x17b0c, 0x17b18, 0x17b30, 0x17b3e, 0x17b60, 0x17b7c, 0x17b8e,
0x17b9c, 0x17bb8, 0x17bc4, 0x17bc8, 0x17bd0, 0x17bde, 0x17be6, 0x17bec, 0x17c2e, 0x17c32, 0x17c34, 0x17c4e,
0x17c5c, 0x17c62, 0x17c64, 0x17c68, 0x17c76, 0x17c8e, 0x17c9c, 0x17cb8, 0x17cc2, 0x17cc4, 0x17cc8, 0x17cd0,
0x17cde, 0x17ce6, 0x17cec, 0x17d0e, 0x17d1c, 0x17d38, 0x17d70, 0x17d82, 0x17d84, 0x17d88, 0x17d90, 0x17d9e,
0x17da0, 0x17dbc, 0x17dc6, 0x17dcc, 0x17dd8, 0x17dee, 0x17e26, 0x17e2c, 0x17e3a, 0x17e46, 0x17e4c, 0x17e58,
0x17e6e, 0x17e72, 0x17e74, 0x17e86, 0x17e8c, 0x17e98, 0x17eb0, 0x17ece, 0x17edc, 0x17ee2, 0x17ee4, 0x17ee8,
0x17ef6, 0x1813a, 0x18172, 0x18174, 0x18216, 0x18226, 0x1823a, 0x1824c, 0x18258, 0x1826e, 0x18272, 0x18274,
0x18298, 0x182be, 0x182e2, 0x182e4, 0x182e8, 0x182f6, 0x1835e, 0x1837a, 0x183ae, 0x183d6, 0x18416, 0x18426,
0x1842c, 0x1843a, 0x18446, 0x18458, 0x1846e, 0x18472, 0x18474, 0x18486, 0x184b0, 0x184be, 0x184ce, 0x184dc,
0x184e2, 0x184e4, 0x184e8, 0x184f6, 0x18506, 0x1850c, 0x18518, 0x18530, 0x1853e, 0x18560, 0x1857c, 0x1858e,
0x1859c, 0x185b8, 0x185c2, 0x185c4, 0x185c8, 0x185d0, 0x185de, 0x185e6, 0x185ec, 0x185fa, 0x18612, 0x18614,
0x18622, 0x18628, 0x18636, 0x18642, 0x18650, 0x1865e, 0x1867a, 0x18682, 0x18684, 0x18688, 0x18690, 0x1869e,
0x186a0, 0x186bc, 0x186c6, 0x186cc, 0x186d8, 0x186ee, 0x186f2, 0x186f4, 0x1872e, 0x1874e, 0x1875c, 0x18796,
0x187a6, 0x187ac, 0x187d2, 0x187d4, 0x18826, 0x1882c, 0x1883a, 0x18846, 0x1884c, 0x18858, 0x1886e, 0x18872,
0x18874, 0x18886, 0x18898, 0x188b0, 0x188be, 0x188ce, 0x188dc, 0x188e2, 0x188e4, 0x188e8, 0x188f6, 0x1890c,
0x18930, 0x1893e, 0x18960, 0x1897c, 0x1898e, 0x189b8, 0x189c2, 0x189c8, 0x189d0, 0x189de, 0x189e6, 0x189ec,
0x189fa, 0x18a18, 0x18a30, 0x18a3e, 0x18a60, 0x18a7c, 0x18ac0, 0x18af8, 0x18b1c, 0x18b38, 0x18b70, 0x18b7e,
0x18b82, 0x18b84, 0x18b88, 0x18b90, 0x18b9e, 0x18ba0, 0x18bbc, 0x18bc6, 0x18bcc, 0x18bd8, 0x18bee, 0x18bf2,
0x18bf4, 0x18c22, 0x18c24, 0x18c28, 0x18c36, 0x18c42, 0x18c48, 0x18c50, 0x18c5e, 0x18c66, 0x18c7a, 0x18c82,
0x18c84, 0x18c90, 0x18c9e, 0x18ca0, 0x18cbc, 0x18ccc, 0x18cf2, 0x18cf4, 0x18d04, 0x18d08, 0x18d10, 0x18d1e,
0x18d20, 0x18d3c, 0x18d40, 0x18d78, 0x18d86, 0x18d98, 0x18dce, 0x18de2, 0x18de4, 0x18de8, 0x18e2e, 0x18e32,
0x18e34, 0x18e4e, 0x18e5c, 0x18e62, 0x18e64, 0x18e68, 0x18e8e, 0x18e9c, 0x18eb8, 0x18ec2, 0x18ec4, 0x18ec8,
0x18ed0, 0x18efa, 0x18f16, 0x18f26, 0x18f2c, 0x18f46, 0x18f4c, 0x18f58, 0x18f6e, 0x18f8a, 0x18f92, 0x18f94,
0x18fa2, 0x18fa4, 0x18fa8, 0x18fb6, 0x1902c, 0x1903a, 0x19046, 0x1904c, 0x19058, 0x19072, 0x19074, 0x19086,
0x19098, 0x190b0, 0x190be, 0x190ce, 0x190dc, 0x190e2, 0x190e8, 0x190f6, 0x19106, 0x1910c, 0x19130, 0x1913e,
0x19160, 0x1917c, 0x1918e, 0x1919c, 0x191b8, 0x191c2, 0x191c8, 0x191d0, 0x191de, 0x191e6, 0x191ec, 0x191fa,
0x19218, 0x1923e, 0x19260, 0x1927c, 0x192c0, 0x192f8, 0x19338, 0x19370, 0x1937e, 0x19382, 0x19384, 0x19390,
0x1939e, 0x193a0, 0x193bc, 0x193c6, 0x193cc, 0x193d8, 0x193ee, 0x193f2, 0x193f4, 0x19430, 0x1943e, 0x19460,
0x1947c, 0x194c0, 0x194f8, 0x195f0, 0x19638, 0x19670, 0x1967e, 0x196e0, 0x196fc, 0x19702, 0x19704, 0x19708,
0x19710, 0x19720, 0x1973c, 0x19740, 0x19778, 0x19786, 0x1978c, 0x19798, 0x197b0, 0x197be, 0x197ce, 0x197dc,
0x197e2, 0x197e4, 0x197e8, 0x19822, 0x19824, 0x19842, 0x19848, 0x19850, 0x1985e, 0x19866, 0x1987a, 0x19882,
0x19884, 0x19890, 0x1989e, 0x198a0, 0x198bc, 0x198cc, 0x198f2, 0x198f4, 0x19902, 0x19908, 0x1991e, 0x19920,
0x1993c, 0x19940, 0x19978, 0x19986, 0x19998, 0x199ce, 0x199e2, 0x199e4, 0x199e8, 0x19a08, 0x19a10, 0x19a1e,
0x19a20, 0x19a3c, 0x19a40, 0x19a78, 0x19af0, 0x19b18, 0x19b3e, 0x19b60, 0x19b9c, 0x19bc2, 0x19bc4, 0x19bc8,
0x19bd0, 0x19be6, 0x19c2e, 0x19c34, 0x19c4e, 0x19c5c, 0x19c62, 0x19c64, 0x19c68, 0x19c8e, 0x19c9c, 0x19cb8,
0x19cc2, 0x19cc8, 0x19cd0, 0x19ce6, 0x19cfa, 0x19d0e, 0x19d1c, 0x19d38, 0x19d70, 0x19d7e, 0x19d82, 0x19d84,
0x19d88, 0x19d90, 0x19da0, 0x19dcc, 0x19df2, 0x19df4, 0x19e16, 0x19e26, 0x19e2c, 0x19e46, 0x19e4c, 0x19e58,
0x19e74, 0x19e86, 0x19e8c, 0x19e98, 0x19eb0, 0x19ebe, 0x19ece, 0x19ee2, 0x19ee4, 0x19ee8, 0x19f0a, 0x19f12,
0x19f14, 0x19f22, 0x19f24, 0x19f28, 0x19f42, 0x19f44, 0x19f48, 0x19f50, 0x19f5e, 0x19f6c, 0x19f9a, 0x19fae,
0x19fb2, 0x19fb4, 0x1a046, 0x1a04c, 0x1a072, 0x1a074, 0x1a086, 0x1a08c, 0x1a098, 0x1a0b0, 0x1a0be, 0x1a0e2,
0x1a0e4, 0x1a0e8, 0x1a0f6, 0x1a106, 0x1a10c, 0x1a118, 0x1a130, 0x1a13e, 0x1a160, 0x1a17c, 0x1a18e, 0x1a19c,
0x1a1b8, 0x1a1c2, 0x1a1c4, 0x1a1c8, 0x1a1d0, 0x1a1de, 0x1a1e6, 0x1a1ec, 0x1a218, 0x1a230, 0x1a23e, 0x1a260,
0x1a27c, 0x1a2c0, 0x1a2f8, 0x1a31c, 0x1a338, 0x1a370, 0x1a37e, 0x1a382, 0x1a384, 0x1a388, 0x1a390, 0x1a39e,
0x1a3a0, 0x1a3bc, 0x1a3c6, 0x1a3cc, 0x1a3d8, 0x1a3ee, 0x1a3f2, 0x1a3f4, 0x1a418, 0x1a430, 0x1a43e, 0x1a460,
0x1a47c, 0x1a4c0, 0x1a4f8, 0x1a5f0, 0x1a61c, 0x1a638, 0x1a670, 0x1a67e, 0x1a6e0, 0x1a6fc, 0x1a702, 0x1a704,
0x1a708, 0x1a710, 0x1a71e, 0x1a720, 0x1a73c, 0x1a740, 0x1a778, 0x1a786, 0x1a78c, 0x1a798, 0x1a7b0, 0x1a7be,
0x1a7ce, 0x1a7dc, 0x1a7e2, 0x1a7e4, 0x1a7e8, 0x1a830, 0x1a860, 0x1a87c, 0x1a8c0, 0x1a8f8, 0x1a9f0, 0x1abe0,
0x1ac70, 0x1ac7e, 0x1ace0, 0x1acfc, 0x1adc0, 0x1adf8, 0x1ae04, 0x1ae08, 0x1ae10, 0x1ae20, 0x1ae3c, 0x1ae40,
0x1ae78, 0x1aef0, 0x1af06, 0x1af0c, 0x1af18, 0x1af30, 0x1af3e, 0x1af60, 0x1af7c, 0x1af8e, 0x1af9c, 0x1afb8,
0x1afc4, 0x1afc8, 0x1afd0, 0x1afde, 0x1b042, 0x1b05e, 0x1b07a, 0x1b082, 0x1b084, 0x1b088, 0x1b090, 0x1b09e,
0x1b0a0, 0x1b0bc, 0x1b0cc, 0x1b0f2, 0x1b0f4, 0x1b102, 0x1b104, 0x1b108, 0x1b110, 0x1b11e, 0x1b120, 0x1b13c,
0x1b140, 0x1b178, 0x1b186, 0x1b198, 0x1b1ce, 0x1b1e2, 0x1b1e4, 0x1b1e8, 0x1b204, 0x1b208, 0x1b210, 0x1b21e,
0x1b220, 0x1b23c, 0x1b240, 0x1b278, 0x1b2f0, 0x1b30c, 0x1b33e, 0x1b360, 0x1b39c, 0x1b3c2, 0x1b3c4, 0x1b3c8,
0x1b3d0, 0x1b3e6, 0x1b410, 0x1b41e, 0x1b420, 0x1b43c, 0x1b440, 0x1b478, 0x1b4f0, 0x1b5e0, 0x1b618, 0x1b660,
0x1b67c, 0x1b6c0, 0x1b738, 0x1b782, 0x1b784, 0x1b788, 0x1b790, 0x1b79e, 0x1b7a0, 0x1b7cc, 0x1b82e, 0x1b84e,
0x1b85c, 0x1b88e, 0x1b89c, 0x1b8b8, 0x1b8c2, 0x1b8c4, 0x1b8c8, 0x1b8d0, 0x1b8e6, 0x1b8fa, 0x1b90e, 0x1b91c,
0x1b938, 0x1b970, 0x1b97e, 0x1b982, 0x1b984, 0x1b988, 0x1b990, 0x1b99e, 0x1b9a0, 0x1b9cc, 0x1b9f2, 0x1b9f4,
0x1ba0e, 0x1ba1c, 0x1ba38, 0x1ba70, 0x1ba7e, 0x1bae0, 0x1bafc, 0x1bb08, 0x1bb10, 0x1bb20, 0x1bb3c, 0x1bb40,
0x1bb98, 0x1bbce, 0x1bbe2, 0x1bbe4, 0x1bbe8, 0x1bc16, 0x1bc26, 0x1bc2c, 0x1bc46, 0x1bc4c, 0x1bc58, 0x1bc72,
0x1bc74, 0x1bc86, 0x1bc8c, 0x1bc98, 0x1bcb0, 0x1bcbe, 0x1bcce, 0x1bce2, 0x1bce4, 0x1bce8, 0x1bd06, 0x1bd0c,
0x1bd18, 0x1bd30, 0x1bd3e, 0x1bd60, 0x1bd7c, 0x1bd9c, 0x1bdc2, 0x1bdc4, 0x1bdc8, 0x1bdd0, 0x1bde6, 0x1bdfa,
0x1be12, 0x1be14, 0x1be22, 0x1be24, 0x1be28, 0x1be42, 0x1be44, 0x1be48, 0x1be50, 0x1be5e, 0x1be66, 0x1be82,
0x1be84, 0x1be88, 0x1be90, 0x1be9e, 0x1bea0, 0x1bebc, 0x1becc, 0x1bef4, 0x1bf1a, 0x1bf2e, 0x1bf32, 0x1bf34,
0x1bf4e, 0x1bf5c, 0x1bf62, 0x1bf64, 0x1bf68, 0x1c09a, 0x1c0b2, 0x1c0b4, 0x1c11a, 0x1c132, 0x1c134, 0x1c162,
0x1c164, 0x1c168, 0x1c176, 0x1c1ba, 0x1c21a, 0x1c232, 0x1c234, 0x1c24e, 0x1c25c, 0x1c262, 0x1c264, 0x1c268,
0x1c276, 0x1c28e, 0x1c2c2, 0x1c2c4, 0x1c2c8, 0x1c2d0, 0x1c2de, 0x1c2e6, 0x1c2ec, 0x1c2fa, 0x1c316, 0x1c326,
0x1c33a, 0x1c346, 0x1c34c, 0x1c372, 0x1c374, 0x1c41a, 0x1c42e, 0x1c432, 0x1c434, 0x1c44e, 0x1c45c, 0x1c462,
0x1c464, 0x1c468, 0x1c476, 0x1c48e, 0x1c49c, 0x1c4b8, 0x1c4c2, 0x1c4c8, 0x1c4d0, 0x1c4de, 0x1c4e6, 0x1c4ec,
0x1c4fa, 0x1c51c, 0x1c538, 0x1c570, 0x1c57e, 0x1c582, 0x1c584, 0x1c588, 0x1c590, 0x1c59e, 0x1c5a0, 0x1c5bc,
0x1c5c6, 0x1c5cc, 0x1c5d8, 0x1c5ee, 0x1c5f2, 0x1c5f4, 0x1c616, 0x1c626, 0x1c62c, 0x1c63a, 0x1c646, 0x1c64c,
0x1c658, 0x1c66e, 0x1c672, 0x1c674, 0x1c686, 0x1c68c, 0x1c698, 0x1c6b0, 0x1c6be, 0x1c6ce, 0x1c6dc, 0x1c6e2,
0x1c6e4, 0x1c6e8, 0x1c712, 0x1c714, 0x1c722, 0x1c728, 0x1c736, 0x1c742, 0x1c744, 0x1c748, 0x1c750, 0x1c75e,
0x1c766, 0x1c76c, 0x1c77a, 0x1c7ae, 0x1c7d6, 0x1c7ea, 0x1c81a, 0x1c82e, 0x1c832, 0x1c834, 0x1c84e, 0x1c85c,
0x1c862, 0x1c864, 0x1c868, 0x1c876, 0x1c88e, 0x1c89c, 0x1c8b8, 0x1c8c2, 0x1c8c8, 0x1c8d0, 0x1c8de, 0x1c8e6,
0x1c8ec, 0x1c8fa, 0x1c90e, 0x1c938, 0x1c970, 0x1c97e, 0x1c982, 0x1c984, 0x1c990, 0x1c99e, 0x1c9a0, 0x1c9bc,
0x1c9c6, 0x1c9cc, 0x1c9d8, 0x1c9ee, 0x1c9f2, 0x1c9f4, 0x1ca38, 0x1ca70, 0x1ca7e, 0x1cae0, 0x1cafc, 0x1cb02,
0x1cb04, 0x1cb08, 0x1cb10, 0x1cb20, 0x1cb3c, 0x1cb40, 0x1cb78, 0x1cb86, 0x1cb8c, 0x1cb98, 0x1cbb0, 0x1cbbe,
0x1cbce, 0x1cbdc, 0x1cbe2, 0x1cbe4, 0x1cbe8, 0x1cbf6, 0x1cc16, 0x1cc26, 0x1cc2c, 0x1cc3a, 0x1cc46, 0x1cc58,
0x1cc72, 0x1cc74, 0x1cc86, 0x1ccb0, 0x1ccbe, 0x1ccce, 0x1cce2, 0x1cce4, 0x1cce8, 0x1cd06, 0x1cd0c, 0x1cd18,
0x1cd30, 0x1cd3e, 0x1cd60, 0x1cd7c, 0x1cd9c, 0x1cdc2, 0x1cdc4, 0x1cdc8, 0x1cdd0, 0x1cdde, 0x1cde6, 0x1cdfa,
0x1ce22, 0x1ce28, 0x1ce42, 0x1ce50, 0x1ce5e, 0x1ce66, 0x1ce7a, 0x1ce82, 0x1ce84, 0x1ce88, 0x1ce90, 0x1ce9e,
0x1cea0, 0x1cebc, 0x1cecc, 0x1cef2, 0x1cef4, 0x1cf2e, 0x1cf32, 0x1cf34, 0x1cf4e, 0x1cf5c, 0x1cf62, 0x1cf64,
0x1cf68, 0x1cf96, 0x1cfa6, 0x1cfac, 0x1cfca, 0x1cfd2, 0x1cfd4, 0x1d02e, 0x1d032, 0x1d034, 0x1d04e, 0x1d05c,
0x1d062, 0x1d064, 0x1d068, 0x1d076, 0x1d08e, 0x1d09c, 0x1d0b8, 0x1d0c2, 0x1d0c4, 0x1d0c8, 0x1d0d0, 0x1d0de,
0x1d0e6, 0x1d0ec, 0x1d0fa, 0x1d11c, 0x1d138, 0x1d170, 0x1d17e, 0x1d182, 0x1d184, 0x1d188, 0x1d190, 0x1d19e,
0x1d1a0, 0x1d1bc, 0x1d1c6, 0x1d1cc, 0x1d1d8, 0x1d1ee, 0x1d1f2, 0x1d1f4, 0x1d21c, 0x1d238, 0x1d270, 0x1d27e,
0x1d2e0, 0x1d2fc, 0x1d302, 0x1d304, 0x1d308, 0x1d310, 0x1d31e, 0x1d320, 0x1d33c, 0x1d340, 0x1d378, 0x1d386,
0x1d38c, 0x1d398, 0x1d3b0, 0x1d3be, 0x1d3ce, 0x1d3dc, 0x1d3e2, 0x1d3e4, 0x1d3e8, 0x1d3f6, 0x1d470, 0x1d47e,
0x1d4e0, 0x1d4fc, 0x1d5c0, 0x1d5f8, 0x1d604, 0x1d608, 0x1d610, 0x1d620, 0x1d640, 0x1d678, 0x1d6f0, 0x1d706,
0x1d70c, 0x1d718, 0x1d730, 0x1d73e, 0x1d760, 0x1d77c, 0x1d78e, 0x1d79c, 0x1d7b8, 0x1d7c2, 0x1d7c4, 0x1d7c8,
0x1d7d0, 0x1d7de, 0x1d7e6, 0x1d7ec, 0x1d826, 0x1d82c, 0x1d83a, 0x1d846, 0x1d84c, 0x1d858, 0x1d872, 0x1d874,
0x1d886, 0x1d88c, 0x1d898, 0x1d8b0, 0x1d8be, 0x1d8ce, 0x1d8e2, 0x1d8e4, 0x1d8e8, 0x1d8f6, 0x1d90c, 0x1d918,
0x1d930, 0x1d93e, 0x1d960, 0x1d97c, 0x1d99c, 0x1d9c2, 0x1d9c4, 0x1d9c8, 0x1d9d0, 0x1d9e6, 0x1d9fa, 0x1da0c,
0x1da18, 0x1da30, 0x1da3e, 0x1da60, 0x1da7c, 0x1dac0, 0x1daf8, 0x1db38, 0x1db82, 0x1db84, 0x1db88, 0x1db90,
0x1db9e, 0x1dba0, 0x1dbcc, 0x1dbf2, 0x1dbf4, 0x1dc22, 0x1dc42, 0x1dc44, 0x1dc48, 0x1dc50, 0x1dc5e, 0x1dc66,
0x1dc7a, 0x1dc82, 0x1dc84, 0x1dc88, 0x1dc90, 0x1dc9e, 0x1dca0, 0x1dcbc, 0x1dccc, 0x1dcf2, 0x1dcf4, 0x1dd04,
0x1dd08, 0x1dd10, 0x1dd1e, 0x1dd20, 0x1dd3c, 0x1dd40, 0x1dd78, 0x1dd86, 0x1dd98, 0x1ddce, 0x1dde2, 0x1dde4,
0x1dde8, 0x1de2e, 0x1de32, 0x1de34, 0x1de4e, 0x1de5c, 0x1de62, 0x1de64, 0x1de68, 0x1de8e, 0x1de9c, 0x1deb8,
0x1dec2, 0x1dec4, 0x1dec8, 0x1ded0, 0x1dee6, 0x1defa, 0x1df16, 0x1df26, 0x1df2c, 0x1df46, 0x1df4c, 0x1df58,
0x1df72, 0x1df74, 0x1df8a, 0x1df92, 0x1df94, 0x1dfa2, 0x1dfa4, 0x1dfa8, 0x1e08a, 0x1e092, 0x1e094, 0x1e0a2,
0x1e0a4, 0x1e0a8, 0x1e0b6, 0x1e0da, 0x1e10a, 0x1e112, 0x1e114, 0x1e122, 0x1e124, 0x1e128, 0x1e136, 0x1e142,
0x1e144, 0x1e148, 0x1e150, 0x1e166, 0x1e16c, 0x1e17a, 0x1e19a, 0x1e1b2, 0x1e1b4, 0x1e20a, 0x1e212, 0x1e214,
0x1e222, 0x1e224, 0x1e228, 0x1e236, 0x1e242, 0x1e248, 0x1e250, 0x1e25e, 0x1e266, 0x1e26c, 0x1e27a, 0x1e282,
0x1e284, 0x1e288, 0x1e290, 0x1e2a0, 0x1e2bc, 0x1e2c6, 0x1e2cc, 0x1e2d8, 0x1e2ee, 0x1e2f2, 0x1e2f4, 0x1e31a,
0x1e332, 0x1e334, 0x1e35c, 0x1e362, 0x1e364, 0x1e368, 0x1e3ba, 0x1e40a, 0x1e412, 0x1e414, 0x1e422, 0x1e428,
0x1e436, 0x1e442, 0x1e448, 0x1e450, 0x1e45e, 0x1e466, 0x1e46c, 0x1e47a, 0x1e482, 0x1e484, 0x1e490, 0x1e49e,
0x1e4a0, 0x1e4bc, 0x1e4c6, 0x1e4cc, 0x1e4d8, 0x1e4ee, 0x1e4f2, 0x1e4f4, 0x1e502, 0x1e504, 0x1e508, 0x1e510,
0x1e51e, 0x1e520, 0x1e53c, 0x1e540, 0x1e578, 0x1e586, 0x1e58c, 0x1e598, 0x1e5b0, 0x1e5be, 0x1e5ce, 0x1e5dc,
0x1e5e2, 0x1e5e4, 0x1e5e8, 0x1e5f6, 0x1e61a, 0x1e62e, 0x1e632, 0x1e634, 0x1e64e, 0x1e65c, 0x1e662, 0x1e668,
0x1e68e, 0x1e69c, 0x1e6b8, 0x1e6c2, 0x1e6c4, 0x1e6c8, 0x1e6d0, 0x1e6e6, 0x1e6fa, 0x1e716, 0x1e726, 0x1e72c,
0x1e73a, 0x1e746, 0x1e74c, 0x1e758, 0x1e772, 0x1e774, 0x1e792, 0x1e794, 0x1e7a2, 0x1e7a4, 0x1e7a8, 0x1e7b6,
0x1e812, 0x1e814, 0x1e822, 0x1e824, 0x1e828, 0x1e836, 0x1e842, 0x1e844, 0x1e848, 0x1e850, 0x1e85e, 0x1e866,
0x1e86c, 0x1e87a, 0x1e882, 0x1e884, 0x1e888, 0x1e890, 0x1e89e, 0x1e8a0, 0x1e8bc, 0x1e8c6, 0x1e8cc, 0x1e8d8,
0x1e8ee, 0x1e8f2, 0x1e8f4, 0x1e902, 0x1e904, 0x1e908, 0x1e910, 0x1e920, 0x1e93c, 0x1e940, 0x1e978, 0x1e986,
0x1e98c, 0x1e998, 0x1e9b0, 0x1e9be, 0x1e9ce, 0x1e9dc, 0x1e9e2, 0x1e9e4, 0x1e9e8, 0x1e9f6, 0x1ea04, 0x1ea08,
0x1ea10, 0x1ea20, 0x1ea40, 0x1ea78, 0x1eaf0, 0x1eb06, 0x1eb0c, 0x1eb18, 0x1eb30, 0x1eb3e, 0x1eb60, 0x1eb7c,
0x1eb8e, 0x1eb9c, 0x1ebb8, 0x1ebc2, 0x1ebc4, 0x1ebc8, 0x1ebd0, 0x1ebde, 0x1ebe6, 0x1ebec, 0x1ec1a, 0x1ec2e,
0x1ec32, 0x1ec34, 0x1ec4e, 0x1ec5c, 0x1ec62, 0x1ec64, 0x1ec68, 0x1ec8e, 0x1ec9c, 0x1ecb8, 0x1ecc2, 0x1ecc4,
0x1ecc8, 0x1ecd0, 0x1ece6, 0x1ecfa, 0x1ed0e, 0x1ed1c, 0x1ed38, 0x1ed70, 0x1ed7e, 0x1ed82, 0x1ed84, 0x1ed88,
0x1ed90, 0x1ed9e, 0x1eda0, 0x1edcc, 0x1edf2, 0x1edf4, 0x1ee16, 0x1ee26, 0x1ee2c, 0x1ee3a, 0x1ee46, 0x1ee4c,
0x1ee58, 0x1ee6e, 0x1ee72, 0x1ee74, 0x1ee86, 0x1ee8c, 0x1ee98, 0x1eeb0, 0x1eebe, 0x1eece, 0x1eedc, 0x1eee2,
0x1eee4, 0x1eee8, 0x1ef12, 0x1ef22, 0x1ef24, 0x1ef28, 0x1ef36, 0x1ef42, 0x1ef44, 0x1ef48, 0x1ef50, 0x1ef5e,
0x1ef66, 0x1ef6c, 0x1ef7a, 0x1efae, 0x1efb2, 0x1efb4, 0x1efd6, 0x1f096, 0x1f0a6, 0x1f0ac, 0x1f0ba, 0x1f0ca,
0x1f0d2, 0x1f0d4, 0x1f116, 0x1f126, 0x1f12c, 0x1f13a, 0x1f146, 0x1f14c, 0x1f158, 0x1f16e, 0x1f172, 0x1f174,
0x1f18a, 0x1f192, 0x1f194, 0x1f1a2, 0x1f1a4, 0x1f1a8, 0x1f1da, 0x1f216, 0x1f226, 0x1f22c, 0x1f23a, 0x1f246,
0x1f258, 0x1f26e, 0x1f272, 0x1f274, 0x1f286, 0x1f28c, 0x1f298, 0x1f2b0, 0x1f2be, 0x1f2ce, 0x1f2dc, 0x1f2e2,
0x1f2e4, 0x1f2e8, 0x1f2f6, 0x1f30a, 0x1f312, 0x1f314, 0x1f322, 0x1f328, 0x1f342, 0x1f344, 0x1f348, 0x1f350,
0x1f35e, 0x1f366, 0x1f37a, 0x1f39a, 0x1f3ae, 0x1f3b2, 0x1f3b4, 0x1f416, 0x1f426, 0x1f42c, 0x1f43a, 0x1f446,
0x1f44c, 0x1f458, 0x1f46e, 0x1f472, 0x1f474, 0x1f486, 0x1f48c, 0x1f498, 0x1f4b0, 0x1f4be, 0x1f4ce, 0x1f4dc,
0x1f4e2, 0x1f4e4, 0x1f4e8, 0x1f4f6, 0x1f506, 0x1f50c, 0x1f518, 0x1f530, 0x1f53e, 0x1f560, 0x1f57c, 0x1f58e,
0x1f59c, 0x1f5b8, 0x1f5c2, 0x1f5c4, 0x1f5c8, 0x1f5d0, 0x1f5de, 0x1f5e6, 0x1f5ec, 0x1f5fa, 0x1f60a, 0x1f612,
0x1f614, 0x1f622, 0x1f624, 0x1f628, 0x1f636, 0x1f642, 0x1f644, 0x1f648, 0x1f650, 0x1f65e, 0x1f666, 0x1f67a,
0x1f682, 0x1f684, 0x1f688, 0x1f690, 0x1f69e, 0x1f6a0, 0x1f6bc, 0x1f6cc, 0x1f6f2, 0x1f6f4, 0x1f71a, 0x1f72e,
0x1f732, 0x1f734, 0x1f74e, 0x1f75c, 0x1f762, 0x1f764, 0x1f768, 0x1f776, 0x1f796, 0x1f7a6, 0x1f7ac, 0x1f7ba,
0x1f7d2, 0x1f7d4, 0x1f89a, 0x1f8ae, 0x1f8b2, 0x1f8b4, 0x1f8d6, 0x1f8ea, 0x1f91a, 0x1f92e, 0x1f932, 0x1f934,
0x1f94e, 0x1f95c, 0x1f962, 0x1f964, 0x1f968, 0x1f976, 0x1f996, 0x1f9a6, 0x1f9ac, 0x1f9ba, 0x1f9ca, 0x1f9d2,
0x1f9d4, 0x1fa1a, 0x1fa2e, 0x1fa32, 0x1fa34, 0x1fa4e, 0x1fa5c, 0x1fa62, 0x1fa64, 0x1fa68, 0x1fa76, 0x1fa8e,
0x1fa9c, 0x1fab8, 0x1fac2, 0x1fac4, 0x1fac8, 0x1fad0, 0x1fade, 0x1fae6, 0x1faec, 0x1fb16, 0x1fb26, 0x1fb2c,
0x1fb3a, 0x1fb46, 0x1fb4c, 0x1fb58, 0x1fb6e, 0x1fb72, 0x1fb74, 0x1fb8a, 0x1fb92, 0x1fb94, 0x1fba2, 0x1fba4,
0x1fba8, 0x1fbb6, 0x1fbda};
/// <summary>
/// This table contains to codewords for all symbols.
/// </summary>
private static readonly int[] CODEWORD_TABLE = {
2627, 1819, 2622, 2621, 1813, 1812, 2729, 2724, 2723, 2779, 2774, 2773, 902, 896, 908, 868, 865, 861, 859, 2511,
873, 871, 1780, 835, 2493, 825, 2491, 842, 837, 844, 1764, 1762, 811, 810, 809, 2483, 807, 2482, 806, 2480, 815,
814, 813, 812, 2484, 817, 816, 1745, 1744, 1742, 1746, 2655, 2637, 2635, 2626, 2625, 2623, 2628, 1820, 2752,
2739, 2737, 2728, 2727, 2725, 2730, 2785, 2783, 2778, 2777, 2775, 2780, 787, 781, 747, 739, 736, 2413, 754, 752,
1719, 692, 689, 681, 2371, 678, 2369, 700, 697, 694, 703, 1688, 1686, 642, 638, 2343, 631, 2341, 627, 2338, 651,
646, 643, 2345, 654, 652, 1652, 1650, 1647, 1654, 601, 599, 2322, 596, 2321, 594, 2319, 2317, 611, 610, 608, 606,
2324, 603, 2323, 615, 614, 612, 1617, 1616, 1614, 1612, 616, 1619, 1618, 2575, 2538, 2536, 905, 901, 898, 909,
2509, 2507, 2504, 870, 867, 864, 860, 2512, 875, 872, 1781, 2490, 2489, 2487, 2485, 1748, 836, 834, 832, 830,
2494, 827, 2492, 843, 841, 839, 845, 1765, 1763, 2701, 2676, 2674, 2653, 2648, 2656, 2634, 2633, 2631, 2629,
1821, 2638, 2636, 2770, 2763, 2761, 2750, 2745, 2753, 2736, 2735, 2733, 2731, 1848, 2740, 2738, 2786, 2784, 591,
588, 576, 569, 566, 2296, 1590, 537, 534, 526, 2276, 522, 2274, 545, 542, 539, 548, 1572, 1570, 481, 2245, 466,
2242, 462, 2239, 492, 485, 482, 2249, 496, 494, 1534, 1531, 1528, 1538, 413, 2196, 406, 2191, 2188, 425, 419,
2202, 415, 2199, 432, 430, 427, 1472, 1467, 1464, 433, 1476, 1474, 368, 367, 2160, 365, 2159, 362, 2157, 2155,
2152, 378, 377, 375, 2166, 372, 2165, 369, 2162, 383, 381, 379, 2168, 1419, 1418, 1416, 1414, 385, 1411, 384,
1423, 1422, 1420, 1424, 2461, 802, 2441, 2439, 790, 786, 783, 794, 2409, 2406, 2403, 750, 742, 738, 2414, 756,
753, 1720, 2367, 2365, 2362, 2359, 1663, 693, 691, 684, 2373, 680, 2370, 702, 699, 696, 704, 1690, 1687, 2337,
2336, 2334, 2332, 1624, 2329, 1622, 640, 637, 2344, 634, 2342, 630, 2340, 650, 648, 645, 2346, 655, 653, 1653,
1651, 1649, 1655, 2612, 2597, 2595, 2571, 2568, 2565, 2576, 2534, 2529, 2526, 1787, 2540, 2537, 907, 904, 900,
910, 2503, 2502, 2500, 2498, 1768, 2495, 1767, 2510, 2508, 2506, 869, 866, 863, 2513, 876, 874, 1782, 2720, 2713,
2711, 2697, 2694, 2691, 2702, 2672, 2670, 2664, 1828, 2678, 2675, 2647, 2646, 2644, 2642, 1823, 2639, 1822, 2654,
2652, 2650, 2657, 2771, 1855, 2765, 2762, 1850, 1849, 2751, 2749, 2747, 2754, 353, 2148, 344, 342, 336, 2142,
332, 2140, 345, 1375, 1373, 306, 2130, 299, 2128, 295, 2125, 319, 314, 311, 2132, 1354, 1352, 1349, 1356, 262,
257, 2101, 253, 2096, 2093, 274, 273, 267, 2107, 263, 2104, 280, 278, 275, 1316, 1311, 1308, 1320, 1318, 2052,
202, 2050, 2044, 2040, 219, 2063, 212, 2060, 208, 2055, 224, 221, 2066, 1260, 1258, 1252, 231, 1248, 229, 1266,
1264, 1261, 1268, 155, 1998, 153, 1996, 1994, 1991, 1988, 165, 164, 2007, 162, 2006, 159, 2003, 2000, 172, 171,
169, 2012, 166, 2010, 1186, 1184, 1182, 1179, 175, 1176, 173, 1192, 1191, 1189, 1187, 176, 1194, 1193, 2313,
2307, 2305, 592, 589, 2294, 2292, 2289, 578, 572, 568, 2297, 580, 1591, 2272, 2267, 2264, 1547, 538, 536, 529,
2278, 525, 2275, 547, 544, 541, 1574, 1571, 2237, 2235, 2229, 1493, 2225, 1489, 478, 2247, 470, 2244, 465, 2241,
493, 488, 484, 2250, 498, 495, 1536, 1533, 1530, 1539, 2187, 2186, 2184, 2182, 1432, 2179, 1430, 2176, 1427, 414,
412, 2197, 409, 2195, 405, 2193, 2190, 426, 424, 421, 2203, 418, 2201, 431, 429, 1473, 1471, 1469, 1466, 434,
1477, 1475, 2478, 2472, 2470, 2459, 2457, 2454, 2462, 803, 2437, 2432, 2429, 1726, 2443, 2440, 792, 789, 785,
2401, 2399, 2393, 1702, 2389, 1699, 2411, 2408, 2405, 745, 741, 2415, 758, 755, 1721, 2358, 2357, 2355, 2353,
1661, 2350, 1660, 2347, 1657, 2368, 2366, 2364, 2361, 1666, 690, 687, 2374, 683, 2372, 701, 698, 705, 1691, 1689,
2619, 2617, 2610, 2608, 2605, 2613, 2593, 2588, 2585, 1803, 2599, 2596, 2563, 2561, 2555, 1797, 2551, 1795, 2573,
2570, 2567, 2577, 2525, 2524, 2522, 2520, 1786, 2517, 1785, 2514, 1783, 2535, 2533, 2531, 2528, 1788, 2541, 2539,
906, 903, 911, 2721, 1844, 2715, 2712, 1838, 1836, 2699, 2696, 2693, 2703, 1827, 1826, 1824, 2673, 2671, 2669,
2666, 1829, 2679, 2677, 1858, 1857, 2772, 1854, 1853, 1851, 1856, 2766, 2764, 143, 1987, 139, 1986, 135, 133,
131, 1984, 128, 1983, 125, 1981, 138, 137, 136, 1985, 1133, 1132, 1130, 112, 110, 1974, 107, 1973, 104, 1971,
1969, 122, 121, 119, 117, 1977, 114, 1976, 124, 1115, 1114, 1112, 1110, 1117, 1116, 84, 83, 1953, 81, 1952, 78,
1950, 1948, 1945, 94, 93, 91, 1959, 88, 1958, 85, 1955, 99, 97, 95, 1961, 1086, 1085, 1083, 1081, 1078, 100,
1090, 1089, 1087, 1091, 49, 47, 1917, 44, 1915, 1913, 1910, 1907, 59, 1926, 56, 1925, 53, 1922, 1919, 66, 64,
1931, 61, 1929, 1042, 1040, 1038, 71, 1035, 70, 1032, 68, 1048, 1047, 1045, 1043, 1050, 1049, 12, 10, 1869, 1867,
1864, 1861, 21, 1880, 19, 1877, 1874, 1871, 28, 1888, 25, 1886, 22, 1883, 982, 980, 977, 974, 32, 30, 991, 989,
987, 984, 34, 995, 994, 992, 2151, 2150, 2147, 2146, 2144, 356, 355, 354, 2149, 2139, 2138, 2136, 2134, 1359,
343, 341, 338, 2143, 335, 2141, 348, 347, 346, 1376, 1374, 2124, 2123, 2121, 2119, 1326, 2116, 1324, 310, 308,
305, 2131, 302, 2129, 298, 2127, 320, 318, 316, 313, 2133, 322, 321, 1355, 1353, 1351, 1357, 2092, 2091, 2089,
2087, 1276, 2084, 1274, 2081, 1271, 259, 2102, 256, 2100, 252, 2098, 2095, 272, 269, 2108, 266, 2106, 281, 279,
277, 1317, 1315, 1313, 1310, 282, 1321, 1319, 2039, 2037, 2035, 2032, 1203, 2029, 1200, 1197, 207, 2053, 205,
2051, 201, 2049, 2046, 2043, 220, 218, 2064, 215, 2062, 211, 2059, 228, 226, 223, 2069, 1259, 1257, 1254, 232,
1251, 230, 1267, 1265, 1263, 2316, 2315, 2312, 2311, 2309, 2314, 2304, 2303, 2301, 2299, 1593, 2308, 2306, 590,
2288, 2287, 2285, 2283, 1578, 2280, 1577, 2295, 2293, 2291, 579, 577, 574, 571, 2298, 582, 581, 1592, 2263, 2262,
2260, 2258, 1545, 2255, 1544, 2252, 1541, 2273, 2271, 2269, 2266, 1550, 535, 532, 2279, 528, 2277, 546, 543, 549,
1575, 1573, 2224, 2222, 2220, 1486, 2217, 1485, 2214, 1482, 1479, 2238, 2236, 2234, 2231, 1496, 2228, 1492, 480,
477, 2248, 473, 2246, 469, 2243, 490, 487, 2251, 497, 1537, 1535, 1532, 2477, 2476, 2474, 2479, 2469, 2468, 2466,
2464, 1730, 2473, 2471, 2453, 2452, 2450, 2448, 1729, 2445, 1728, 2460, 2458, 2456, 2463, 805, 804, 2428, 2427,
2425, 2423, 1725, 2420, 1724, 2417, 1722, 2438, 2436, 2434, 2431, 1727, 2444, 2442, 793, 791, 788, 795, 2388,
2386, 2384, 1697, 2381, 1696, 2378, 1694, 1692, 2402, 2400, 2398, 2395, 1703, 2392, 1701, 2412, 2410, 2407, 751,
748, 744, 2416, 759, 757, 1807, 2620, 2618, 1806, 1805, 2611, 2609, 2607, 2614, 1802, 1801, 1799, 2594, 2592,
2590, 2587, 1804, 2600, 2598, 1794, 1793, 1791, 1789, 2564, 2562, 2560, 2557, 1798, 2554, 1796, 2574, 2572, 2569,
2578, 1847, 1846, 2722, 1843, 1842, 1840, 1845, 2716, 2714, 1835, 1834, 1832, 1830, 1839, 1837, 2700, 2698, 2695,
2704, 1817, 1811, 1810, 897, 862, 1777, 829, 826, 838, 1760, 1758, 808, 2481, 1741, 1740, 1738, 1743, 2624, 1818,
2726, 2776, 782, 740, 737, 1715, 686, 679, 695, 1682, 1680, 639, 628, 2339, 647, 644, 1645, 1643, 1640, 1648,
602, 600, 597, 595, 2320, 593, 2318, 609, 607, 604, 1611, 1610, 1608, 1606, 613, 1615, 1613, 2328, 926, 924, 892,
886, 899, 857, 850, 2505, 1778, 824, 823, 821, 819, 2488, 818, 2486, 833, 831, 828, 840, 1761, 1759, 2649, 2632,
2630, 2746, 2734, 2732, 2782, 2781, 570, 567, 1587, 531, 527, 523, 540, 1566, 1564, 476, 467, 463, 2240, 486,
483, 1524, 1521, 1518, 1529, 411, 403, 2192, 399, 2189, 423, 416, 1462, 1457, 1454, 428, 1468, 1465, 2210, 366,
363, 2158, 360, 2156, 357, 2153, 376, 373, 370, 2163, 1410, 1409, 1407, 1405, 382, 1402, 380, 1417, 1415, 1412,
1421, 2175, 2174, 777, 774, 771, 784, 732, 725, 722, 2404, 743, 1716, 676, 674, 668, 2363, 665, 2360, 685, 1684,
1681, 626, 624, 622, 2335, 620, 2333, 617, 2330, 641, 635, 649, 1646, 1644, 1642, 2566, 928, 925, 2530, 2527,
894, 891, 888, 2501, 2499, 2496, 858, 856, 854, 851, 1779, 2692, 2668, 2665, 2645, 2643, 2640, 2651, 2768, 2759,
2757, 2744, 2743, 2741, 2748, 352, 1382, 340, 337, 333, 1371, 1369, 307, 300, 296, 2126, 315, 312, 1347, 1342,
1350, 261, 258, 250, 2097, 246, 2094, 271, 268, 264, 1306, 1301, 1298, 276, 1312, 1309, 2115, 203, 2048, 195,
2045, 191, 2041, 213, 209, 2056, 1246, 1244, 1238, 225, 1234, 222, 1256, 1253, 1249, 1262, 2080, 2079, 154, 1997,
150, 1995, 147, 1992, 1989, 163, 160, 2004, 156, 2001, 1175, 1174, 1172, 1170, 1167, 170, 1164, 167, 1185, 1183,
1180, 1177, 174, 1190, 1188, 2025, 2024, 2022, 587, 586, 564, 559, 556, 2290, 573, 1588, 520, 518, 512, 2268,
508, 2265, 530, 1568, 1565, 461, 457, 2233, 450, 2230, 446, 2226, 479, 471, 489, 1526, 1523, 1520, 397, 395,
2185, 392, 2183, 389, 2180, 2177, 410, 2194, 402, 422, 1463, 1461, 1459, 1456, 1470, 2455, 799, 2433, 2430, 779,
776, 773, 2397, 2394, 2390, 734, 728, 724, 746, 1717, 2356, 2354, 2351, 2348, 1658, 677, 675, 673, 670, 667, 688,
1685, 1683, 2606, 2589, 2586, 2559, 2556, 2552, 927, 2523, 2521, 2518, 2515, 1784, 2532, 895, 893, 890, 2718,
2709, 2707, 2689, 2687, 2684, 2663, 2662, 2660, 2658, 1825, 2667, 2769, 1852, 2760, 2758, 142, 141, 1139, 1138,
134, 132, 129, 126, 1982, 1129, 1128, 1126, 1131, 113, 111, 108, 105, 1972, 101, 1970, 120, 118, 115, 1109, 1108,
1106, 1104, 123, 1113, 1111, 82, 79, 1951, 75, 1949, 72, 1946, 92, 89, 86, 1956, 1077, 1076, 1074, 1072, 98,
1069, 96, 1084, 1082, 1079, 1088, 1968, 1967, 48, 45, 1916, 42, 1914, 39, 1911, 1908, 60, 57, 54, 1923, 50, 1920,
1031, 1030, 1028, 1026, 67, 1023, 65, 1020, 62, 1041, 1039, 1036, 1033, 69, 1046, 1044, 1944, 1943, 1941, 11, 9,
1868, 7, 1865, 1862, 1859, 20, 1878, 16, 1875, 13, 1872, 970, 968, 966, 963, 29, 960, 26, 23, 983, 981, 978, 975,
33, 971, 31, 990, 988, 985, 1906, 1904, 1902, 993, 351, 2145, 1383, 331, 330, 328, 326, 2137, 323, 2135, 339,
1372, 1370, 294, 293, 291, 289, 2122, 286, 2120, 283, 2117, 309, 303, 317, 1348, 1346, 1344, 245, 244, 242, 2090,
239, 2088, 236, 2085, 2082, 260, 2099, 249, 270, 1307, 1305, 1303, 1300, 1314, 189, 2038, 186, 2036, 183, 2033,
2030, 2026, 206, 198, 2047, 194, 216, 1247, 1245, 1243, 1240, 227, 1237, 1255, 2310, 2302, 2300, 2286, 2284,
2281, 565, 563, 561, 558, 575, 1589, 2261, 2259, 2256, 2253, 1542, 521, 519, 517, 514, 2270, 511, 533, 1569,
1567, 2223, 2221, 2218, 2215, 1483, 2211, 1480, 459, 456, 453, 2232, 449, 474, 491, 1527, 1525, 1522, 2475, 2467,
2465, 2451, 2449, 2446, 801, 800, 2426, 2424, 2421, 2418, 1723, 2435, 780, 778, 775, 2387, 2385, 2382, 2379,
1695, 2375, 1693, 2396, 735, 733, 730, 727, 749, 1718, 2616, 2615, 2604, 2603, 2601, 2584, 2583, 2581, 2579,
1800, 2591, 2550, 2549, 2547, 2545, 1792, 2542, 1790, 2558, 929, 2719, 1841, 2710, 2708, 1833, 1831, 2690, 2688,
2686, 1815, 1809, 1808, 1774, 1756, 1754, 1737, 1736, 1734, 1739, 1816, 1711, 1676, 1674, 633, 629, 1638, 1636,
1633, 1641, 598, 1605, 1604, 1602, 1600, 605, 1609, 1607, 2327, 887, 853, 1775, 822, 820, 1757, 1755, 1584, 524,
1560, 1558, 468, 464, 1514, 1511, 1508, 1519, 408, 404, 400, 1452, 1447, 1444, 417, 1458, 1455, 2208, 364, 361,
358, 2154, 1401, 1400, 1398, 1396, 374, 1393, 371, 1408, 1406, 1403, 1413, 2173, 2172, 772, 726, 723, 1712, 672,
669, 666, 682, 1678, 1675, 625, 623, 621, 618, 2331, 636, 632, 1639, 1637, 1635, 920, 918, 884, 880, 889, 849,
848, 847, 846, 2497, 855, 852, 1776, 2641, 2742, 2787, 1380, 334, 1367, 1365, 301, 297, 1340, 1338, 1335, 1343,
255, 251, 247, 1296, 1291, 1288, 265, 1302, 1299, 2113, 204, 196, 192, 2042, 1232, 1230, 1224, 214, 1220, 210,
1242, 1239, 1235, 1250, 2077, 2075, 151, 148, 1993, 144, 1990, 1163, 1162, 1160, 1158, 1155, 161, 1152, 157,
1173, 1171, 1168, 1165, 168, 1181, 1178, 2021, 2020, 2018, 2023, 585, 560, 557, 1585, 516, 509, 1562, 1559, 458,
447, 2227, 472, 1516, 1513, 1510, 398, 396, 393, 390, 2181, 386, 2178, 407, 1453, 1451, 1449, 1446, 420, 1460,
2209, 769, 764, 720, 712, 2391, 729, 1713, 664, 663, 661, 659, 2352, 656, 2349, 671, 1679, 1677, 2553, 922, 919,
2519, 2516, 885, 883, 881, 2685, 2661, 2659, 2767, 2756, 2755, 140, 1137, 1136, 130, 127, 1125, 1124, 1122, 1127,
109, 106, 102, 1103, 1102, 1100, 1098, 116, 1107, 1105, 1980, 80, 76, 73, 1947, 1068, 1067, 1065, 1063, 90, 1060,
87, 1075, 1073, 1070, 1080, 1966, 1965, 46, 43, 40, 1912, 36, 1909, 1019, 1018, 1016, 1014, 58, 1011, 55, 1008,
51, 1029, 1027, 1024, 1021, 63, 1037, 1034, 1940, 1939, 1937, 1942, 8, 1866, 4, 1863, 1, 1860, 956, 954, 952,
949, 946, 17, 14, 969, 967, 964, 961, 27, 957, 24, 979, 976, 972, 1901, 1900, 1898, 1896, 986, 1905, 1903, 350,
349, 1381, 329, 327, 324, 1368, 1366, 292, 290, 287, 284, 2118, 304, 1341, 1339, 1337, 1345, 243, 240, 237, 2086,
233, 2083, 254, 1297, 1295, 1293, 1290, 1304, 2114, 190, 187, 184, 2034, 180, 2031, 177, 2027, 199, 1233, 1231,
1229, 1226, 217, 1223, 1241, 2078, 2076, 584, 555, 554, 552, 550, 2282, 562, 1586, 507, 506, 504, 502, 2257, 499,
2254, 515, 1563, 1561, 445, 443, 441, 2219, 438, 2216, 435, 2212, 460, 454, 475, 1517, 1515, 1512, 2447, 798,
797, 2422, 2419, 770, 768, 766, 2383, 2380, 2376, 721, 719, 717, 714, 731, 1714, 2602, 2582, 2580, 2548, 2546,
2543, 923, 921, 2717, 2706, 2705, 2683, 2682, 2680, 1771, 1752, 1750, 1733, 1732, 1731, 1735, 1814, 1707, 1670,
1668, 1631, 1629, 1626, 1634, 1599, 1598, 1596, 1594, 1603, 1601, 2326, 1772, 1753, 1751, 1581, 1554, 1552, 1504,
1501, 1498, 1509, 1442, 1437, 1434, 401, 1448, 1445, 2206, 1392, 1391, 1389, 1387, 1384, 359, 1399, 1397, 1394,
1404, 2171, 2170, 1708, 1672, 1669, 619, 1632, 1630, 1628, 1773, 1378, 1363, 1361, 1333, 1328, 1336, 1286, 1281,
1278, 248, 1292, 1289, 2111, 1218, 1216, 1210, 197, 1206, 193, 1228, 1225, 1221, 1236, 2073, 2071, 1151, 1150,
1148, 1146, 152, 1143, 149, 1140, 145, 1161, 1159, 1156, 1153, 158, 1169, 1166, 2017, 2016, 2014, 2019, 1582,
510, 1556, 1553, 452, 448, 1506, 1500, 394, 391, 387, 1443, 1441, 1439, 1436, 1450, 2207, 765, 716, 713, 1709,
662, 660, 657, 1673, 1671, 916, 914, 879, 878, 877, 882, 1135, 1134, 1121, 1120, 1118, 1123, 1097, 1096, 1094,
1092, 103, 1101, 1099, 1979, 1059, 1058, 1056, 1054, 77, 1051, 74, 1066, 1064, 1061, 1071, 1964, 1963, 1007,
1006, 1004, 1002, 999, 41, 996, 37, 1017, 1015, 1012, 1009, 52, 1025, 1022, 1936, 1935, 1933, 1938, 942, 940,
938, 935, 932, 5, 2, 955, 953, 950, 947, 18, 943, 15, 965, 962, 958, 1895, 1894, 1892, 1890, 973, 1899, 1897,
1379, 325, 1364, 1362, 288, 285, 1334, 1332, 1330, 241, 238, 234, 1287, 1285, 1283, 1280, 1294, 2112, 188, 185,
181, 178, 2028, 1219, 1217, 1215, 1212, 200, 1209, 1227, 2074, 2072, 583, 553, 551, 1583, 505, 503, 500, 513,
1557, 1555, 444, 442, 439, 436, 2213, 455, 451, 1507, 1505, 1502, 796, 763, 762, 760, 767, 711, 710, 708, 706,
2377, 718, 715, 1710, 2544, 917, 915, 2681, 1627, 1597, 1595, 2325, 1769, 1749, 1747, 1499, 1438, 1435, 2204,
1390, 1388, 1385, 1395, 2169, 2167, 1704, 1665, 1662, 1625, 1623, 1620, 1770, 1329, 1282, 1279, 2109, 1214, 1207,
1222, 2068, 2065, 1149, 1147, 1144, 1141, 146, 1157, 1154, 2013, 2011, 2008, 2015, 1579, 1549, 1546, 1495, 1487,
1433, 1431, 1428, 1425, 388, 1440, 2205, 1705, 658, 1667, 1664, 1119, 1095, 1093, 1978, 1057, 1055, 1052, 1062,
1962, 1960, 1005, 1003, 1000, 997, 38, 1013, 1010, 1932, 1930, 1927, 1934, 941, 939, 936, 933, 6, 930, 3, 951,
948, 944, 1889, 1887, 1884, 1881, 959, 1893, 1891, 35, 1377, 1360, 1358, 1327, 1325, 1322, 1331, 1277, 1275,
1272, 1269, 235, 1284, 2110, 1205, 1204, 1201, 1198, 182, 1195, 179, 1213, 2070, 2067, 1580, 501, 1551, 1548,
440, 437, 1497, 1494, 1490, 1503, 761, 709, 707, 1706, 913, 912, 2198, 1386, 2164, 2161, 1621, 1766, 2103, 1208,
2058, 2054, 1145, 1142, 2005, 2002, 1999, 2009, 1488, 1429, 1426, 2200, 1698, 1659, 1656, 1975, 1053, 1957, 1954,
1001, 998, 1924, 1921, 1918, 1928, 937, 934, 931, 1879, 1876, 1873, 1870, 945, 1885, 1882, 1323, 1273, 1270,
2105, 1202, 1199, 1196, 1211, 2061, 2057, 1576, 1543, 1540, 1484, 1481, 1478, 1491, 1700};
}
}

View file

@ -1,5 +1,3 @@
using System.Collections.Generic;
/*
* Copyright 2009 ZXing authors
*
@ -16,214 +14,353 @@ using System.Collections.Generic;
* limitations under the License.
*/
namespace com.google.zxing.pdf417
using System.Collections.Generic;
using ZXing.Common;
using ZXing.PDF417.Internal;
using System;
namespace ZXing.PDF417
{
/// <summary>
/// This implementation can detect and decode PDF417 codes in an image.
///
/// <author>SITA Lab (kevin.osullivan@sita.aero)</author>
/// <author>Guenther Grau (java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
/// </summary>
public sealed class PDF417Reader : Reader
{
/// <summary>
/// NO_POINTS found.
/// </summary>
private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0];
using BarcodeFormat = com.google.zxing.BarcodeFormat;
using BinaryBitmap = com.google.zxing.BinaryBitmap;
using ChecksumException = com.google.zxing.ChecksumException;
using DecodeHintType = com.google.zxing.DecodeHintType;
using FormatException = com.google.zxing.FormatException;
using NotFoundException = com.google.zxing.NotFoundException;
using Reader = com.google.zxing.Reader;
using Result = com.google.zxing.Result;
using ResultPoint = com.google.zxing.ResultPoint;
using BitMatrix = com.google.zxing.common.BitMatrix;
using DecoderResult = com.google.zxing.common.DecoderResult;
using DetectorResult = com.google.zxing.common.DetectorResult;
using Decoder = com.google.zxing.pdf417.decoder.Decoder;
using Detector = com.google.zxing.pdf417.detector.Detector;
/// <summary>
/// Locates and decodes a PDF417 code in an image.
///
/// <returns>a String representing the content encoded by the PDF417 code</returns>
/// <exception cref="FormatException">if a PDF417 cannot be decoded</exception>
/// </summary>
public Result Decode(BinaryBitmap image)
{
return Decode(image, null);
}
/// <summary>
/// Locates and decodes a barcode in some format within an image. This method also accepts
/// hints, each possibly associated to some data, which may help the implementation decode.
/// **Note** this will return the FIRST barcode discovered if there are many.
/// </summary>
/// <param name="image">image of barcode to decode</param>
/// <param name="hints">passed as a <see cref="IDictionary{TKey, TValue}"/> from <see cref="DecodeHintType"/>
/// to arbitrary data. The
/// meaning of the data depends upon the hint type. The implementation may or may not do
/// anything with these hints.</param>
/// <returns>
/// String which the barcode encodes
/// </returns>
public Result Decode(BinaryBitmap image,
IDictionary<DecodeHintType, object> hints)
{
Result[] results = Decode(image, hints, false);
if (results.Length == 0)
{
return null;
} else
{
return results[0]; // First barcode discovered.
}
}
/// <summary>
/// This implementation can detect and decode PDF417 codes in an image.
///
/// @author SITA Lab (kevin.osullivan@sita.aero)
/// </summary>
public sealed class PDF417Reader : com.google.zxing.Reader
{
/// <summary>
/// Locates and decodes Multiple PDF417 codes in an image.
///
/// <returns>an array of Strings representing the content encoded by the PDF417 codes</returns>
/// </summary>
public Result[] DecodeMultiple(BinaryBitmap image)
{
return DecodeMultiple(image, null);
}
/// <summary>
/// Locates and decodes multiple barcodes in some format within an image. This method also accepts
/// hints, each possibly associated to some data, which may help the implementation decode.
/// </summary>
/// <param name="image">image of barcode to decode</param>
/// <param name="hints">passed as a <see cref="IDictionary{TKey, TValue}"/> from <see cref="DecodeHintType"/>
/// to arbitrary data. The
/// meaning of the data depends upon the hint type. The implementation may or may not do
/// anything with these hints.</param>
/// <returns>
/// String which the barcodes encode
/// </returns>
public Result[] DecodeMultiple(BinaryBitmap image,
IDictionary<DecodeHintType, object> hints)
{
return Decode(image, hints, true);
}
private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0];
/// <summary>
/// Decode the specified image, with the hints and optionally multiple barcodes.
/// Based on Owen's Comments in <see cref="ZXing.ReaderException"/>, this method has been modified to continue silently
/// if a barcode was not decoded where it was detected instead of throwing a new exception object.
/// </summary>
/// <param name="image">Image.</param>
/// <param name="hints">Hints.</param>
/// <param name="multiple">If set to <c>true</c> multiple.</param>
private static Result[] Decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints, bool multiple)
{
List<Result> results = new List<Result>();
PDF417DetectorResult detectorResult = Detector.Detect(image, hints, multiple);
foreach (ResultPoint[] points in detectorResult.Points)
{
DecoderResult decoderResult = PDF417ScanningDecoder.Decode(detectorResult.Bits, points[4], points[5],
points[6], points[7], GetMinCodewordWidth(points), GetMaxCodewordWidth(points));
if (decoderResult == null)
{
// See comments re: Exceptions above
// continue;
throw ReaderException.Instance;
}
System.Diagnostics.Debug.WriteLine("Result " + points.ToString() + " > " + decoderResult.Text + " " + decoderResult.RawBytes);
Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.PDF_417);
result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.ECLevel);
PDF417ResultMetadata pdf417ResultMetadata = (PDF417ResultMetadata)decoderResult.Other;
if (pdf417ResultMetadata != null)
{
result.putMetadata(ResultMetadataType.PDF417_EXTRA_METADATA, pdf417ResultMetadata);
}
results.Add(result);
}
return results.ToArray();
}
private readonly Decoder decoder = new Decoder();
/// <summary>
/// Gets the maximum width of the barcode
/// </summary>
/// <returns>The max width.</returns>
/// <param name="p1">P1.</param>
/// <param name="p2">P2.</param>
private static int GetMaxWidth(ResultPoint p1, ResultPoint p2)
{
if (p1 == null || p2 == null)
{
return 0;
}
return (int)Math.Abs(p1.X - p2.X);
}
/// <summary>
/// Locates and decodes a PDF417 code in an image.
/// </summary>
/// <returns> a String representing the content encoded by the PDF417 code </returns>
/// <exception cref="NotFoundException"> if a PDF417 code cannot be found, </exception>
/// <exception cref="FormatException"> if a PDF417 cannot be decoded </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException, com.google.zxing.ChecksumException
public Result decode(BinaryBitmap image)
{
return decode(image, null);
}
/// <summary>
/// Gets the minimum width of the barcode
/// </summary>
/// <returns>The minimum width.</returns>
/// <param name="p1">P1.</param>
/// <param name="p2">P2.</param>
private static int GetMinWidth(ResultPoint p1, ResultPoint p2)
{
if (p1 == null || p2 == null)
{
return int.MaxValue;
}
return (int)Math.Abs(p1.X - p2.X);
}
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image, java.util.Map<com.google.zxing.DecodeHintType,?> hints) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException, com.google.zxing.ChecksumException
public Result decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints)
{
DecoderResult decoderResult;
ResultPoint[] points;
if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE))
{
BitMatrix bits = extractPureBits(image.BlackMatrix);
decoderResult = decoder.decode(bits);
points = NO_POINTS;
}
else
{
DetectorResult detectorResult = (new Detector(image)).detect();
decoderResult = decoder.decode(detectorResult.Bits);
points = detectorResult.Points;
}
return new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.PDF_417);
}
/// <summary>
/// Gets the maximum width of the codeword.
/// </summary>
/// <returns>The max codeword width.</returns>
/// <param name="p">P.</param>
private static int GetMaxCodewordWidth(ResultPoint[] p)
{
return Math.Max(
Math.Max(GetMaxWidth(p[0], p[4]), GetMaxWidth(p[6], p[2]) * PDF417Common.MODULES_IN_CODEWORD /
PDF417Common.MODULES_IN_STOP_PATTERN),
Math.Max(GetMaxWidth(p[1], p[5]), GetMaxWidth(p[7], p[3]) * PDF417Common.MODULES_IN_CODEWORD /
PDF417Common.MODULES_IN_STOP_PATTERN));
}
public void reset()
{
// do nothing
}
/// <summary>
/// Gets the minimum width of the codeword.
/// </summary>
/// <returns>The minimum codeword width.</returns>
/// <param name="p">P.</param>
private static int GetMinCodewordWidth(ResultPoint[] p)
{
return Math.Min(
Math.Min(GetMinWidth(p[0], p[4]), GetMinWidth(p[6], p[2]) * PDF417Common.MODULES_IN_CODEWORD /
PDF417Common.MODULES_IN_STOP_PATTERN),
Math.Min(GetMinWidth(p[1], p[5]), GetMinWidth(p[7], p[3]) * PDF417Common.MODULES_IN_CODEWORD /
PDF417Common.MODULES_IN_STOP_PATTERN));
}
/// <summary>
/// This method detects a code in a "pure" image -- that is, pure monochrome image
/// which contains only an unrotated, unskewed, image of a code, with some white border
/// around it. This is a specialized method that works exceptionally fast in this special
/// case.
/// </summary>
/// <seealso cref= com.google.zxing.qrcode.QRCodeReader#extractPureBits(BitMatrix) </seealso>
/// <seealso cref= com.google.zxing.datamatrix.DataMatrixReader#extractPureBits(BitMatrix) </seealso>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: private static com.google.zxing.common.BitMatrix extractPureBits(com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException
private static BitMatrix extractPureBits(BitMatrix image)
{
/// <summary>
/// Resets any internal state the implementation has after a decode, to prepare it
/// for reuse.
/// </summary>
public void Reset()
{
// do nothing
}
int[] leftTopBlack = image.TopLeftOnBit;
int[] rightBottomBlack = image.BottomRightOnBit;
if (leftTopBlack == null || rightBottomBlack == null)
{
throw NotFoundException.NotFoundInstance;
}
/// <summary>
/// This method detects a code in a "pure" image -- that is, pure monochrome image
/// which contains only an unrotated, unskewed, image of a code, with some white border
/// around it. This is a specialized method that works exceptionally fast in this special
/// case.
///
/// <see cref="QrCode.QRCodeReader.extractPureBits(BitMatrix)" />
/// <see cref="Datamatrix.DataMatrixReader.extractPureBits(BitMatrix)" />
/// </summary>
private static BitMatrix ExtractPureBits(BitMatrix image)
{
int moduleSize = getModuleSize(leftTopBlack, image);
int[] leftTopBlack = image.getTopLeftOnBit();
int[] rightBottomBlack = image.getBottomRightOnBit();
if (leftTopBlack == null || rightBottomBlack == null)
{
return null;
}
int top = leftTopBlack[1];
int bottom = rightBottomBlack[1];
int left = findPatternStart(leftTopBlack[0], top, image);
int right = findPatternEnd(leftTopBlack[0], top, image);
int moduleSize;
if (!PDF417Reader.ModuleSize(leftTopBlack, image, out moduleSize))
return null;
int matrixWidth = (right - left + 1) / moduleSize;
int matrixHeight = (bottom - top + 1) / moduleSize;
if (matrixWidth <= 0 || matrixHeight <= 0)
{
throw NotFoundException.NotFoundInstance;
}
int top = leftTopBlack[1];
int bottom = rightBottomBlack[1];
int left;
if (!FindPatternStart(leftTopBlack[0], top, image, out left))
return null;
int right;
if (!FindPatternEnd(leftTopBlack[0], top, image, out right))
return null;
// Push in the "border" by half the module width so that we start
// sampling in the middle of the module. Just in case the image is a
// little off, this will help recover.
int nudge = moduleSize >> 1;
top += nudge;
left += nudge;
int matrixWidth = (right - left + 1) / moduleSize;
int matrixHeight = (bottom - top + 1) / moduleSize;
if (matrixWidth <= 0 || matrixHeight <= 0)
{
return null;
}
// Now just read off the bits
BitMatrix bits = new BitMatrix(matrixWidth, matrixHeight);
for (int y = 0; y < matrixHeight; y++)
{
int iOffset = top + y * moduleSize;
for (int x = 0; x < matrixWidth; x++)
{
if (image.get(left + x * moduleSize, iOffset))
{
bits.set(x, y);
}
}
}
return bits;
}
// Push in the "border" by half the module width so that we start
// sampling in the middle of the module. Just in case the image is a
// little off, this will help recover.
int nudge = moduleSize >> 1;
top += nudge;
left += nudge;
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: private static int moduleSize(int[] leftTopBlack, com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException
private static int getModuleSize(int[] leftTopBlack, BitMatrix image)
{
int x = leftTopBlack[0];
int y = leftTopBlack[1];
int width = image.Width;
while (x < width && image.get(x, y))
{
x++;
}
if (x == width)
{
throw NotFoundException.NotFoundInstance;
}
// Now just read off the bits
var bits = new BitMatrix(matrixWidth, matrixHeight);
for (int y = 0; y < matrixHeight; y++)
{
int iOffset = top + y * moduleSize;
for (int x = 0; x < matrixWidth; x++)
{
if (image[left + x * moduleSize, iOffset])
{
bits[x, y] = true;
}
}
}
return bits;
}
int moduleSize = (int)((uint)(x - leftTopBlack[0]) >> 3); // We've crossed left first bar, which is 8x
if (moduleSize == 0)
{
throw NotFoundException.NotFoundInstance;
}
/// <summary>
/// Computes the Module Size
/// </summary>
/// <returns><c>true</c>, if size was moduled, <c>false</c> otherwise.</returns>
/// <param name="leftTopBlack">Left top black.</param>
/// <param name="image">Image.</param>
/// <param name="msize">Msize.</param>
private static bool ModuleSize(int[] leftTopBlack, BitMatrix image, out int msize)
{
int x = leftTopBlack[0];
int y = leftTopBlack[1];
int width = image.Width;
while (x < width && image[x, y])
{
x++;
}
if (x == width)
{
msize = 0;
return false;
}
return moduleSize;
}
msize = (int)((uint)(x - leftTopBlack[0]) >> 3); // (x - leftTopBlack[0]) >>> 3// We've crossed left first bar, which is 8x
if (msize == 0)
{
return false;
}
return true;
}
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: private static int findPatternStart(int x, int y, com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException
private static int findPatternStart(int x, int y, BitMatrix image)
{
int width = image.Width;
int start = x;
// start should be on black
int transitions = 0;
bool black = true;
while (start < width - 1 && transitions < 8)
{
start++;
bool newBlack = image.get(start, y);
if (black != newBlack)
{
transitions++;
}
black = newBlack;
}
if (start == width - 1)
{
throw NotFoundException.NotFoundInstance;
}
return start;
}
/// <summary>
/// Finds the pattern start.
/// </summary>
/// <returns><c>true</c>, if pattern start was found, <c>false</c> otherwise.</returns>
/// <param name="x">The x coordinate.</param>
/// <param name="y">The y coordinate.</param>
/// <param name="image">Image.</param>
/// <param name="start">Start.</param>
private static bool FindPatternStart(int x, int y, BitMatrix image, out int start)
{
int width = image.Width;
start = x;
// start should be on black
int transitions = 0;
bool black = true;
while (start < width - 1 && transitions < 8)
{
start++;
bool newBlack = image[start, y];
if (black != newBlack)
{
transitions++;
}
black = newBlack;
}
if (start == width - 1)
{
return false;
}
return true;
}
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: private static int findPatternEnd(int x, int y, com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException
private static int findPatternEnd(int x, int y, BitMatrix image)
{
int width = image.Width;
int end = width - 1;
// end should be on black
while (end > x && !image.get(end, y))
{
end--;
}
int transitions = 0;
bool black = true;
while (end > x && transitions < 9)
{
end--;
bool newBlack = image.get(end, y);
if (black != newBlack)
{
transitions++;
}
black = newBlack;
}
if (end == x)
{
throw NotFoundException.NotFoundInstance;
}
return end;
}
}
}
/// <summary>
/// Finds the pattern end.
/// </summary>
/// <returns><c>true</c>, if pattern end was found, <c>false</c> otherwise.</returns>
/// <param name="x">The x coordinate.</param>
/// <param name="y">The y coordinate.</param>
/// <param name="image">Image.</param>
/// <param name="end">End.</param>
private static bool FindPatternEnd(int x, int y, BitMatrix image, out int end)
{
int width = image.Width;
end = width - 1;
// end should be on black
while (end > x && !image[end, y])
{
end--;
}
int transitions = 0;
bool black = true;
while (end > x && transitions < 9)
{
end--;
bool newBlack = image[end, y];
if (black != newBlack)
{
transitions++;
}
black = newBlack;
}
if (end == x)
{
return false;
}
return true;
}
}
}

View file

@ -0,0 +1,33 @@
// /*
// * Copyright 2009 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.PDF417
{
/// <summary>
/// PDF 417 result meta data. Skipped private backing stores.
/// <author>Guenther Grau (Java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
/// </summary>
public sealed class PDF417ResultMetadata
{
public int SegmentIndex { get; set; }
public string FileId { get; set; }
public int[] OptionalData { get; set; }
public bool IsLastSegment { get; set; }
}
}

View file

@ -0,0 +1,192 @@
/*
* Copyright 2012 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;
using ZXing.PDF417.Internal;
namespace ZXing.PDF417
{
/// <summary>
/// <author>Jacob Haynes</author>
/// <author>qwandor@google.com (Andrew Walbran)</author>
/// </summary>
public sealed class PDF417Writer : Writer
{
/// <summary>
/// </summary>
/// <param name="contents">The contents to encode in the barcode</param>
/// <param name="format">The barcode format to generate</param>
/// <param name="width">The preferred width in pixels</param>
/// <param name="height">The preferred height in pixels</param>
/// <param name="hints">Additional parameters to supply to the encoder</param>
/// <returns>
/// The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white)
/// </returns>
public BitMatrix encode(String contents,
BarcodeFormat format,
int width,
int height,
IDictionary<EncodeHintType, object> hints)
{
if (format != BarcodeFormat.PDF_417)
{
throw new ArgumentException("Can only encode PDF_417, but got " + format);
}
var encoder = new Internal.PDF417();
if (hints != null)
{
if (hints.ContainsKey(EncodeHintType.PDF417_COMPACT))
{
encoder.setCompact((Boolean)hints[EncodeHintType.PDF417_COMPACT]);
}
if (hints.ContainsKey(EncodeHintType.PDF417_COMPACTION))
{
encoder.setCompaction((Compaction)hints[EncodeHintType.PDF417_COMPACTION]);
}
if (hints.ContainsKey(EncodeHintType.PDF417_DIMENSIONS))
{
Dimensions dimensions = (Dimensions)hints[EncodeHintType.PDF417_DIMENSIONS];
encoder.setDimensions(dimensions.MaxCols,
dimensions.MinCols,
dimensions.MaxRows,
dimensions.MinRows);
}
}
return bitMatrixFromEncoder(encoder, contents, width, height);
}
/// <summary>
/// Encode a barcode using the default settings.
/// </summary>
/// <param name="contents">The contents to encode in the barcode</param>
/// <param name="format">The barcode format to generate</param>
/// <param name="width">The preferred width in pixels</param>
/// <param name="height">The preferred height in pixels</param>
/// <returns>
/// The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white)
/// </returns>
public BitMatrix encode(String contents,
BarcodeFormat format,
int width,
int height)
{
return encode(contents, format, width, height, null);
}
/// <summary>
/// Takes encoder, accounts for width/height, and retrieves bit matrix
/// </summary>
private static BitMatrix bitMatrixFromEncoder(Internal.PDF417 encoder,
String contents,
int width,
int height)
{
const int errorCorrectionLevel = 2;
encoder.generateBarcodeLogic(contents, errorCorrectionLevel);
const int lineThickness = 2;
const int aspectRatio = 4;
sbyte[][] originalScale = encoder.BarcodeMatrix.getScaledMatrix(lineThickness, aspectRatio * lineThickness);
bool rotated = false;
if ((height > width) ^ (originalScale[0].Length < originalScale.Length))
{
originalScale = rotateArray(originalScale);
rotated = true;
}
int scaleX = width / originalScale[0].Length;
int scaleY = height / originalScale.Length;
int scale;
if (scaleX < scaleY)
{
scale = scaleX;
}
else
{
scale = scaleY;
}
if (scale > 1)
{
sbyte[][] scaledMatrix =
encoder.BarcodeMatrix.getScaledMatrix(scale * lineThickness, scale * aspectRatio * lineThickness);
if (rotated)
{
scaledMatrix = rotateArray(scaledMatrix);
}
return bitMatrixFrombitArray(scaledMatrix);
}
return bitMatrixFrombitArray(originalScale);
}
/// <summary>
/// This takes an array holding the values of the PDF 417
///
/// <param name="input">a byte array of information with 0 is black, and 1 is white</param>
/// <returns>BitMatrix of the input</returns>
/// </summary>
private static BitMatrix bitMatrixFrombitArray(sbyte[][] input)
{
// Creates a small whitespace border around the barcode
const int whiteSpace = 30;
// Creates the bitmatrix with extra space for whitespace
var output = new BitMatrix(input[0].Length + 2 * whiteSpace, input.Length + 2 * whiteSpace);
var yOutput = output.Height - whiteSpace;
for (int y = 0; y < input.Length; y++)
{
for (int x = 0; x < input[0].Length; x++)
{
// Zero is white in the bytematrix
if (input[y][x] == 1)
{
output[x + whiteSpace, yOutput] = true;
}
}
yOutput--;
}
return output;
}
/// <summary>
/// Takes and rotates the it 90 degrees
/// </summary>
private static sbyte[][] rotateArray(sbyte[][] bitarray)
{
sbyte[][] temp = new sbyte[bitarray[0].Length][];
for (int idx = 0; idx < bitarray[0].Length; idx++)
temp[idx] = new sbyte[bitarray.Length];
for (int ii = 0; ii < bitarray.Length; ii++)
{
// This makes the direction consistent on screen when rotating the
// screen;
int inverseii = bitarray.Length - ii - 1;
for (int jj = 0; jj < bitarray[0].Length; jj++)
{
temp[jj][inverseii] = bitarray[ii][jj];
}
}
return temp;
}
}
}

View file

@ -0,0 +1,45 @@
// /*
// * Copyright 2009 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.PDF417.Internal
{
/// <summary>
/// Metadata about a PDF417 Barcode
/// </summary>
/// <author>Guenther Grau (Java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
public sealed class BarcodeMetadata
{
public int ColumnCount { get; private set; }
public int ErrorCorrectionLevel { get; private set; }
public int RowCountUpper { get; private set; }
public int RowCountLower { get; private set; }
public int RowCount { get; private set; }
public BarcodeMetadata(int columnCount, int rowCountUpperPart, int rowCountLowerPart, int errorCorrectionLevel)
{
this.ColumnCount = columnCount;
this.ErrorCorrectionLevel = errorCorrectionLevel;
this.RowCountUpper = rowCountUpperPart;
this.RowCountLower = rowCountLowerPart;
this.RowCount = rowCountLowerPart + rowCountUpperPart;
}
}
}

View file

@ -0,0 +1,97 @@
// /*
// * Copyright 2009 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.Linq;
using System.Collections.Generic;
using ZXing.Common;
namespace ZXing.PDF417.Internal
{
/// <summary>
/// A Barcode Value for the PDF417 barcode.
/// The scanner will iterate through the bitmatrix,
/// and given the different methods or iterations
/// will increment a given barcode value's confidence.
///
/// When done, this will return the values of highest confidence.
/// </summary>
/// <author>Guenther Grau (Java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
public sealed class BarcodeValue
{
private readonly IDictionary<int, int> values = new Dictionary<int, int>();
/// <summary>
/// Incremenets the Confidence for a given value. (Adds an occurance of a value)
///
/// </summary>
/// <param name="value">Value.</param>
public void SetValue(int barcodeValue)
{
// ints can't be null in C# - check for containmentship
if (values.ContainsKey(barcodeValue))
{
int confidence = values[barcodeValue];
confidence ++;
values[barcodeValue] = confidence;
} else
{
values.Add(barcodeValue, 1);
}
}
/// <summary>
/// Determines the maximum occurrence of a set value and returns all values which were set with this occurrence.
/// </summary>
/// <returns>an array of int, containing the values with the highest occurrence, or null, if no value was set.</returns>
public int[] GetValue()
{
// if (confidence == null || confidence.Count == 0)
// {
// return new int[0];
// }
// int max = (from pair in confidence select pair.Value).Max();
// return (from pair in confidence where pair.Value == max select pair.Key).ToArray();
int maxConfidence = -1;
List<int> result = new List<int>();
foreach (var entry in values)
{
if (entry.Value > maxConfidence)
{
maxConfidence = entry.Value;
result.Clear();
result.Add(entry.Key);
} else if (entry.Value == maxConfidence)
{
result.Add(entry.Key);
}
}
return result.ToArray();
}
/// <summary>
/// Returns the confience value for a given barcode value
/// </summary>
/// <param name="barcodeValue">Barcode value.</param>
public int GetConfidence(int barcodeValue)
{
return values.ContainsKey(barcodeValue) ? values[barcodeValue] : 0;
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,198 @@
// /*
// * Copyright 2009 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.PDF417.Internal
{
/// <summary>
/// A Bounding Box helper class
/// </summary>
/// <author>Guenther Grau (Java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
public sealed class BoundingBox
{
private BitMatrix Image { get; set; }
public ResultPoint TopLeft { get; private set; }
public ResultPoint TopRight { get; private set; }
public ResultPoint BottomLeft { get; private set; }
public ResultPoint BottomRight { get; private set; }
public int MinX { get; private set; }
public int MaxX { get; private set; }
public int MinY { get; private set; }
public int MaxY { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="ZXing.PDF417.Internal.BoundingBox"/> class.
/// Will throw an exception if the corner points don't match up correctly
/// </summary>
/// <param name="image">Image.</param>
/// <param name="topLeft">Top left.</param>
/// <param name="topRight">Top right.</param>
/// <param name="bottomLeft">Bottom left.</param>
/// <param name="bottomRight">Bottom right.</param>
public BoundingBox(BitMatrix image,
ResultPoint topLeft,
ResultPoint bottomLeft,
ResultPoint topRight,
ResultPoint bottomRight)
{
if ((topLeft == null && topRight == null) ||
(bottomLeft == null && bottomRight == null) ||
(topLeft != null && bottomLeft == null) ||
(topRight != null && bottomRight == null))
{
throw ReaderException.Instance;
}
this.Image = image;
this.TopLeft = topLeft;
this.TopRight = topRight;
this.BottomLeft = bottomLeft;
this.BottomRight = bottomRight;
CalculateMinMaxValues();
}
/// <summary>
/// Initializes a new instance of the <see cref="ZXing.PDF417.Internal.BoundingBox"/> class.
/// </summary>
/// <param name="box">Box.</param>
public BoundingBox(BoundingBox box) : this (box.Image, box.TopLeft,box.BottomLeft, box.TopRight, box.BottomRight)
{
}
/// <summary>
/// Calculates the minimum and maximum X & Y values based on the corner points.
/// </summary>
private void CalculateMinMaxValues()
{
// Constructor ensures that either Left or Right is not null
if (TopLeft == null)
{
TopLeft = new ResultPoint(0, TopRight.Y);
BottomLeft = new ResultPoint(0, BottomRight.Y);
} else if (TopRight == null)
{
TopRight = new ResultPoint(Image.Width - 1, TopLeft.Y);
BottomRight = new ResultPoint(Image.Width - 1, TopLeft.Y);
}
MinX = (int)Math.Min(TopLeft.X, BottomLeft.X);
MinY = (int)Math.Min(TopLeft.Y, TopRight.Y);
MaxX = (int)Math.Max(TopRight.X, BottomRight.X);
MaxY = (int)Math.Max(BottomLeft.Y, BottomRight.Y); // Y points down
}
/// <summary>
/// If we adjust the width, set a new right corner coordinate and recalculate
/// </summary>
/// <param name="topRight">Top right.</param>
internal void SetTopRight(ResultPoint topRight)
{
this.TopRight = topRight;
CalculateMinMaxValues();
}
/// <summary>
/// If we adjust the width, set a new right corner coordinate and recalculate
/// </summary>
/// <param name="bottomRight">Bottom right.</param>
internal void SetBottomRight(ResultPoint bottomRight)
{
this.BottomRight = bottomRight;
CalculateMinMaxValues();
}
/// <summary>
/// Merge two Bounding Boxes, getting the left corners of left, and the right corners of right
/// (Images should be the same)
/// </summary>
/// <param name="left">Left.</param>
/// <param name="right">Right.</param>
internal static BoundingBox Merge(BoundingBox left, BoundingBox right)
{
if (left == null)
return right;
if (right == null)
return left;
return new BoundingBox(left.Image, left.TopLeft, left.BottomLeft, right.TopRight, right.BottomRight);
}
/// <summary>
/// Adds the missing rows.
/// </summary>
/// <returns>The missing rows.</returns>
/// <param name="missingStartRows">Missing start rows.</param>
/// <param name="missingEndRows">Missing end rows.</param>
/// <param name="isLeft">If set to <c>true</c> is left.</param>
public BoundingBox AddMissingRows(int missingStartRows, int missingEndRows, bool isLeft)
{
ResultPoint newTopLeft = TopLeft;
ResultPoint newBottomLeft = BottomLeft;
ResultPoint newTopRight = TopRight;
ResultPoint newBottomRight = BottomRight;
if (missingStartRows > 0)
{
ResultPoint top = isLeft ? TopLeft : TopRight;
int newMinY = (int)top.Y - missingStartRows;
if (newMinY < 0)
{
newMinY = 0;
}
// TODO use existing points to better interpolate the new x positions
ResultPoint newTop = new ResultPoint(top.X, newMinY);
if (isLeft)
{
newTopLeft = newTop;
} else
{
newTopRight = newTop;
}
}
if (missingEndRows > 0)
{
ResultPoint bottom = isLeft ? BottomLeft : BottomRight;
int newMaxY = (int)bottom.Y + missingEndRows;
if (newMaxY >= Image.Height)
{
newMaxY = Image.Height - 1;
}
// TODO use existing points to better interpolate the new x positions
ResultPoint newBottom = new ResultPoint(bottom.X, newMaxY);
if (isLeft)
{
newBottomLeft = newBottom;
} else
{
newBottomRight = newBottom;
}
}
CalculateMinMaxValues();
return new BoundingBox(Image, newTopLeft, newBottomLeft, newTopRight, newBottomRight);
}
}
}

View file

@ -0,0 +1,108 @@
// /*
// * Copyright 2009 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.PDF417.Internal
{
/// <summary>
/// A Codeword in the PDF417 barcode
/// </summary>
/// <author>Guenther Grau (Java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
public sealed class Codeword
{
/// <summary>
/// Default value for the RowNumber (-1 being an invalid real number)
/// </summary>
private static readonly int BARCODE_ROW_UNKNOWN = -1;
public int StartX { get; private set; }
public int EndX { get; private set; }
public int Bucket { get; private set; }
public int Value { get; private set; }
public int RowNumber { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ZXing.PDF417.Internal.Codeword"/> class.
/// </summary>
/// <param name="startX">Start x.</param>
/// <param name="endX">End x.</param>
/// <param name="bucket">Bucket.</param>
/// <param name="value">Value.</param>
public Codeword(int startX, int endX, int bucket, int value)
{
this.StartX = startX;
this.EndX = endX;
this.Bucket = bucket;
this.Value = value;
this.RowNumber = BARCODE_ROW_UNKNOWN;
}
/// <summary>
/// Gets the width.
/// </summary>
/// <value>The width.</value>
public int Width
{
get
{
return EndX - StartX;
}
}
/// <summary>
/// Gets a value indicating whether this instance has valid row number.
/// </summary>
/// <value><c>true</c> if this instance has valid row number; otherwise, <c>false</c>.</value>
public bool HasValidRowNumber
{
get
{
return IsValidRowNumber(RowNumber);
}
}
/// <summary>
/// Determines whether this instance is valid row number the specified rowNumber.
/// </summary>
/// <returns><c>true</c> if this instance is valid row number the specified rowNumber; otherwise, <c>false</c>.</returns>
/// <param name="rowNumber">Row number.</param>
public bool IsValidRowNumber(int rowNumber)
{
return rowNumber != BARCODE_ROW_UNKNOWN && Bucket == (rowNumber % 3) * 3;
}
/// <summary>
/// Sets the row number as the row's indicator column.
/// </summary>
public void SetRowNumberAsRowIndicatorColumn()
{
this.RowNumber = (Value / 30) * 3 + Bucket / 3;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.Codeword"/>.
/// </summary>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.Codeword"/>.</returns>
public override string ToString()
{
return RowNumber + "|" + Value;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,374 @@
// /*
// * Copyright 2009 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 System.Text;
namespace ZXing.PDF417.Internal
{
/// <summary>
///
/// </summary>
/// <author>Guenther Grau (Java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
public class DetectionResult
{
private static readonly int ADJUST_ROW_NUMBER_SKIP = 2;
public BarcodeMetadata Metadata { get; private set; }
public DetectionResultColumn[] DetectionResultColumns { get; set; }
public BoundingBox Box { get; set; }
public int ColumnCount { get; private set; }
public int RowCount { get { return Metadata.RowCount; } }
public int ErrorCorrectionLevel { get { return Metadata.ErrorCorrectionLevel; } }
public DetectionResult(BarcodeMetadata metadata, BoundingBox box)
{
this.Metadata = metadata;
this.Box = box;
this.ColumnCount = metadata.ColumnCount;
this.DetectionResultColumns = new DetectionResultColumn[ColumnCount + 2];
}
/// <summary>
/// Returns the DetectionResult Columns. This does a fair bit of calculation, so call it sparingly.
/// </summary>
/// <returns>The detection result columns.</returns>
public DetectionResultColumn[] GetDetectionResultColumns()
{
AdjustIndicatorColumnRowNumbers(DetectionResultColumns[0]);
AdjustIndicatorColumnRowNumbers(DetectionResultColumns[ColumnCount + 1]);
int unadjustedCodewordCount = PDF417Common.MAX_CODEWORDS_IN_BARCODE;
int previousUnadjustedCount;
do
{
previousUnadjustedCount = unadjustedCodewordCount;
unadjustedCodewordCount = AdjustRowNumbers();
} while (unadjustedCodewordCount > 0 && unadjustedCodewordCount < previousUnadjustedCount);
return DetectionResultColumns;
}
/// <summary>
/// Adjusts the indicator column row numbers.
/// </summary>
/// <param name="detectionResultColumn">Detection result column.</param>
private void AdjustIndicatorColumnRowNumbers(DetectionResultColumn detectionResultColumn)
{
if (detectionResultColumn != null)
{
((DetectionResultRowIndicatorColumn)detectionResultColumn)
.AdjustCompleteIndicatorColumnRowNumbers(Metadata);
}
}
/// <summary>
/// return number of codewords which don't have a valid row number. Note that the count is not accurate as codewords .
/// will be counted several times. It just serves as an indicator to see when we can stop adjusting row numbers
/// </summary>
/// <returns>The row numbers.</returns>
private int AdjustRowNumbers()
{
// TODO ensure that no detected codewords with unknown row number are left
// we should be able to estimate the row height and use it as a hint for the row number
// we should also fill the rows top to bottom and bottom to top
int unadjustedCount = AdjustRowNumbersByRow();
if (unadjustedCount == 0)
{
return 0;
}
for (int barcodeColumn = 1; barcodeColumn < ColumnCount + 1; barcodeColumn++)
{
Codeword[] codewords = DetectionResultColumns[barcodeColumn].Codewords;
for (int codewordsRow = 0; codewordsRow < codewords.Length; codewordsRow++)
{
if (codewords[codewordsRow] == null)
{
continue;
}
if (!codewords[codewordsRow].HasValidRowNumber)
{
AdjustRowNumbers(barcodeColumn, codewordsRow, codewords);
}
}
}
return unadjustedCount;
}
/// <summary>
/// Adjusts the row numbers by row.
/// </summary>
/// <returns>The row numbers by row.</returns>
private int AdjustRowNumbersByRow()
{
AdjustRowNumbersFromBothRI(); // RI = RowIndicators
// TODO we should only do full row adjustments if row numbers of left and right row indicator column match.
// Maybe it's even better to calculated the height (in codeword rows) and divide it by the number of barcode
// rows. This, together with the LRI and RRI row numbers should allow us to get a good estimate where a row
// number starts and ends.
int unadjustedCount = AdjustRowNumbersFromLRI();
return unadjustedCount + AdjustRowNumbersFromRRI();
}
/// <summary>
/// Adjusts the row numbers from both Row Indicators
/// </summary>
/// <returns> zero </returns>
private int AdjustRowNumbersFromBothRI()
{
if (DetectionResultColumns[0] == null || DetectionResultColumns[ColumnCount + 1] == null)
{
return 0;
}
Codeword[] LRIcodewords = DetectionResultColumns[0].Codewords;
Codeword[] RRIcodewords = DetectionResultColumns[ColumnCount + 1].Codewords;
for (int codewordsRow = 0; codewordsRow < LRIcodewords.Length; codewordsRow++)
{
if (LRIcodewords[codewordsRow] != null &&
RRIcodewords[codewordsRow] != null &&
LRIcodewords[codewordsRow].RowNumber == RRIcodewords[codewordsRow].RowNumber)
{
for (int barcodeColumn = 1; barcodeColumn <= ColumnCount; barcodeColumn++)
{
Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow];
if (codeword == null)
{
continue;
}
codeword.RowNumber = LRIcodewords[codewordsRow].RowNumber;
if (!codeword.HasValidRowNumber)
{
// LOG.info("Removing codeword with invalid row number, cw[" + codewordsRow + "][" + barcodeColumn + "]");
DetectionResultColumns[barcodeColumn].Codewords[codewordsRow] = null;
}
}
}
}
return 0;
}
/// <summary>
/// Adjusts the row numbers from Right Row Indicator.
/// </summary>
/// <returns>The unadjusted row count.</returns>
private int AdjustRowNumbersFromRRI()
{
if (DetectionResultColumns[ColumnCount + 1] == null)
{
return 0;
}
int unadjustedCount = 0;
Codeword[] codewords = DetectionResultColumns[ColumnCount + 1].Codewords;
for (int codewordsRow = 0; codewordsRow < codewords.Length; codewordsRow++)
{
if (codewords[codewordsRow] == null)
{
continue;
}
int rowIndicatorRowNumber = codewords[codewordsRow].RowNumber;
int invalidRowCounts = 0;
for (int barcodeColumn = ColumnCount + 1; barcodeColumn > 0 && invalidRowCounts < ADJUST_ROW_NUMBER_SKIP; barcodeColumn--)
{
Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow];
if (codeword != null)
{
invalidRowCounts = AdjustRowNumberIfValid(rowIndicatorRowNumber, invalidRowCounts, codeword);
if (!codeword.HasValidRowNumber)
{
unadjustedCount++;
}
}
}
}
return unadjustedCount;
}
/// <summary>
/// Adjusts the row numbers from Left Row Indicator.
/// </summary>
/// <returns> Unadjusted row Count.</returns>
private int AdjustRowNumbersFromLRI()
{
if (DetectionResultColumns[0] == null)
{
return 0;
}
int unadjustedCount = 0;
Codeword[] codewords = DetectionResultColumns[0].Codewords;
for (int codewordsRow = 0; codewordsRow < codewords.Length; codewordsRow++)
{
if (codewords[codewordsRow] == null)
{
continue;
}
int rowIndicatorRowNumber = codewords[codewordsRow].RowNumber;
int invalidRowCounts = 0;
for (int barcodeColumn = 1; barcodeColumn < ColumnCount + 1 && invalidRowCounts < ADJUST_ROW_NUMBER_SKIP; barcodeColumn++)
{
Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow];
if (codeword != null)
{
invalidRowCounts = AdjustRowNumberIfValid(rowIndicatorRowNumber, invalidRowCounts, codeword);
if (!codeword.HasValidRowNumber)
{
unadjustedCount++;
}
}
}
}
return unadjustedCount;
}
/// <summary>
/// Adjusts the row number if valid.
/// </summary>
/// <returns>The invalid rows</returns>
/// <param name="rowIndicatorRowNumber">Row indicator row number.</param>
/// <param name="invalidRowCounts">Invalid row counts.</param>
/// <param name="codeword">Codeword.</param>
private static int AdjustRowNumberIfValid(int rowIndicatorRowNumber, int invalidRowCounts, Codeword codeword)
{
if (codeword == null)
{
return invalidRowCounts;
}
if (!codeword.HasValidRowNumber)
{
if (codeword.IsValidRowNumber(rowIndicatorRowNumber))
{
codeword.RowNumber = rowIndicatorRowNumber;
invalidRowCounts = 0;
} else
{
++invalidRowCounts;
}
}
return invalidRowCounts;
}
/// <summary>
/// Adjusts the row numbers.
/// </summary>
/// <param name="barcodeColumn">Barcode column.</param>
/// <param name="codewordsRow">Codewords row.</param>
/// <param name="codewords">Codewords.</param>
private void AdjustRowNumbers(int barcodeColumn, int codewordsRow, Codeword[] codewords)
{
Codeword codeword = codewords[codewordsRow];
Codeword[] previousColumnCodewords = DetectionResultColumns[barcodeColumn - 1].Codewords;
Codeword[] nextColumnCodewords = previousColumnCodewords;
if (DetectionResultColumns[barcodeColumn + 1] != null)
{
nextColumnCodewords = DetectionResultColumns[barcodeColumn + 1].Codewords;
}
Codeword[] otherCodewords = new Codeword[14];
otherCodewords[2] = previousColumnCodewords[codewordsRow];
otherCodewords[3] = nextColumnCodewords[codewordsRow];
if (codewordsRow > 0)
{
otherCodewords[0] = codewords[codewordsRow - 1];
otherCodewords[4] = previousColumnCodewords[codewordsRow - 1];
otherCodewords[5] = nextColumnCodewords[codewordsRow - 1];
}
if (codewordsRow > 1)
{
otherCodewords[8] = codewords[codewordsRow - 2];
otherCodewords[10] = previousColumnCodewords[codewordsRow - 2];
otherCodewords[11] = nextColumnCodewords[codewordsRow - 2];
}
if (codewordsRow < codewords.Length - 1)
{
otherCodewords[1] = codewords[codewordsRow + 1];
otherCodewords[6] = previousColumnCodewords[codewordsRow + 1];
otherCodewords[7] = nextColumnCodewords[codewordsRow + 1];
}
if (codewordsRow < codewords.Length - 2)
{
otherCodewords[9] = codewords[codewordsRow + 2];
otherCodewords[12] = previousColumnCodewords[codewordsRow + 2];
otherCodewords[13] = nextColumnCodewords[codewordsRow + 2];
}
foreach (Codeword otherCodeword in otherCodewords)
{
if (AdjustRowNumber(codeword, otherCodeword))
{
return;
}
}
}
/// <summary>
/// Adjusts the row number.
/// </summary>
/// <returns><c>true</c>, if row number was adjusted, <c>false</c> otherwise.</returns>
/// <param name="codeword">Codeword.</param>
/// <param name="otherCodeword">Other codeword.</param>
private static bool AdjustRowNumber(Codeword codeword, Codeword otherCodeword)
{
if (otherCodeword == null)
{
return false;
}
if (otherCodeword.HasValidRowNumber && otherCodeword.Bucket == codeword.Bucket)
{
codeword.RowNumber = otherCodeword.RowNumber;
return true;
}
return false;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.DetectionResult"/>.
/// </summary>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.DetectionResult"/>.</returns>
public override string ToString()
{
StringBuilder formatter = new StringBuilder();
DetectionResultColumn rowIndicatorColumn = DetectionResultColumns[0];
if (rowIndicatorColumn == null)
{
rowIndicatorColumn = DetectionResultColumns[ColumnCount + 1];
}
for (int codewordsRow = 0; codewordsRow < rowIndicatorColumn.Codewords.Length; codewordsRow++)
{
formatter.AppendFormat("CW {0,3}:", codewordsRow);
for (int barcodeColumn = 0; barcodeColumn < ColumnCount + 2; barcodeColumn++)
{
if (DetectionResultColumns[barcodeColumn] == null)
{
formatter.Append(" | ");
continue;
}
Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow];
if (codeword == null)
{
formatter.Append(" | ");
continue;
}
formatter.AppendFormat(" {0,3}|{1,3}", codeword.RowNumber, codeword.Value);
}
formatter.Append("\n");
}
return formatter.ToString();
}
}
}

View file

@ -0,0 +1,161 @@
// /*
// * Copyright 2009 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.Linq;
using ZXing.Common;
using System.Text;
namespace ZXing.PDF417.Internal
{
/// <summary>
/// Represents a Column in the Detection Result
/// </summary>
/// <author>Guenther Grau (Java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
public class DetectionResultColumn
{
/// <summary>
/// The maximum distance to search in the codeword array in both the positive and negative directions
/// </summary>
private static readonly int MAX_NEARBY_DISTANCE = 5;
/// <summary>
/// The Bounding Box around the column (in the BitMatrix)
/// </summary>
/// <value>The box.</value>
public BoundingBox Box { get; private set; }
/// <summary>
/// The Codewords the Box encodes for, offset by the Box minY.
/// Remember to Access this ONLY through GetCodeword(imageRow) if you're accessing it in that manner.
/// </summary>
/// <value>The codewords.</value>
public Codeword[] Codewords { get; set; } // TODO convert this to a dictionary? Dictionary<imageRow, Codeword> ??
/// <summary>
/// Initializes a new instance of the <see cref="ZXing.PDF417.Internal.DetectionResultColumn"/> class.
/// </summary>
/// <param name="box">The Bounding Box around the column (in the BitMatrix)</param>
public DetectionResultColumn(BoundingBox box)
{
this.Box = new BoundingBox(box);
this.Codewords = new Codeword[Box.MaxY - Box.MinY + 1];
}
/// <summary>
/// Converts the Image's Row to the index in the Codewords array
/// </summary>
/// <returns>The Codeword Index.</returns>
/// <param name="imageRow">Image row.</param>
public int IndexForRow(int imageRow)
{
return imageRow - Box.MinY;
}
/// <summary>
/// Converts the Codeword array index into a Row in the Image (BitMatrix)
/// </summary>
/// <returns>The Image Row.</returns>
/// <param name="codewordIndex">Codeword index.</param>
public int RowForIndex(int codewordIndex)
{
return Box.MinY + codewordIndex;
}
/// <summary>
/// Gets the codeword for a given row
/// </summary>
/// <returns>The codeword.</returns>
/// <param name="imageRow">Image row.</param>
public Codeword GetCodeword(int imageRow)
{
return Codewords[IndexForRow(imageRow)];
}
/// <summary>
/// Gets the codeword closest to the specified row in the image
/// </summary>
/// <param name="imageRow">Image row.</param>
public Codeword GetCodewordNearby(int imageRow)
{
Codeword codeword = GetCodeword(imageRow);
if (codeword == null)
{
int index = IndexForRow(imageRow);
// TODO verify that this LINQ works the same?
// Codeword nearestCW = Codewords[(from n in Codewords.Select((cw, n) => n) where Codewords[n] != null select n).Aggregate((x, y) => Math.Abs(x - index) > Math.Abs(y - index) ? x : y)];
int nearby;
for (int i = 1; i < MAX_NEARBY_DISTANCE; i++)
{
nearby = index - i;
if (nearby >= 0)
{
codeword = Codewords[nearby];
if (codeword != null)
break;
}
nearby = index + i;
if (nearby < Codewords.Length)
{
codeword = Codewords[nearby];
break;
}
}
}
return codeword;
}
/// <summary>
/// Sets the codeword for an image row
/// </summary>
/// <param name="imageRow">Image row.</param>
/// <param name="codeword">Codeword.</param>
public void SetCodeword(int imageRow, Codeword codeword)
{
Codewords[IndexForRow(imageRow)] = codeword;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.DetectionResultColumn"/>.
/// </summary>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.DetectionResultColumn"/>.</returns>
public override string ToString()
{
StringBuilder builder = new StringBuilder();
int row = 0;
foreach (var cw in Codewords)
{
if (cw == null)
{
builder.AppendFormat("{0,3}: | \n", row++);
} else
{
builder.AppendFormat("{0,3}: {1,3}|{2,3}\n", row++, cw.RowNumber, cw.Value);
}
}
return builder.ToString();
// return "Valid Codewords: " + (from cw in Codewords where cw != null select cw).Count().ToString();
}
}
}

View file

@ -0,0 +1,362 @@
// /*
// * Copyright 2009 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.Linq;
using ZXing.Common;
namespace ZXing.PDF417.Internal
{
/// <summary>
/// Represents a Column in the Detection Result
/// </summary>
/// <author>Guenther Grau (Java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
public sealed class DetectionResultRowIndicatorColumn : DetectionResultColumn
{
/// <summary>
/// Gets or sets a value indicating whether this instance is the left indicator
/// </summary>
/// <value><c>true</c> if this instance is left; otherwise, <c>false</c>.</value>
public bool IsLeft { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ZXing.PDF417.Internal.DetectionResultRowIndicatorColumn"/> class.
/// </summary>
/// <param name="box">Box.</param>
/// <param name="isLeft">If set to <c>true</c> is left.</param>
public DetectionResultRowIndicatorColumn(BoundingBox box, bool isLeft) : base (box)
{
this.IsLeft = isLeft;
this.Codewords = new Codeword[box.MaxY - box.MinY + 1];
}
/// <summary>
/// Sets the Row Numbers as Inidicator Columns
/// </summary>
public void SetRowNumbers()
{
foreach (var cw in Codewords)
{
if (cw != null)
{
cw.SetRowNumberAsRowIndicatorColumn();
}
}
// (from item in items where item != null do item.SomeMethod())
}
/// <summary>
/// TODO implement properly
/// TODO maybe we should add missing codewords to store the correct row number to make
/// finding row numbers for other columns easier
/// use row height count to make detection of invalid row numbers more reliable
/// </summary>
/// <returns>The indicator column row numbers.</returns>
/// <param name="metadata">Metadata.</param>
public int AdjustCompleteIndicatorColumnRowNumbers(BarcodeMetadata metadata)
{
SetRowNumbers(); // Assign this as an indicator column
RemoveIncorrectCodewords(metadata);
ResultPoint top = IsLeft ? Box.TopLeft : Box.TopRight;
ResultPoint bottom = IsLeft ? Box.BottomLeft : Box.BottomRight;
int firstRow = IndexForRow((int)top.Y);
int lastRow = IndexForRow((int)bottom.Y);
// We need to be careful using the average row height.
// Barcode could be skewed so that we have smaller and taller rows
float averageRowHeight = (lastRow - firstRow) / (float)metadata.RowCount;
// initialize loop
int barcodeRow = -1;
int maxRowHeight = 1;
int currentRowHeight = 0;
for (int codewordRow = firstRow; codewordRow < lastRow; codewordRow++)
{
var codeword = Codewords[codewordRow];
if (codeword == null)
{
continue;
}
// float expectedRowNumber = (codewordsRow - firstRow) / averageRowHeight;
// if (Math.abs(codeword.getRowNumber() - expectedRowNumber) > 2) {
// SimpleLog.log(LEVEL.WARNING,
// "Removing codeword, rowNumberSkew too high, codeword[" + codewordsRow + "]: Expected Row: " +
// expectedRowNumber + ", RealRow: " + codeword.getRowNumber() + ", value: " + codeword.getValue());
// codewords[codewordsRow] = null;
// }
int rowDifference = codeword.RowNumber - barcodeRow;
// TODO improve handling with case where first row indicator doesn't start with 0
if (rowDifference == 0)
{
currentRowHeight ++;
} else if (rowDifference == 1)
{
maxRowHeight = Math.Max(maxRowHeight, currentRowHeight);
currentRowHeight = 1;
barcodeRow = codeword.RowNumber;
} else if (rowDifference < 0)
{
Codewords[codewordRow] = null;
} else if (codeword.RowNumber >= metadata.RowCount)
{
Codewords[codewordRow] = null;
} else if (rowDifference > codewordRow)
{
Codewords[codewordRow] = null;
} else
{
int checkedRows;
if (maxRowHeight > 2)
{
checkedRows = (maxRowHeight - 2) * rowDifference;
} else
{
checkedRows = rowDifference;
}
bool closePreviousCodewordFound = checkedRows > codewordRow;
for (int i = 1; i <= checkedRows && !closePreviousCodewordFound; i++)
{
closePreviousCodewordFound = Codewords[codewordRow - i] != null;
}
if (closePreviousCodewordFound)
{
Codewords[codewordRow] = null;
} else
{
barcodeRow = codeword.RowNumber;
currentRowHeight = 1;
}
}
}
return (int)(averageRowHeight + 0.5);
}
/// <summary>
/// Adjusts the in omplete indicator column row numbers.
/// </summary>
/// <param name="metadata">Metadata.</param>
public int AdjustIncompleteIndicatorColumnRowNumbers(BarcodeMetadata metadata)
{
ResultPoint top = IsLeft ? Box.TopLeft : Box.TopRight;
ResultPoint bottom = IsLeft ? Box.BottomLeft : Box.BottomRight;
int firstRow = IndexForRow((int)top.Y);
int lastRow = IndexForRow((int)bottom.Y);
// We need to be careful using the average row height.
// Barcode could be skewed so that we have smaller and taller rows
float averageRowHeight = (lastRow - firstRow) / (float)metadata.RowCount;
// initialize loop
int barcodeRow = -1;
int maxRowHeight = 1;
int currentRowHeight = 0;
for (int codewordRow = firstRow; codewordRow < lastRow; codewordRow++)
{
var codeword = Codewords[codewordRow];
if (codeword == null)
{
continue;
}
codeword.SetRowNumberAsRowIndicatorColumn();
int rowDifference = codeword.RowNumber - barcodeRow;
// TODO improve handling with case where first row indicator doesn't start with 0
if (rowDifference == 0)
{
currentRowHeight++;
} else if (rowDifference == 1)
{
maxRowHeight = Math.Max(maxRowHeight, currentRowHeight);
currentRowHeight = 1;
barcodeRow = codeword.RowNumber;
} else if (codeword.RowNumber > metadata.RowCount)
{
Codewords[codewordRow] = null;
} else
{
barcodeRow = codeword.RowNumber;
currentRowHeight = 1;
}
}
return (int)(averageRowHeight + 0.5);
}
/// <summary>
/// Gets the row heights.
/// </summary>
/// <returns>The row heights.</returns>
public int[] GetRowHeights()
{
BarcodeMetadata metadata = GetBarcodeMetadata();
if (metadata == null)
{
return null;
}
AdjustIncompleteIndicatorColumnRowNumbers(metadata);
int[] result = Enumerable.Repeat(0, metadata.RowCount).ToArray();
foreach (var word in Codewords)
{
if (word != null)
{
result[word.RowNumber]++;
}
}
return result;
}
/// <summary>
/// Gets the barcode metadata.
/// </summary>
/// <returns>The barcode metadata.</returns>
public BarcodeMetadata GetBarcodeMetadata()
{
BarcodeValue barcodeColumnCount = new BarcodeValue();
BarcodeValue barcodeRowCountUpperPart = new BarcodeValue();
BarcodeValue barcodeRowCountLowerPart = new BarcodeValue();
BarcodeValue barcodeECLevel = new BarcodeValue();
foreach (Codeword codeword in Codewords)
{
if (codeword == null)
{
continue;
}
codeword.SetRowNumberAsRowIndicatorColumn();
int rowIndicatorValue = codeword.Value % 30;
int codewordRowNumber = codeword.RowNumber;
if (!IsLeft)
{
codewordRowNumber += 2;
}
switch (codewordRowNumber % 3)
{
case 0:
barcodeRowCountUpperPart.SetValue(rowIndicatorValue * 3 + 1);
break;
case 1:
barcodeECLevel.SetValue(rowIndicatorValue / 3);
barcodeRowCountLowerPart.SetValue(rowIndicatorValue % 3);
break;
case 2:
barcodeColumnCount.SetValue(rowIndicatorValue + 1);
break;
}
}
// Maybe we should check if we have ambiguous values?
if ((barcodeColumnCount.GetValue().Length == 0) ||
(barcodeRowCountUpperPart.GetValue().Length == 0) ||
(barcodeRowCountLowerPart.GetValue().Length == 0) ||
(barcodeECLevel.GetValue().Length == 0) ||
barcodeColumnCount.GetValue()[0] < 1 ||
barcodeRowCountUpperPart.GetValue()[0] + barcodeRowCountLowerPart.GetValue()[0] < PDF417Common.MIN_ROWS_IN_BARCODE ||
barcodeRowCountUpperPart.GetValue()[0] + barcodeRowCountLowerPart.GetValue()[0] > PDF417Common.MAX_ROWS_IN_BARCODE)
{
return null;
}
BarcodeMetadata barcodeMetadata = new BarcodeMetadata(barcodeColumnCount.GetValue()[0],
barcodeRowCountUpperPart.GetValue()[0],
barcodeRowCountLowerPart.GetValue()[0],
barcodeECLevel.GetValue()[0]);
RemoveIncorrectCodewords(barcodeMetadata);
return barcodeMetadata;
}
/// <summary>
/// Prune the codewords which do not match the metadata
/// TODO Maybe we should keep the incorrect codewords for the start and end positions?
/// </summary>
/// <param name="codewords">Codewords.</param>
/// <param name="metadata">Metadata.</param>
private void RemoveIncorrectCodewords(BarcodeMetadata metadata)
{
for (int row = 0; row < Codewords.Length; row++)
{
var codeword = Codewords[row];
if (codeword == null)
continue;
int indicatorValue = codeword.Value % 30;
int rowNumber = codeword.RowNumber;
// Row does not exist in the metadata
if (rowNumber > metadata.RowCount)
{
Codewords[row] = null; // remove this.
continue;
}
if (!IsLeft)
{
rowNumber += 2;
}
switch (rowNumber % 3)
{
default:
case 0:
if (indicatorValue * 3 + 1 != metadata.RowCountUpper)
{
Codewords[row] = null;
}
break;
case 1:
if (indicatorValue % 3 != metadata.RowCountLower ||
indicatorValue / 3 != metadata.ErrorCorrectionLevel)
{
Codewords[row] = null;
}
break;
case 2:
if (indicatorValue + 1 != metadata.ColumnCount)
{
Codewords[row] = null;
}
break;
}
}
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.DetectionResultRowIndicatorColumn"/>.
/// </summary>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.DetectionResultRowIndicatorColumn"/>.</returns>
public override string ToString()
{
return "Is Left: " + IsLeft + " \n" + base.ToString();
}
}
}

View file

@ -0,0 +1,171 @@
// /*
// * Copyright 2009 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.PDF417.Internal
{
/// <summary>
///
/// </summary>
/// <author>Guenther Grau (Java Core)</author>
/// <author>creatale GmbH (christoph.schulz@creatale.de)</author>
/// <author>Stephen Furlani (C# Port)</author>
public static class PDF417CodewordDecoder
{
/// <summary>
/// The ratios table
/// </summary>
private static readonly float[][] RATIOS_TABLE; // = new float[PDF417Common.SYMBOL_TABLE.Length][PDF417Common.BARS_IN_MODULE];
/// <summary>
/// Initializes the <see cref="ZXing.PDF417.Internal.PDF417CodewordDecoder"/> class & Pre-computes the symbol ratio table.
/// </summary>
static PDF417CodewordDecoder()
{
// Jagged arrays in Java assign the memory automatically, but C# has no equivalent. (Jon Skeet says so!)
// http://stackoverflow.com/a/5313879/266252
RATIOS_TABLE = new float[PDF417Common.SYMBOL_TABLE.Length][];
for (int s = 0; s < RATIOS_TABLE.Length; s++)
{
RATIOS_TABLE[s] = new float[PDF417Common.BARS_IN_MODULE];
}
// Pre-computes the symbol ratio table.
for (int i = 0; i < PDF417Common.SYMBOL_TABLE.Length; i++)
{
int currentSymbol = PDF417Common.SYMBOL_TABLE[i];
int currentBit = currentSymbol & 0x1;
for (int j = 0; j < PDF417Common.BARS_IN_MODULE; j++)
{
float size = 0.0f;
while ((currentSymbol & 0x1) == currentBit)
{
size += 1.0f;
currentSymbol >>= 1;
}
currentBit = currentSymbol & 0x1;
RATIOS_TABLE[i][PDF417Common.BARS_IN_MODULE - j - 1] = size / PDF417Common.MODULES_IN_CODEWORD;
}
}
}
/// <summary>
/// Gets the decoded value.
/// </summary>
/// <returns>The decoded value.</returns>
/// <param name="moduleBitCount">Module bit count.</param>
public static int GetDecodedValue(int[] moduleBitCount)
{
int decodedValue = GetDecodedCodewordValue(SampleBitCounts(moduleBitCount));
if (decodedValue == PDF417Common.INVALID_CODEWORD)
{
decodedValue = GetClosestDecodedValue(moduleBitCount);
}
return decodedValue;
}
/// <summary>
/// Samples the bit counts.
/// </summary>
/// <returns>The bit counts.</returns>
/// <param name="moduleBitCount">Module bit count.</param>
private static int[] SampleBitCounts(int[] moduleBitCount)
{
float bitCountSum = PDF417Common.GetBitCountSum(moduleBitCount);
int[] result = new int[PDF417Common.BARS_IN_MODULE];
int bitCountIndex = 0;
int sumPreviousBits = 0;
for (int i = 0; i < PDF417Common.MODULES_IN_CODEWORD; i++)
{
float sampleIndex =
bitCountSum / (2 * PDF417Common.MODULES_IN_CODEWORD) +
(i * bitCountSum) / PDF417Common.MODULES_IN_CODEWORD;
if (sumPreviousBits + moduleBitCount[bitCountIndex] <= sampleIndex)
{
sumPreviousBits += moduleBitCount[bitCountIndex];
bitCountIndex++;
}
result[bitCountIndex]++;
}
return result;
}
/// <summary>
/// Gets the decoded codeword value.
/// </summary>
/// <returns>The decoded codeword value.</returns>
/// <param name="moduleBitCount">Module bit count.</param>
private static int GetDecodedCodewordValue(int[] moduleBitCount)
{
int decodedValue = GetBitValue(moduleBitCount);
return PDF417Common.GetCodeword(decodedValue) == PDF417Common.INVALID_CODEWORD ? PDF417Common.INVALID_CODEWORD : decodedValue;
}
/// <summary>
/// Gets the bit value.
/// </summary>
/// <returns>The bit value.</returns>
/// <param name="moduleBitCount">Module bit count.</param>
private static int GetBitValue(int[] moduleBitCount)
{
ulong result = 0;
for (ulong i = 0; i < (ulong)moduleBitCount.Length; i++)
{
foreach (var bit in moduleBitCount)
{
result = (result << 1) | (i % 2ul == 0ul ? 1ul : 0ul); // C# was warning about using the bit-wise 'OR' here with a mix of int/longs.
}
}
return (int)result;
}
/// <summary>
/// Gets the closest decoded value.
/// </summary>
/// <returns>The closest decoded value.</returns>
/// <param name="moduleBitCount">Module bit count.</param>
private static int GetClosestDecodedValue(int[] moduleBitCount)
{
int bitCountSum = PDF417Common.GetBitCountSum(moduleBitCount);
float[] bitCountRatios = new float[PDF417Common.BARS_IN_MODULE];
for (int i = 0; i < bitCountRatios.Length; i++)
{
bitCountRatios[i] = moduleBitCount[i] / (float)bitCountSum;
}
float bestMatchError = float.MaxValue;
int bestMatch = PDF417Common.INVALID_CODEWORD;
for (int j = 0; j < RATIOS_TABLE.Length; j++)
{
float error = 0.0f;
for (int k = 0; k < PDF417Common.BARS_IN_MODULE; k++)
{
float diff = RATIOS_TABLE[j][k] - bitCountRatios[k];
error += diff * diff;
}
if (error < bestMatchError)
{
bestMatchError = error;
bestMatch = PDF417Common.SYMBOL_TABLE[j];
}
}
return bestMatch;
}
}
}

View file

@ -0,0 +1,894 @@
// /*
// * Copyright 2009 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.Linq;
using ZXing.Common;
using ZXing.PDF417.Internal.EC;
using Log = System.Diagnostics.Debug;
using System.Text;
namespace ZXing.PDF417.Internal
{
/// <summary>
///
/// </summary>
/// <author>Guenther Grau (Java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
public static class PDF417ScanningDecoder
{
private static readonly int CODEWORD_SKEW_SIZE = 2;
private static readonly int MAX_ERRORS = 3;
private static readonly int MAX_EC_CODEWORDS = 512;
private static readonly ErrorCorrection errorCorrection = new ErrorCorrection();
/// <summary>
/// Decode the specified image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight, minCodewordWidth
/// and maxCodewordWidth.
/// TODO: don't pass in minCodewordWidth and maxCodewordWidth, pass in barcode columns for start and stop pattern
/// columns. That way width can be deducted from the pattern column.
/// This approach also allows to detect more details about the barcode, e.g. if a bar type (white or black) is wider
/// than it should be. This can happen if the scanner used a bad blackpoint.
/// </summary>
/// <param name="image">Image.</param>
/// <param name="imageTopLeft">Image top left.</param>
/// <param name="imageBottomLeft">Image bottom left.</param>
/// <param name="imageTopRight">Image top right.</param>
/// <param name="imageBottomRight">Image bottom right.</param>
/// <param name="minCodewordWidth">Minimum codeword width.</param>
/// <param name="maxCodewordWidth">Max codeword width.</param>
public static DecoderResult Decode(BitMatrix image,
ResultPoint imageTopLeft,
ResultPoint imageBottomLeft,
ResultPoint imageTopRight,
ResultPoint imageBottomRight,
int minCodewordWidth,
int maxCodewordWidth)
{
BoundingBox boundingBox = new BoundingBox(image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight);
DetectionResultRowIndicatorColumn leftRowIndicatorColumn = null;
DetectionResultRowIndicatorColumn rightRowIndicatorColumn = null;
DetectionResult detectionResult = null;
for (int i = 0; i < 2; i++)
{
if (imageTopLeft != null)
{
leftRowIndicatorColumn = GetRowIndicatorColumn(image, boundingBox, imageTopLeft, true, minCodewordWidth, maxCodewordWidth);
Log.WriteLine("Before setRowNumbers\n" + leftRowIndicatorColumn);
leftRowIndicatorColumn.SetRowNumbers();
Log.WriteLine("After setRowNumbers\n" + leftRowIndicatorColumn);
}
if (imageTopRight != null)
{
rightRowIndicatorColumn = GetRowIndicatorColumn(image, boundingBox, imageTopRight, false, minCodewordWidth, maxCodewordWidth);
Log.WriteLine("Before setRowNumbers\n" + rightRowIndicatorColumn);
rightRowIndicatorColumn.SetRowNumbers();
Log.WriteLine("After setRowNumbers\n" + rightRowIndicatorColumn);
}
detectionResult = Merge(leftRowIndicatorColumn, rightRowIndicatorColumn);
if (detectionResult == null)
{
// TODO Based on Owen's Comments in <see cref="ZXing.ReaderException"/>, this method has been modified to continue silently
// if a barcode was not decoded where it was detected instead of throwing a new exception object.
// return null;
throw ReaderException.Instance;
}
if (i == 0 &&
(detectionResult.Box.MinY < boundingBox.MinY || detectionResult.Box.MaxY > boundingBox.MaxY))
{
boundingBox = detectionResult.Box;
} else
{
detectionResult.Box = boundingBox;
break;
}
}
int maxBarcodeColumn = detectionResult.ColumnCount + 1;
detectionResult.DetectionResultColumns[0] = leftRowIndicatorColumn;
detectionResult.DetectionResultColumns[maxBarcodeColumn] = rightRowIndicatorColumn;
bool leftToRight = leftRowIndicatorColumn != null;
for (int barcodeColumnCount = 1; barcodeColumnCount <= maxBarcodeColumn; barcodeColumnCount++)
{
int barcodeColumn = leftToRight ? barcodeColumnCount : maxBarcodeColumn - barcodeColumnCount;
if (detectionResult.DetectionResultColumns[barcodeColumn] != null)
{
// This will be the case for the opposite row indicator column, which doesn't need to be decoded again.
continue;
}
DetectionResultColumn detectionResultColumn;
if (barcodeColumn == 0 || barcodeColumn == maxBarcodeColumn)
{
detectionResultColumn = new DetectionResultRowIndicatorColumn(boundingBox, barcodeColumn == 0);
} else
{
detectionResultColumn = new DetectionResultColumn(boundingBox);
}
detectionResult.DetectionResultColumns[barcodeColumn] = detectionResultColumn;
int startColumn = -1;
int previousStartColumn = startColumn;
// TODO start at a row for which we know the start position, then detect upwards and downwards from there.
for (int imageRow = boundingBox.MinY; imageRow <= boundingBox.MaxY; imageRow++)
{
startColumn = GetStartColumn(detectionResult, barcodeColumn, imageRow, leftToRight);
if (startColumn < 0 || startColumn > boundingBox.MaxX)
{
if (previousStartColumn == -1)
{
continue;
}
startColumn = previousStartColumn;
}
Codeword codeword = DetectCodeword(image, boundingBox.MinX, boundingBox.MaxX, leftToRight,
startColumn, imageRow, minCodewordWidth, maxCodewordWidth);
if (codeword != null)
{
detectionResultColumn.SetCodeword(imageRow, codeword);
previousStartColumn = startColumn;
minCodewordWidth = Math.Min(minCodewordWidth, codeword.Width);
maxCodewordWidth = Math.Max(maxCodewordWidth, codeword.Width);
}
}
}
return CreateDecoderResult(detectionResult);
}
/// <summary>
/// Merge the specified leftRowIndicatorColumn and rightRowIndicatorColumn.
/// </summary>
/// <param name="leftRowIndicatorColumn">Left row indicator column.</param>
/// <param name="rightRowIndicatorColumn">Right row indicator column.</param>
private static DetectionResult Merge(DetectionResultRowIndicatorColumn leftRowIndicatorColumn,
DetectionResultRowIndicatorColumn rightRowIndicatorColumn)
{
if (leftRowIndicatorColumn == null && rightRowIndicatorColumn == null)
{
return null;
}
BarcodeMetadata barcodeMetadata = GetBarcodeMetadata(leftRowIndicatorColumn, rightRowIndicatorColumn);
if (barcodeMetadata == null)
{
return null;
}
BoundingBox boundingBox = GetBoundingBox(leftRowIndicatorColumn, rightRowIndicatorColumn);
return new DetectionResult(barcodeMetadata, boundingBox);
}
/// <summary>
/// Gets the bounding box.
/// </summary>
/// <returns>The bounding box.</returns>
/// <param name="leftRowIndicatorColumn">Left row indicator column.</param>
/// <param name="rightRowIndicatorColumn">Right row indicator column.</param>
private static BoundingBox GetBoundingBox(DetectionResultRowIndicatorColumn leftRowIndicatorColumn,
DetectionResultRowIndicatorColumn rightRowIndicatorColumn)
{
BoundingBox box1 = AdjustBoundingBox(leftRowIndicatorColumn);
BoundingBox box2 = AdjustBoundingBox(rightRowIndicatorColumn);
return BoundingBox.Merge(box1, box2);
}
/// <summary>
/// Adjusts the bounding box.
/// </summary>
/// <returns>The bounding box.</returns>
/// <param name="rowIndicatorColumn">Row indicator column.</param>
private static BoundingBox AdjustBoundingBox(DetectionResultRowIndicatorColumn rowIndicatorColumn)
{
if (rowIndicatorColumn == null)
{
return null;
}
int[] rowHeights = rowIndicatorColumn.GetRowHeights();
int maxRowHeight = rowHeights.Max();
int missingStartRows = 0;
foreach (int rowHeight in rowHeights)
{
missingStartRows += maxRowHeight - rowHeight;
if (rowHeight > 0)
{
break;
}
}
Codeword[] codewords = rowIndicatorColumn.Codewords;
for (int row = 0; missingStartRows > 0 && codewords[row] == null; row++)
{
missingStartRows--;
}
int missingEndRows = 0;
for (int row = rowHeights.Length - 1; row >= 0; row--)
{
missingEndRows += maxRowHeight - rowHeights[row];
if (rowHeights[row] > 0)
{
break;
}
}
for (int row = codewords.Length - 1; missingEndRows > 0 && codewords[row] == null; row--)
{
missingEndRows--;
}
return rowIndicatorColumn.Box.AddMissingRows(missingStartRows, missingEndRows, rowIndicatorColumn.IsLeft);
}
/// <summary>
/// Gets the barcode metadata.
/// </summary>
/// <returns>The barcode metadata.</returns>
/// <param name="leftRowIndicatorColumn">Left row indicator column.</param>
/// <param name="rightRowIndicatorColumn">Right row indicator column.</param>
private static BarcodeMetadata GetBarcodeMetadata(DetectionResultRowIndicatorColumn leftRowIndicatorColumn,
DetectionResultRowIndicatorColumn rightRowIndicatorColumn)
{
if (leftRowIndicatorColumn == null || leftRowIndicatorColumn.GetBarcodeMetadata() == null)
{
return rightRowIndicatorColumn == null ? null : rightRowIndicatorColumn.GetBarcodeMetadata();
}
if (rightRowIndicatorColumn == null || rightRowIndicatorColumn.GetBarcodeMetadata() == null)
{
return leftRowIndicatorColumn == null ? null : leftRowIndicatorColumn.GetBarcodeMetadata();
}
BarcodeMetadata leftBarcodeMetadata = leftRowIndicatorColumn.GetBarcodeMetadata();
BarcodeMetadata rightBarcodeMetadata = rightRowIndicatorColumn.GetBarcodeMetadata();
if (leftBarcodeMetadata.ColumnCount != rightBarcodeMetadata.ColumnCount &&
leftBarcodeMetadata.ErrorCorrectionLevel != rightBarcodeMetadata.ErrorCorrectionLevel &&
leftBarcodeMetadata.RowCount != rightBarcodeMetadata.RowCount)
{
return null;
}
return leftBarcodeMetadata;
}
/// <summary>
/// Gets the row indicator column.
/// </summary>
/// <returns>The row indicator column.</returns>
/// <param name="image">Image.</param>
/// <param name="boundingBox">Bounding box.</param>
/// <param name="startPoint">Start point.</param>
/// <param name="leftToRight">If set to <c>true</c> left to right.</param>
/// <param name="minCodewordWidth">Minimum codeword width.</param>
/// <param name="maxCodewordWidth">Max codeword width.</param>
private static DetectionResultRowIndicatorColumn GetRowIndicatorColumn(BitMatrix image,
BoundingBox boundingBox,
ResultPoint startPoint,
bool leftToRight,
int minCodewordWidth,
int maxCodewordWidth)
{
DetectionResultRowIndicatorColumn rowIndicatorColumn = new DetectionResultRowIndicatorColumn(boundingBox, leftToRight);
for (int i = 0; i < 2; i++)
{
int increment = i == 0 ? 1 : -1;
int startColumn = (int)startPoint.X;
for (int imageRow = (int) startPoint.Y; imageRow <= boundingBox.MaxY &&
imageRow >= boundingBox.MinY; imageRow += increment)
{
Codeword codeword = DetectCodeword(image, 0, image.Width, leftToRight, startColumn, imageRow,
minCodewordWidth, maxCodewordWidth);
if (codeword != null)
{
rowIndicatorColumn.SetCodeword(imageRow, codeword);
if (leftToRight)
{
startColumn = codeword.StartX;
} else
{
startColumn = codeword.EndX;
}
}
}
}
return rowIndicatorColumn;
}
/// <summary>
/// Adjusts the codeword count.
/// </summary>
/// <param name="detectionResult">Detection result.</param>
/// <param name="barcodeMatrix">Barcode matrix.</param>
private static void AdjustCodewordCount(DetectionResult detectionResult, BarcodeValue[][] barcodeMatrix)
{
int[] numberOfCodewords = barcodeMatrix[0][1].GetValue();
int calculatedNumberOfCodewords = detectionResult.ColumnCount *
detectionResult.RowCount -
GetNumberOfECCodeWords(detectionResult.ErrorCorrectionLevel);
if (numberOfCodewords.Length == 0)
{
if (calculatedNumberOfCodewords < 1 || calculatedNumberOfCodewords > PDF417Common.MAX_CODEWORDS_IN_BARCODE)
{
throw ReaderException.Instance;
}
barcodeMatrix[0][1].SetValue(calculatedNumberOfCodewords);
} else if (numberOfCodewords[0] != calculatedNumberOfCodewords)
{
// The calculated one is more reliable as it is derived from the row indicator columns
barcodeMatrix[0][1].SetValue(calculatedNumberOfCodewords);
}
}
/// <summary>
/// Creates the decoder result.
/// </summary>
/// <returns>The decoder result.</returns>
/// <param name="detectionResult">Detection result.</param>
private static DecoderResult CreateDecoderResult(DetectionResult detectionResult)
{
BarcodeValue[][] barcodeMatrix = CreateBarcodeMatrix(detectionResult);
AdjustCodewordCount(detectionResult, barcodeMatrix);
List<int> erasures = new List<int>();
int[] codewords = new int[detectionResult.RowCount * detectionResult.ColumnCount];
List<int[]> ambiguousIndexValuesList = new List<int[]>();
List<int> ambiguousIndexesList = new List<int>();
for (int row = 0; row < detectionResult.RowCount; row++)
{
for (int column = 0; column < detectionResult.ColumnCount; column++)
{
int[] values = barcodeMatrix[row][column + 1].GetValue();
int codewordIndex = row * detectionResult.ColumnCount + column;
if (values.Length == 0)
{
erasures.Add(codewordIndex);
} else if (values.Length == 1)
{
codewords[codewordIndex] = values[0];
} else
{
ambiguousIndexesList.Add(codewordIndex);
ambiguousIndexValuesList.Add(values);
}
}
}
int[][] ambiguousIndexValues = new int[ambiguousIndexValuesList.Count][];
for (int i = 0; i < ambiguousIndexValues.Length; i++)
{
ambiguousIndexValues[i] = ambiguousIndexValuesList[i];
}
return CreateDecoderResultFromAmbiguousValues(detectionResult.ErrorCorrectionLevel, codewords,
erasures.ToArray(), ambiguousIndexesList.ToArray(), ambiguousIndexValues);
}
/**
* This method deals with the fact, that the decoding process doesn't always yield a single most likely value. The
* current error correction implementation doesn't deal with erasures very well, so it's better to provide a value
* for these ambiguous codewords instead of treating it as an erasure. The problem is that we don't know which of
* the ambiguous values to choose. We try decode using the first value, and if that fails, we use another of the
* ambiguous values and try to decode again. This usually only happens on very hard to read and decode barcodes,
* so decoding the normal barcodes is not affected by this.
* @param ecLevel
* @param codewords
* @param erasureArray contains the indexes of erasures
* @param ambiguousIndexes array with the indexes that have more than one most likely value
* @param ambiguousIndexValues two dimensional array that contains the ambiguous values. The first dimension must
* be the same Length as the ambiguousIndexes array
* @return
* @throws FormatException
* @throws ChecksumException
*/
/// <summary>
/// This method deals with the fact, that the decoding process doesn't always yield a single most likely value. The
/// current error correction implementation doesn't deal with erasures very well, so it's better to provide a value
/// for these ambiguous codewords instead of treating it as an erasure. The problem is that we don't know which of
/// the ambiguous values to choose. We try decode using the first value, and if that fails, we use another of the
/// ambiguous values and try to decode again. This usually only happens on very hard to read and decode barcodes,
/// so decoding the normal barcodes is not affected by this.
/// </summary>
/// <returns>The decoder result from ambiguous values.</returns>
/// <param name="ecLevel">Ec level.</param>
/// <param name="codewords">Codewords.</param>
/// <param name="erasureArray">contains the indexes of erasures.</param>
/// <param name="ambiguousIndexes">array with the indexes that have more than one most likely value.</param>
/// <param name="ambiguousIndexValues">two dimensional array that contains the ambiguous values. The first dimension must
/// be the same Length as the ambiguousIndexes array.</param>
/// <exception cref="Zxing.ReaderException"></exception>
private static DecoderResult CreateDecoderResultFromAmbiguousValues(int ecLevel,
int[] codewords,
int[] erasureArray,
int[] ambiguousIndexes,
int[][] ambiguousIndexValues)
{
int[] ambiguousIndexCount = new int[ambiguousIndexes.Length];
int tries = 100;
while (tries-- > 0)
{
for (int i = 0; i < ambiguousIndexCount.Length; i++)
{
codewords[ambiguousIndexes[i]] = ambiguousIndexValues[i][ambiguousIndexCount[i]];
}
try
{
return DecodeCodewords(codewords, ecLevel, erasureArray);
} catch (ReaderException ignored)
{
//
}
if (ambiguousIndexCount.Length == 0)
{
throw ReaderException.Instance;
}
for (int i = 0; i < ambiguousIndexCount.Length; i++)
{
if (ambiguousIndexCount[i] < ambiguousIndexValues[i].Length - 1)
{
ambiguousIndexCount[i]++;
break;
} else
{
ambiguousIndexCount[i] = 0;
if (i == ambiguousIndexCount.Length - 1)
{
throw ReaderException.Instance;
}
}
}
}
throw ReaderException.Instance;
}
/// <summary>
/// Creates the barcode matrix.
/// </summary>
/// <returns>The barcode matrix.</returns>
/// <param name="detectionResult">Detection result.</param>
private static BarcodeValue[][] CreateBarcodeMatrix(DetectionResult detectionResult)
{
// Manually setup Jagged Array in C#
BarcodeValue[][] barcodeMatrix = new BarcodeValue[detectionResult.RowCount][];
for (int row = 0; row < barcodeMatrix.Length; row++)
{
barcodeMatrix[row] = new BarcodeValue[detectionResult.ColumnCount + 2];// Enumerable.Repeat(new BarcodeValue(), detectionResult.ColumnCount + 2).ToArray();
for (int col = 0; col < barcodeMatrix[row].Length; col++)
{
barcodeMatrix[row][col] = new BarcodeValue();
}
}
int column = -1;
foreach (DetectionResultColumn detectionResultColumn in detectionResult.GetDetectionResultColumns())
{
column++;
if (detectionResultColumn == null)
{
continue;
}
foreach (Codeword codeword in detectionResultColumn.Codewords)
{
if (codeword == null || codeword.RowNumber == -1)
{
continue;
}
barcodeMatrix[codeword.RowNumber][column].SetValue(codeword.Value);
}
}
return barcodeMatrix;
}
/// <summary>
/// Tests to see if the Barcode Column is Valid
/// </summary>
/// <returns><c>true</c>, if barcode column is valid, <c>false</c> otherwise.</returns>
/// <param name="detectionResult">Detection result.</param>
/// <param name="barcodeColumn">Barcode column.</param>
private static bool IsValidBarcodeColumn(DetectionResult detectionResult, int barcodeColumn)
{
return (barcodeColumn >= 0) && (barcodeColumn < detectionResult.DetectionResultColumns.Length);
}
/// <summary>
/// Gets the start column.
/// </summary>
/// <returns>The start column.</returns>
/// <param name="detectionResult">Detection result.</param>
/// <param name="barcodeColumn">Barcode column.</param>
/// <param name="imageRow">Image row.</param>
/// <param name="leftToRight">If set to <c>true</c> left to right.</param>
private static int GetStartColumn(DetectionResult detectionResult,
int barcodeColumn,
int imageRow,
bool leftToRight)
{
int offset = leftToRight ? 1 : -1;
Codeword codeword = null;
if (IsValidBarcodeColumn(detectionResult, barcodeColumn - offset))
{
codeword = detectionResult.DetectionResultColumns[barcodeColumn - offset].GetCodeword(imageRow);
}
if (codeword != null)
{
return leftToRight ? codeword.EndX : codeword.StartX;
}
codeword = detectionResult.DetectionResultColumns[barcodeColumn].GetCodewordNearby(imageRow);
if (codeword != null)
{
return leftToRight ? codeword.EndX : codeword.StartX;
}
if (IsValidBarcodeColumn(detectionResult, barcodeColumn - offset))
{
codeword = detectionResult.DetectionResultColumns[barcodeColumn - offset].GetCodewordNearby(imageRow);
}
if (codeword != null)
{
return leftToRight ? codeword.EndX : codeword.StartX;
}
int skippedColumns = 0;
while (IsValidBarcodeColumn(detectionResult, barcodeColumn - offset))
{
barcodeColumn -= offset;
foreach (Codeword previousRowCodeword in detectionResult.DetectionResultColumns[barcodeColumn].Codewords)
{
if (previousRowCodeword != null)
{
return (leftToRight ? previousRowCodeword.EndX : previousRowCodeword.StartX) +
offset *
skippedColumns *
(previousRowCodeword.EndX - previousRowCodeword.StartX);
}
}
skippedColumns++;
}
return leftToRight ? detectionResult.Box.MinX : detectionResult.Box.MaxX;
}
/// <summary>
/// Detects the codeword.
/// </summary>
/// <returns>The codeword.</returns>
/// <param name="image">Image.</param>
/// <param name="minColumn">Minimum column.</param>
/// <param name="maxColumn">Max column.</param>
/// <param name="leftToRight">If set to <c>true</c> left to right.</param>
/// <param name="startColumn">Start column.</param>
/// <param name="imageRow">Image row.</param>
/// <param name="minCodewordWidth">Minimum codeword width.</param>
/// <param name="maxCodewordWidth">Max codeword width.</param>
private static Codeword DetectCodeword(BitMatrix image,
int minColumn,
int maxColumn,
bool leftToRight,
int startColumn,
int imageRow,
int minCodewordWidth,
int maxCodewordWidth)
{
startColumn = AdjustCodewordStartColumn(image, minColumn, maxColumn, leftToRight, startColumn, imageRow);
// we usually know fairly exact now how long a codeword is. We should provide minimum and maximum expected Length
// and try to adjust the read pixels, e.g. remove single pixel errors or try to cut off exceeding pixels.
// min and maxCodewordWidth should not be used as they are calculated for the whole barcode an can be inaccurate
// for the current position
int[] moduleBitCount = GetModuleBitCount(image, minColumn, maxColumn, leftToRight, startColumn, imageRow);
if (moduleBitCount == null)
{
return null;
}
int endColumn;
int codewordBitCount = PDF417Common.GetBitCountSum(moduleBitCount);
if (leftToRight)
{
endColumn = startColumn + codewordBitCount;
} else
{
for (int i = 0; i < moduleBitCount.Length >> 1; i++)
{
int tmpCount = moduleBitCount[i];
moduleBitCount[i] = moduleBitCount[moduleBitCount.Length - 1 - i];
moduleBitCount[moduleBitCount.Length - 1 - i] = tmpCount;
}
endColumn = startColumn;
startColumn = endColumn - codewordBitCount;
}
// TODO implement check for width and correction of black and white bars
// use start (and maybe stop pattern) to determine if blackbars are wider than white bars. If so, adjust.
// should probably done only for codewords with a lot more than 17 bits.
// The following fixes 10-1.png, which has wide black bars and small white bars
// for (int i = 0; i < moduleBitCount.Length; i++) {
// if (i % 2 == 0) {
// moduleBitCount[i]--;
// } else {
// moduleBitCount[i]++;
// }
// }
// We could also use the width of surrounding codewords for more accurate results, but this seems
// sufficient for now
if (!CheckCodewordSkew(codewordBitCount, minCodewordWidth, maxCodewordWidth))
{
// We could try to use the startX and endX position of the codeword in the same column in the previous row,
// create the bit count from it and normalize it to 8. This would help with single pixel errors.
return null;
}
int decodedValue = PDF417CodewordDecoder.GetDecodedValue(moduleBitCount);
int codeword = PDF417Common.GetCodeword(decodedValue);
if (codeword == -1)
{
return null;
}
return new Codeword(startColumn, endColumn, GetCodewordBucketNumber(decodedValue), codeword);
}
/// <summary>
/// Gets the module bit count.
/// </summary>
/// <returns>The module bit count.</returns>
/// <param name="image">Image.</param>
/// <param name="minColumn">Minimum column.</param>
/// <param name="maxColumn">Max column.</param>
/// <param name="leftToRight">If set to <c>true</c> left to right.</param>
/// <param name="startColumn">Start column.</param>
/// <param name="imageRow">Image row.</param>
private static int[] GetModuleBitCount(BitMatrix image,
int minColumn,
int maxColumn,
bool leftToRight,
int startColumn,
int imageRow)
{
int imageColumn = startColumn;
int[] moduleBitCount = new int[8];
int moduleNumber = 0;
int increment = leftToRight ? 1 : -1;
bool previousPixelValue = leftToRight;
while (((leftToRight && imageColumn < maxColumn) || (!leftToRight && imageColumn >= minColumn)) &&
moduleNumber < moduleBitCount.Length)
{
if (image[imageColumn, imageRow] == previousPixelValue)
{
moduleBitCount[moduleNumber]++;
imageColumn += increment;
} else
{
moduleNumber++;
previousPixelValue = !previousPixelValue;
}
}
if (moduleNumber == moduleBitCount.Length ||
(((leftToRight && imageColumn == maxColumn) || (!leftToRight && imageColumn == minColumn)) && moduleNumber == moduleBitCount.Length - 1))
{
return moduleBitCount;
}
return null;
}
/// <summary>
/// Gets the number of EC code words.
/// </summary>
/// <returns>The number of EC code words.</returns>
/// <param name="barcodeECLevel">Barcode EC level.</param>
private static int GetNumberOfECCodeWords(int barcodeECLevel)
{
return 2 << barcodeECLevel;
}
/// <summary>
/// Adjusts the codeword start column.
/// </summary>
/// <returns>The codeword start column.</returns>
/// <param name="image">Image.</param>
/// <param name="minColumn">Minimum column.</param>
/// <param name="maxColumn">Max column.</param>
/// <param name="leftToRight">If set to <c>true</c> left to right.</param>
/// <param name="codewordStartColumn">Codeword start column.</param>
/// <param name="imageRow">Image row.</param>
private static int AdjustCodewordStartColumn(BitMatrix image,
int minColumn,
int maxColumn,
bool leftToRight,
int codewordStartColumn,
int imageRow)
{
int correctedStartColumn = codewordStartColumn;
int increment = leftToRight ? -1 : 1;
// there should be no black pixels before the start column. If there are, then we need to start earlier.
for (int i = 0; i < 2; i++)
{
while (((leftToRight && correctedStartColumn >= minColumn) || (!leftToRight && correctedStartColumn < maxColumn)) &&
leftToRight == image[correctedStartColumn, imageRow])
{
if (Math.Abs(codewordStartColumn - correctedStartColumn) > CODEWORD_SKEW_SIZE)
{
return codewordStartColumn;
}
correctedStartColumn += increment;
}
increment = -increment;
leftToRight = !leftToRight;
}
return correctedStartColumn;
}
/// <summary>
/// Checks the codeword for any skew.
/// </summary>
/// <returns><c>true</c>, if codeword is within the skew, <c>false</c> otherwise.</returns>
/// <param name="codewordSize">Codeword size.</param>
/// <param name="minCodewordWidth">Minimum codeword width.</param>
/// <param name="maxCodewordWidth">Max codeword width.</param>
private static bool CheckCodewordSkew(int codewordSize, int minCodewordWidth, int maxCodewordWidth)
{
return minCodewordWidth - CODEWORD_SKEW_SIZE <= codewordSize &&
codewordSize <= maxCodewordWidth + CODEWORD_SKEW_SIZE;
}
/// <summary>
/// Decodes the codewords.
/// </summary>
/// <returns>The codewords.</returns>
/// <param name="codewords">Codewords.</param>
/// <param name="ecLevel">Ec level.</param>
/// <param name="erasures">Erasures.</param>
private static DecoderResult DecodeCodewords(int[] codewords, int ecLevel, int[] erasures)
{
if (codewords.Length == 0)
{
throw ReaderException.Instance;
}
int numECCodewords = 1 << (ecLevel + 1);
Log.WriteLine("EC level: " + ecLevel + ", ec codewords: " + numECCodewords);
int correctedErrorsCount = CorrectErrors(codewords, erasures, numECCodewords);
Log.WriteLine("Corrected errors: " + correctedErrorsCount);
VerifyCodewordCount(codewords, numECCodewords);
// Decode the codewords
DecoderResult decoderResult = DecodedBitStreamParser.Decode(codewords);
decoderResult.ErrorsCorrected = (correctedErrorsCount >= 0) ? correctedErrorsCount : 0;
decoderResult.Erasures = erasures.Length;
return decoderResult;
}
/// <summary>
/// Given data and error-correction codewords received, possibly corrupted by errors, attempts to
/// correct the errors in-place.
/// </summary>
/// <returns>The errors.</returns>
/// <param name="codewords">data and error correction codewords.</param>
/// <param name="erasures">positions of any known erasures.</param>
/// <param name="numECCodewords">number of error correction codewords that are available in codewords.</param>
private static int CorrectErrors(int[] codewords, int[] erasures, int numECCodewords)
{
if (erasures != null &&
erasures.Length > numECCodewords / 2 + MAX_ERRORS ||
numECCodewords < 0 ||
numECCodewords > MAX_EC_CODEWORDS)
{
// Too many errors or EC Codewords is corrupted
throw ReaderException.Instance;
//return -1;
}
return errorCorrection.Decode(codewords, numECCodewords, erasures);
}
/// <summary>
/// Verifies that all is well with the the codeword array.
/// </summary>
/// <param name="codewords">Codewords.</param>
/// <param name="numECCodewords">Number EC codewords.</param>
private static void VerifyCodewordCount(int[] codewords, int numECCodewords)
{
if (codewords.Length < 4)
{
// Codeword array size should be at least 4 allowing for
// Count CW, At least one Data CW, Error Correction CW, Error Correction CW
throw ReaderException.Instance;
}
// The first codeword, the Symbol Length Descriptor, shall always encode the total number of data
// codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad
// codewords, but excluding the number of error correction codewords.
int numberOfCodewords = codewords[0];
if (numberOfCodewords > codewords.Length)
{
throw ReaderException.Instance;
}
if (numberOfCodewords == 0)
{
// Reset to the Length of the array - 8 (Allow for at least level 3 Error Correction (8 Error Codewords)
if (numECCodewords < codewords.Length)
{
codewords[0] = codewords.Length - numECCodewords;
} else
{
throw ReaderException.Instance;
}
}
}
/// <summary>
/// Gets the bit count for codeword.
/// </summary>
/// <returns>The bit count for codeword.</returns>
/// <param name="codeword">Codeword.</param>
private static int[] GetBitCountForCodeword(int codeword)
{
int[] result = new int[8];
int previousValue = 0;
int i = result.Length - 1;
while (true)
{
if ((codeword & 0x1) != previousValue)
{
previousValue = codeword & 0x1;
i--;
if (i < 0)
{
break;
}
}
result[i]++;
codeword >>= 1;
}
return result;
}
/// <summary>
/// Gets the codeword bucket number.
/// </summary>
/// <returns>The codeword bucket number.</returns>
/// <param name="codeword">Codeword.</param>
private static int GetCodewordBucketNumber(int codeword)
{
return GetCodewordBucketNumber(GetBitCountForCodeword(codeword));
}
/// <summary>
/// Gets the codeword bucket number.
/// </summary>
/// <returns>The codeword bucket number.</returns>
/// <param name="moduleBitCount">Module bit count.</param>
private static int GetCodewordBucketNumber(int[] moduleBitCount)
{
return (moduleBitCount[0] - moduleBitCount[2] + moduleBitCount[4] - moduleBitCount[6] + 9) % 9;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the <see cref="ZXing.PDF417.Internal.BarcodeValue"/> jagged array.
/// </summary>
/// <returns>A <see cref="System.String"/> that represents the <see cref="ZXing.PDF417.Internal.BarcodeValue"/> jagged array.</returns>
/// <param name="barcodeMatrix">Barcode matrix as a jagged array.</param>
public static String ToString(BarcodeValue[][] barcodeMatrix)
{
StringBuilder formatter = new StringBuilder();
for (int row = 0; row < barcodeMatrix.Length; row++)
{
formatter.AppendFormat("Row {0,2}: ", row);
for (int column = 0; column < barcodeMatrix[row].Length; column++)
{
BarcodeValue barcodeValue = barcodeMatrix[row][column];
if (barcodeValue.GetValue().Length == 0)
{
formatter.Append(" ");
} else
{
formatter.AppendFormat("{0,4}({0,3})", barcodeValue.GetValue()[0], barcodeValue.GetConfidence(barcodeValue.GetValue()[0]));
}
}
formatter.Append("\n");
}
return formatter.ToString();
}
}
}

View file

@ -0,0 +1,244 @@
/*
* Copyright 2012 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.PDF417.Internal.EC
{
/// <summary>
/// <p>PDF417 error correction implementation.</p>
/// <p>This <a href="http://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction#Example">example</a>
/// is quite useful in understanding the algorithm.</p>
/// <author>Sean Owen</author>
/// <see cref="ZXing.Common.ReedSolomon.ReedSolomonDecoder" />
/// </summary>
public sealed class ErrorCorrection
{
private readonly ModulusGF field;
/// <summary>
/// Initializes a new instance of the <see cref="ErrorCorrection"/> class.
/// </summary>
public ErrorCorrection()
{
this.field = ModulusGF.PDF417_GF;
}
/// <summary>
/// Decodes the specified received.
/// </summary>
/// <param name="received">The received.</param>
/// <param name="numECCodewords">The num EC codewords.</param>
/// <param name="erasures">The erasures.</param>
/// <returns></returns>
public int Decode(int[] received,
int numECCodewords,
int[] erasures)
{
ModulusPoly poly = new ModulusPoly(field, received);
int[] S = new int[numECCodewords];
bool error = false;
for (int i = numECCodewords; i > 0; i--)
{
int eval = poly.EvaluateAt(field.Exp(i));
S[numECCodewords - i] = eval;
if (eval != 0)
{
error = true;
}
}
if (!error)
{
return 0;
}
ModulusPoly knownErrors = field.One;
foreach (int erasure in erasures)
{
int b = field.Exp(received.Length - 1 - erasure);
// Add (1 - bx) term:
ModulusPoly term = new ModulusPoly(field, new int[]
{
field.Subtract(0, b),
1
});
knownErrors = knownErrors.Multiply(term);
}
ModulusPoly syndrome = new ModulusPoly(field, S);
//syndrome = syndrome.multiply(knownErrors);
ModulusPoly[] sigmaOmega = RunEuclideanAlgorithm(field.BuildMonomial(numECCodewords, 1), syndrome, numECCodewords);
if (sigmaOmega == null)
{
throw ReaderException.Instance;
}
ModulusPoly sigma = sigmaOmega[0];
ModulusPoly omega = sigmaOmega[1];
if (sigma == null || omega == null)
{
throw ReaderException.Instance;
}
//sigma = sigma.multiply(knownErrors);
int[] errorLocations = FindErrorLocations(sigma);
if (errorLocations == null)
{
throw ReaderException.Instance;
}
int[] errorMagnitudes = FindErrorMagnitudes(omega, sigma, errorLocations);
for (int i = 0; i < errorLocations.Length; i++)
{
int position = received.Length - 1 - field.Log(errorLocations[i]);
if (position < 0)
{
throw ReaderException.Instance;
// return -3; // don't throw
}
received[position] = field.Subtract(received[position], errorMagnitudes[i]);
}
return errorLocations.Length;
}
/// <summary>
/// Runs the euclidean algorithm (Greatest Common Divisor) until r's degree is less than R/2
/// </summary>
/// <returns>The euclidean algorithm.</returns>
private ModulusPoly[] RunEuclideanAlgorithm(ModulusPoly a, ModulusPoly b, int R)
{
// Assume a's degree is >= b's
if (a.Degree < b.Degree)
{
ModulusPoly temp = a;
a = b;
b = temp;
}
ModulusPoly rLast = a;
ModulusPoly r = b;
ModulusPoly tLast = field.Zero;
ModulusPoly t = field.One;
// Run Euclidean algorithm until r's degree is less than R/2
while (r.Degree >= R / 2)
{
ModulusPoly rLastLast = rLast;
ModulusPoly tLastLast = tLast;
rLast = r;
tLast = t;
// Divide rLastLast by rLast, with quotient in q and remainder in r
if (rLast.IsZero)
{
// Oops, Euclidean algorithm already terminated?
return null;
}
r = rLastLast;
ModulusPoly q = field.Zero;
int denominatorLeadingTerm = rLast.GetCoefficient(rLast.Degree);
int dltInverse = field.Inverse(denominatorLeadingTerm);
while (r.Degree >= rLast.Degree && !r.IsZero)
{
int degreeDiff = r.Degree - rLast.Degree;
int scale = field.Multiply(r.GetCoefficient(r.Degree), dltInverse);
q = q.Add(field.BuildMonomial(degreeDiff, scale));
r = r.Subtract(rLast.MultiplyByMonomial(degreeDiff, scale));
}
t = q.Multiply(tLast).Subtract(tLastLast).GetNegative();
}
int sigmaTildeAtZero = t.GetCoefficient(0);
if (sigmaTildeAtZero == 0)
{
return null;
}
int inverse = field.Inverse(sigmaTildeAtZero);
ModulusPoly sigma = t.Multiply(inverse);
ModulusPoly omega = r.Multiply(inverse);
return new ModulusPoly[] { sigma, omega };
}
/// <summary>
/// Finds the error locations as a direct application of Chien's search
/// </summary>
/// <returns>The error locations.</returns>
/// <param name="errorLocator">Error locator.</param>
private int[] FindErrorLocations(ModulusPoly errorLocator)
{
// This is a direct application of Chien's search
int numErrors = errorLocator.Degree;
int[] result = new int[numErrors];
int e = 0;
for (int i = 1; i < field.Size && e < numErrors; i++)
{
if (errorLocator.EvaluateAt(i) == 0)
{
result[e] = field.Inverse(i);
e++;
}
}
if (e != numErrors)
{
// return null;
throw ReaderException.Instance;
}
return result;
}
/// <summary>
/// Finds the error magnitudes by directly applying Forney's Formula
/// </summary>
/// <returns>The error magnitudes.</returns>
/// <param name="errorEvaluator">Error evaluator.</param>
/// <param name="errorLocator">Error locator.</param>
/// <param name="errorLocations">Error locations.</param>
private int[] FindErrorMagnitudes(ModulusPoly errorEvaluator,
ModulusPoly errorLocator,
int[] errorLocations)
{
int errorLocatorDegree = errorLocator.Degree;
int[] formalDerivativeCoefficients = new int[errorLocatorDegree];
for (int i = 1; i <= errorLocatorDegree; i++)
{
formalDerivativeCoefficients[errorLocatorDegree - i] =
field.Multiply(i, errorLocator.GetCoefficient(i));
}
ModulusPoly formalDerivative = new ModulusPoly(field, formalDerivativeCoefficients);
// This is directly applying Forney's Formula
int s = errorLocations.Length;
int[] result = new int[s];
for (int i = 0; i < s; i++)
{
int xiInverse = field.Inverse(errorLocations[i]);
int numerator = field.Subtract(0, errorEvaluator.EvaluateAt(xiInverse));
int denominator = field.Inverse(formalDerivative.EvaluateAt(xiInverse));
result[i] = field.Multiply(numerator, denominator);
}
return result;
}
}
}

View file

@ -0,0 +1,122 @@
/*
* Copyright 2012 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.PDF417.Internal.EC
{
/// <summary>
/// <p>A field based on powers of a generator integer, modulo some modulus.</p>
/// @see com.google.zxing.common.reedsolomon.GenericGF
/// </summary>
/// <author>Sean Owen</author>
/// <author>Stephen Furlani (CS Port of Guenther Grau's new PDF417 code)</author>
internal sealed class ModulusGF
{
public static ModulusGF PDF417_GF = new ModulusGF(929, 3);
private readonly int[] expTable;
private readonly int[] logTable;
public ModulusPoly Zero { get; private set; }
public ModulusPoly One { get; private set; }
private int Modulus { get; set; }
public ModulusGF(int modulus, int generator)
{
this.Modulus = modulus;
expTable = new int[modulus];
logTable = new int[modulus];
int x = 1;
for (int i = 0; i < modulus; i++)
{
expTable[i] = x;
x = (x * generator) % modulus;
}
for (int i = 0; i < modulus - 1; i++)
{
logTable[expTable[i]] = i;
}
// logTable[0] == 0 but this should never be used
Zero = new ModulusPoly(this, new int[] { 0 });
One = new ModulusPoly(this, new int[] { 1 });
}
internal ModulusPoly BuildMonomial(int degree, int coefficient)
{
if (degree < 0)
{
throw new ArgumentException();
}
if (coefficient == 0)
{
return Zero;
}
int[] coefficients = new int[degree + 1];
coefficients[0] = coefficient;
return new ModulusPoly(this, coefficients);
}
internal int Add(int a, int b)
{
return (a + b) % Modulus;
}
internal int Subtract(int a, int b)
{
return (Modulus + a - b) % Modulus;
}
internal int Exp(int a)
{
return expTable[a];
}
internal int Log(int a)
{
if (a == 0)
{
throw new ArgumentException();
}
return logTable[a];
}
internal int Inverse(int a)
{
if (a == 0)
{
throw new ArithmeticException();
}
return expTable[Modulus - logTable[a] - 1];
}
internal int Multiply(int a, int b)
{
if (a == 0 || b == 0)
{
return 0;
}
return expTable[(logTable[a] + logTable[b]) % (Modulus - 1)];
}
internal int Size
{
get
{
return Modulus;
}
}
}
}

View file

@ -0,0 +1,365 @@
/*
* Copyright 2012 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.Text;
namespace ZXing.PDF417.Internal.EC
{
/// <summary>
/// <see cref="com.google.zxing.common.reedsolomon.GenericGFPoly"/>
/// </summary>
/// <author>Sean Owen</author>
internal sealed class ModulusPoly
{
private readonly ModulusGF field;
private readonly int[] coefficients;
public ModulusPoly(ModulusGF field, int[] coefficients)
{
if (coefficients.Length == 0)
{
throw new ArgumentException();
}
this.field = field;
int coefficientsLength = coefficients.Length;
if (coefficientsLength > 1 && coefficients[0] == 0)
{
// Leading term must be non-zero for anything except the constant polynomial "0"
int firstNonZero = 1;
while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0)
{
firstNonZero++;
}
if (firstNonZero == coefficientsLength)
{
this.coefficients = field.Zero.coefficients;
} else
{
this.coefficients = new int[coefficientsLength - firstNonZero];
Array.Copy(coefficients,
firstNonZero,
this.coefficients,
0,
this.coefficients.Length);
}
} else
{
this.coefficients = coefficients;
}
}
/// <summary>
/// Gets the coefficients.
/// </summary>
/// <value>The coefficients.</value>
internal int[] Coefficients
{
get
{
return coefficients;
}
}
/// <summary>
/// degree of this polynomial
/// </summary>
internal int Degree
{
get
{
return coefficients.Length - 1;
}
}
/// <summary>
/// Gets a value indicating whether this instance is zero.
/// </summary>
/// <value>true if this polynomial is the monomial "0"
/// </value>
internal bool IsZero
{
get { return coefficients[0] == 0; }
}
/// <summary>
/// coefficient of x^degree term in this polynomial
/// </summary>
/// <param name="degree">The degree.</param>
/// <returns>coefficient of x^degree term in this polynomial</returns>
internal int GetCoefficient(int degree)
{
return coefficients[coefficients.Length - 1 - degree];
}
/// <summary>
/// evaluation of this polynomial at a given point
/// </summary>
/// <param name="a">A.</param>
/// <returns>evaluation of this polynomial at a given point</returns>
internal int EvaluateAt(int a)
{
if (a == 0)
{
// Just return the x^0 coefficient
return GetCoefficient(0);
}
int size = coefficients.Length;
int result = 0;
if (a == 1)
{
// Just the sum of the coefficients
foreach (var coefficient in coefficients)
{
result = field.Add(result, coefficient);
}
return result;
}
result = coefficients[0];
for (int i = 1; i < size; i++)
{
result = field.Add(field.Multiply(a, result), coefficients[i]);
}
return result;
}
/// <summary>
/// Adds another Modulus
/// </summary>
/// <param name="other">Other.</param>
internal ModulusPoly Add(ModulusPoly other)
{
if (!field.Equals(other.field))
{
throw new ArgumentException("ModulusPolys do not have same ModulusGF field");
}
if (IsZero)
{
return other;
}
if (other.IsZero)
{
return this;
}
int[] smallerCoefficients = this.coefficients;
int[] largerCoefficients = other.coefficients;
if (smallerCoefficients.Length > largerCoefficients.Length)
{
int[] temp = smallerCoefficients;
smallerCoefficients = largerCoefficients;
largerCoefficients = temp;
}
int[] sumDiff = new int[largerCoefficients.Length];
int lengthDiff = largerCoefficients.Length - smallerCoefficients.Length;
// Copy high-order terms only found in higher-degree polynomial's coefficients
Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
for (int i = lengthDiff; i < largerCoefficients.Length; i++)
{
sumDiff[i] = field.Add(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
}
return new ModulusPoly(field, sumDiff);
}
/// <summary>
/// Subtract another Modulus
/// </summary>
/// <param name="other">Other.</param>
internal ModulusPoly Subtract(ModulusPoly other)
{
if (!field.Equals(other.field))
{
throw new ArgumentException("ModulusPolys do not have same ModulusGF field");
}
if (other.IsZero)
{
return this;
}
return Add(other.GetNegative());
}
/// <summary>
/// Multiply by another Modulus
/// </summary>
/// <param name="other">Other.</param>
internal ModulusPoly Multiply(ModulusPoly other)
{
if (!field.Equals(other.field))
{
throw new ArgumentException("ModulusPolys do not have same ModulusGF field");
}
if (IsZero || other.IsZero)
{
return field.Zero;
}
int[] aCoefficients = this.coefficients;
int aLength = aCoefficients.Length;
int[] bCoefficients = other.coefficients;
int bLength = bCoefficients.Length;
int[] product = new int[aLength + bLength - 1];
for (int i = 0; i < aLength; i++)
{
int aCoeff = aCoefficients[i];
for (int j = 0; j < bLength; j++)
{
product[i + j] = field.Add(product[i + j], field.Multiply(aCoeff, bCoefficients[j]));
}
}
return new ModulusPoly(field, product);
}
/// <summary>
/// Returns a Negative version of this instance
/// </summary>
internal ModulusPoly GetNegative()
{
int size = coefficients.Length;
int[] negativeCoefficients = new int[size];
for (int i = 0; i < size; i++)
{
negativeCoefficients[i] = field.Subtract(0, coefficients[i]);
}
return new ModulusPoly(field, negativeCoefficients);
}
/// <summary>
/// Multiply by a Scalar.
/// </summary>
/// <param name="scalar">Scalar.</param>
internal ModulusPoly Multiply(int scalar)
{
if (scalar == 0)
{
return field.Zero;
}
if (scalar == 1)
{
return this;
}
int size = coefficients.Length;
int[] product = new int[size];
for (int i = 0; i < size; i++)
{
product[i] = field.Multiply(coefficients[i], scalar);
}
return new ModulusPoly(field, product);
}
/// <summary>
/// Multiplies by a Monomial
/// </summary>
/// <returns>The by monomial.</returns>
/// <param name="degree">Degree.</param>
/// <param name="coefficient">Coefficient.</param>
internal ModulusPoly MultiplyByMonomial(int degree, int coefficient)
{
if (degree < 0)
{
throw new ArgumentException();
}
if (coefficient == 0)
{
return field.Zero;
}
int size = coefficients.Length;
int[] product = new int[size + degree];
for (int i = 0; i < size; i++)
{
product[i] = field.Multiply(coefficients[i], coefficient);
}
return new ModulusPoly(field, product);
}
/// <summary>
/// Divide by another modulus
/// </summary>
/// <param name="other">Other.</param>
internal ModulusPoly[] Divide(ModulusPoly other)
{
if (!field.Equals(other.field))
{
throw new ArgumentException("ModulusPolys do not have same ModulusGF field");
}
if (other.IsZero)
{
throw new DivideByZeroException();
}
ModulusPoly quotient = field.Zero;
ModulusPoly remainder = this;
int denominatorLeadingTerm = other.GetCoefficient(other.Degree);
int inverseDenominatorLeadingTerm = field.Inverse(denominatorLeadingTerm);
while (remainder.Degree >= other.Degree && !remainder.IsZero)
{
int degreeDifference = remainder.Degree - other.Degree;
int scale = field.Multiply(remainder.GetCoefficient(remainder.Degree), inverseDenominatorLeadingTerm);
ModulusPoly term = other.MultiplyByMonomial(degreeDifference, scale);
ModulusPoly iterationQuotient = field.BuildMonomial(degreeDifference, scale);
quotient = quotient.Add(iterationQuotient);
remainder = remainder.Subtract(term);
}
return new ModulusPoly[] { quotient, remainder };
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.EC.ModulusPoly"/>.
/// </summary>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.EC.ModulusPoly"/>.</returns>
override public String ToString()
{
var result = new StringBuilder(8 * Degree);
for (int degree = Degree; degree >= 0; degree--)
{
int coefficient = GetCoefficient(degree);
if (coefficient != 0)
{
if (coefficient < 0)
{
result.Append(" - ");
coefficient = -coefficient;
} else
{
if (result.Length > 0)
{
result.Append(" + ");
}
}
if (degree == 0 || coefficient != 1)
{
result.Append(coefficient);
}
if (degree != 0)
{
if (degree == 1)
{
result.Append('x');
} else
{
result.Append("x^");
result.Append(degree);
}
}
}
}
return result.ToString();
}
}
}

View file

@ -0,0 +1,66 @@
// /*
// * Copyright 2009 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.PDF417
{
/// <summary>
/// Bit matrix extensions to assist in PDF417 Detection
/// </summary>
public static class BitMatrixExtensions
{
/// <summary>
/// Rotates the Matrix by 180 degrees in-place
/// </summary>
/// <param name="bitMatrix">Bit matrix.</param>
public static void Rotate180(this BitMatrix bitMatrix)
{
int width = bitMatrix.Width;
int height = bitMatrix.Height;
BitArray firstRowBitArray = new BitArray(width);
BitArray secondRowBitArray = new BitArray(width);
BitArray tmpBitArray = new BitArray(width); // re-use this to save on 'new' calls
for (int y = 0; y < height + 1 >> 1; y++)
{
firstRowBitArray = bitMatrix.getRow(y, firstRowBitArray);
Mirror(bitMatrix.getRow(height - 1 - y, secondRowBitArray), ref tmpBitArray);
bitMatrix.setRow(y, tmpBitArray);
Mirror(firstRowBitArray, ref tmpBitArray);
bitMatrix.setRow(height - 1 - y, tmpBitArray);
}
}
/// <summary>
/// Copies the bits from the input to the result BitArray in reverse order.
/// SF: Not sure how this is different than BitArray.Reverse();
/// </summary>
/// <param name="input">Input.</param>
/// <param name="result">Result.</param>
private static void Mirror(BitArray input, ref BitArray result)
{
result.clear();
int size = input.Size;
for (int i = 0; i < size; i++)
{
result[size - 1 - i] = input[i];
}
}
}
}

View file

@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using com.google.zxing.common;
/*
* Copyright 2009 ZXing authors
*
@ -18,560 +14,361 @@ using com.google.zxing.common;
* limitations under the License.
*/
namespace com.google.zxing.pdf417.detector
using System;
using System.Collections.Generic;
using ZXing.Common;
using ZXing.Common.Detector;
using System.Linq;
namespace ZXing.PDF417.Internal
{
/// <summary>
/// <p>Encapsulates logic that can detect a PDF417 Code in an image, even if the
/// PDF417 Code is rotated or skewed, or partially obscured.</p>
///
/// <author>SITA Lab (kevin.osullivan@sita.aero)</author>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
/// <author> Guenther Grau (Java Core) - changed this class from an instance to static methods</author>
/// <author> Stephen Furlani (C# Port)</author>
/// </summary>
public sealed class Detector
{
private static readonly int[] INDEXES_START_PATTERN = {0, 4, 1, 5};
private static readonly int[] INDEXES_STOP_PATTERN = {6, 2, 7, 3};
private static readonly int INTEGER_MATH_SHIFT = 8;
private static readonly int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
private static readonly int MAX_AVG_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
private static readonly int MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f);
using BinaryBitmap = com.google.zxing.BinaryBitmap;
using DecodeHintType = com.google.zxing.DecodeHintType;
using NotFoundException = com.google.zxing.NotFoundException;
using ResultPoint = com.google.zxing.ResultPoint;
using BitMatrix = com.google.zxing.common.BitMatrix;
using DetectorResult = com.google.zxing.common.DetectorResult;
using GridSampler = com.google.zxing.common.GridSampler;
using MathUtils = com.google.zxing.common.detector.MathUtils;
/// <summary>
/// B S B S B S B S Bar/Space pattern
/// 11111111 0 1 0 1 0 1 000.
/// </summary>
private static readonly int[] START_PATTERN = {8, 1, 1, 1, 1, 1, 1, 3};
/// <summary>
/// 1111111 0 1 000 1 0 1 00 1
/// </summary>
private static readonly int[] STOP_PATTERN = {7, 1, 1, 3, 1, 1, 1, 2, 1};
private static readonly int MAX_PIXEL_DRIFT = 3;
private static readonly int MAX_PATTERN_DRIFT = 5;
/// <summary>
/// if we set the value too low, then we don't detect the correct height of the bar if the start patterns are damaged.
/// if we set the value too high, then we might detect the start pattern from a neighbor barcode.
/// </summary>
private static readonly int SKIPPED_ROW_COUNT_MAX = 25;
/// <summary>
/// A PDF471 barcode should have at least 3 rows, with each row being >= 3 times the module width. Therefore it should be at least
/// 9 pixels tall. To be conservative, we use about half the size to ensure we don't miss it.
/// </summary>
private static readonly int ROW_STEP = 5;
private static readonly int BARCODE_MIN_HEIGHT = 10;
/// <summary>
/// <p>Detects a PDF417 Code in an image. Only checks 0 and 180 degree rotations.</p>
/// </summary>
/// <param name="image">Image.</param>
/// <param name="hints">Hints.</param>
/// <param name="multiple">If set to <c>true</c> multiple.</param>
/// <returns><see cref="PDF417DetectorResult"/> encapsulating results of detecting a PDF417 code </returns>
public static PDF417DetectorResult Detect(BinaryBitmap image,IDictionary<DecodeHintType,object> hints, bool multiple) {
// TODO detection improvement, tryHarder could try several different luminance thresholds/blackpoints or even
// different binarizers (SF: or different Skipped Row Counts/Steps?)
//boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
BitMatrix bitMatrix = image.BlackMatrix;
List<ResultPoint[]> barcodeCoordinates = Detect(multiple, bitMatrix);
if (barcodeCoordinates.Count == 0) {
bitMatrix.Rotate180();
barcodeCoordinates = Detect(multiple, bitMatrix);
}
return new PDF417DetectorResult(bitMatrix, barcodeCoordinates);
}
/// <summary>
/// Detects PDF417 codes in an image. Only checks 0 degree rotation (so rotate the matrix and check again outside of this method)
/// </summary>
/// <param name="multiple">multiple if true, then the image is searched for multiple codes. If false, then at most one code will be found and returned.</param>
/// <param name="bitMatrix">bitMatrix bit matrix to detect barcodes in.</param>
/// <returns>List of ResultPoint arrays containing the coordinates of found barcodes</returns>
private static List<ResultPoint[]> Detect(bool multiple, BitMatrix bitMatrix) {
List<ResultPoint[]> barcodeCoordinates = new List<ResultPoint[]>();
int row = 0;
int column = 0;
bool foundBarcodeInRow = false;
while (row < bitMatrix.Height) {
ResultPoint[] vertices = FindVertices(bitMatrix, row, column);
if (vertices[0] == null && vertices[3] == null) {
if (!foundBarcodeInRow) {
// we didn't find any barcode so that's the end of searching
break;
}
// we didn't find a barcode starting at the given column and row. Try again from the first column and slightly
// below the lowest barcode we found so far.
foundBarcodeInRow = false;
column = 0;
foreach (ResultPoint[] barcodeCoordinate in barcodeCoordinates) {
if (barcodeCoordinate[1] != null) {
row = (int) Math.Max(row, barcodeCoordinate[1].Y);
}
if (barcodeCoordinate[3] != null) {
row = Math.Max(row, (int) barcodeCoordinate[3].Y);
}
}
row += ROW_STEP;
continue;
}
foundBarcodeInRow = true;
barcodeCoordinates.Add(vertices);
if (!multiple) {
break;
}
// if we didn't find a right row indicator column, then continue the search for the next barcode after the
// start pattern of the barcode just found.
if (vertices[2] != null) {
column = (int) vertices[2].X;
row = (int) vertices[2].Y;
} else {
column = (int) vertices[4].X;
row = (int) vertices[4].Y;
}
}
return barcodeCoordinates;
}
/// <summary>
/// Locate the vertices and the codewords area of a black blob using the Start and Stop patterns as locators.
/// </summary>
/// <param name="matrix">Matrix.</param>
/// <param name="startRow">Start row.</param>
/// <param name="startColumn">Start column.</param>
/// <returns> an array containing the vertices:
/// vertices[0] x, y top left barcode
/// vertices[1] x, y bottom left barcode
/// vertices[2] x, y top right barcode
/// vertices[3] x, y bottom right barcode
/// vertices[4] x, y top left codeword area
/// vertices[5] x, y bottom left codeword area
/// vertices[6] x, y top right codeword area
/// vertices[7] x, y bottom right codeword area
/// </returns>
private static ResultPoint[] FindVertices(BitMatrix matrix, int startRow, int startColumn) {
int height = matrix.Height;
int width = matrix.Width;
/// <summary>
/// <p>Encapsulates logic that can detect a PDF417 Code in an image, even if the
/// PDF417 Code is rotated or skewed, or partially obscured.</p>
///
/// @author SITA Lab (kevin.osullivan@sita.aero)
/// @author dswitkin@google.com (Daniel Switkin)
/// </summary>
public sealed class Detector
{
ResultPoint[] result = new ResultPoint[8];
CopyToResult(result, FindRowsWithPattern(matrix, height, width, startRow, startColumn, START_PATTERN),
INDEXES_START_PATTERN);
if (result[4] != null) {
startColumn = (int) result[4].X;
startRow = (int) result[4].Y;
}
CopyToResult(result, FindRowsWithPattern(matrix, height, width, startRow, startColumn, STOP_PATTERN),
INDEXES_STOP_PATTERN);
return result;
}
private const int INTEGER_MATH_SHIFT = 8;
private static readonly int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
private static readonly int MAX_AVG_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
private static readonly int MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f);
private const int SKEW_THRESHOLD = 3;
/// <summary>
/// Copies the temp data to the final result
/// </summary>
/// <param name="result">Result.</param>
/// <param name="tmpResult">Temp result.</param>
/// <param name="destinationIndexes">Destination indexes.</param>
private static void CopyToResult(ResultPoint[] result, ResultPoint[] tmpResult, int[] destinationIndexes) {
for (int i = 0; i < destinationIndexes.Length; i++) {
result[destinationIndexes[i]] = tmpResult[i];
}
}
// B S B S B S B S Bar/Space pattern
// 11111111 0 1 0 1 0 1 000
private static readonly int[] START_PATTERN = {8, 1, 1, 1, 1, 1, 1, 3};
/// <summary>
/// Finds the rows with the given pattern.
/// </summary>
/// <returns>The rows with pattern.</returns>
/// <param name="matrix">Matrix.</param>
/// <param name="height">Height.</param>
/// <param name="width">Width.</param>
/// <param name="startRow">Start row.</param>
/// <param name="startColumn">Start column.</param>
/// <param name="pattern">Pattern.</param>
private static ResultPoint[] FindRowsWithPattern(
BitMatrix matrix,
int height,
int width,
int startRow,
int startColumn,
int[] pattern) {
ResultPoint[] result = new ResultPoint[4];
bool found = false;
int[] counters = new int[pattern.Length];
for (; startRow < height; startRow += ROW_STEP) {
int[] loc = FindGuardPattern(matrix, startColumn, startRow, width, false, pattern, counters);
if (loc != null) {
while (startRow > 0) {
int[] previousRowLoc = FindGuardPattern(matrix, startColumn, --startRow, width, false, pattern, counters);
if (previousRowLoc != null) {
loc = previousRowLoc;
} else {
startRow++;
break;
}
}
result[0] = new ResultPoint(loc[0], startRow);
result[1] = new ResultPoint(loc[1], startRow);
found = true;
break;
}
}
int stopRow = startRow + 1;
// Last row of the current symbol that contains pattern
if (found) {
int skippedRowCount = 0;
int[] previousRowLoc = {(int) result[0].X, (int) result[1].X};
for (; stopRow < height; stopRow++) {
int[] loc = FindGuardPattern(matrix, previousRowLoc[0], stopRow, width, false, pattern, counters);
// a found pattern is only considered to belong to the same barcode if the start and end positions
// don't differ too much. Pattern drift should be not bigger than two for consecutive rows. With
// a higher number of skipped rows drift could be larger. To keep it simple for now, we allow a slightly
// larger drift and don't check for skipped rows.
if (loc != null &&
Math.Abs(previousRowLoc[0] - loc[0]) < MAX_PATTERN_DRIFT &&
Math.Abs(previousRowLoc[1] - loc[1]) < MAX_PATTERN_DRIFT) {
previousRowLoc = loc;
skippedRowCount = 0;
} else {
if (skippedRowCount > SKIPPED_ROW_COUNT_MAX) {
break;
} else {
skippedRowCount++;
}
}
}
stopRow -= skippedRowCount + 1;
result[2] = new ResultPoint(previousRowLoc[0], stopRow);
result[3] = new ResultPoint(previousRowLoc[1], stopRow);
}
if (stopRow - startRow < BARCODE_MIN_HEIGHT) {
for (int i = 0; i < result.Length; i++) {
result[i] = null;
}
}
return result;
}
// 11111111 0 1 0 1 0 1 000
private static readonly int[] START_PATTERN_REVERSE = {3, 1, 1, 1, 1, 1, 1, 8};
// TODO use a lambda to do the counter set in-place?
//private static readonly Converter<int, int> ConvertAllToZero = new Converter<int, int>(input => {return 0;});
// 1111111 0 1 000 1 0 1 00 1
private static readonly int[] STOP_PATTERN = {7, 1, 1, 3, 1, 1, 1, 2, 1};
/// <summary>
/// Finds the guard pattern. Uses System.Linq.Enumerable.Repeat to fill in counters. This might be a performance issue?
/// </summary>
/// <returns>start/end horizontal offset of guard pattern, as an array of two ints.</returns>
/// <param name="matrix">matrix row of black/white values to search</param>
/// <param name="column">column x position to start search.</param>
/// <param name="row">row y position to start search.</param>
/// <param name="width">width the number of pixels to search on this row.</param>
/// <param name="whiteFirst">If set to <c>true</c> search the white patterns first.</param>
/// <param name="pattern">pattern of counts of number of black and white pixels that are being searched for as a pattern.</param>
/// <param name="counters">counters array of counters, as long as pattern, to re-use .</param>
private static int[] FindGuardPattern(
BitMatrix matrix,
int column,
int row,
int width,
bool whiteFirst,
int[] pattern,
int[] counters)
{
// B S B S B S B S B Bar/Space pattern
// 1111111 0 1 000 1 0 1 00 1
private static readonly int[] STOP_PATTERN_REVERSE = {1, 2, 1, 1, 1, 3, 1, 1, 7};
private readonly BinaryBitmap image;
public Detector(BinaryBitmap image)
{
this.image = image;
}
/// <summary>
/// <p>Detects a PDF417 Code in an image, simply.</p>
/// </summary>
/// <returns> <seealso cref="DetectorResult"/> encapsulating results of detecting a PDF417 Code </returns>
/// <exception cref="NotFoundException"> if no QR Code can be found </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public com.google.zxing.common.DetectorResult detect() throws com.google.zxing.NotFoundException
public DetectorResult detect()
{
return detect(null);
}
/// <summary>
/// <p>Detects a PDF417 Code in an image. Only checks 0 and 180 degree rotations.</p>
/// </summary>
/// <param name="hints"> optional hints to detector </param>
/// <returns> <seealso cref="DetectorResult"/> encapsulating results of detecting a PDF417 Code </returns>
/// <exception cref="NotFoundException"> if no PDF417 Code can be found </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public com.google.zxing.common.DetectorResult detect(java.util.Map<com.google.zxing.DecodeHintType,?> hints) throws com.google.zxing.NotFoundException
public DetectorResult detect(IDictionary<DecodeHintType, object> hints)
{
// Fetch the 1 bit matrix once up front.
BitMatrix matrix = image.BlackMatrix;
bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER);
// Try to find the vertices assuming the image is upright.
ResultPoint[] vertices = findVertices(matrix, tryHarder);
if (vertices == null)
{
// Maybe the image is rotated 180 degrees?
vertices = findVertices180(matrix, tryHarder);
if (vertices != null)
{
correctCodeWordVertices(vertices, true);
}
}
else
{
correctCodeWordVertices(vertices, false);
}
if (vertices == null)
{
throw NotFoundException.NotFoundInstance;
}
float moduleWidth = computeModuleWidth(vertices);
if (moduleWidth < 1.0f)
{
throw NotFoundException.NotFoundInstance;
}
int dimension = computeDimension(vertices[4], vertices[6], vertices[5], vertices[7], moduleWidth);
if (dimension < 1)
{
throw NotFoundException.NotFoundInstance;
}
int ydimension = computeYDimension(vertices[4], vertices[6], vertices[5], vertices[7], moduleWidth);
ydimension = ydimension > dimension ? ydimension : dimension;
// Deskew and sample image.
BitMatrix bits = sampleGrid(matrix, vertices[4], vertices[5], vertices[6], vertices[7], dimension, ydimension);
return new DetectorResult(bits, new ResultPoint[]{vertices[5], vertices[4], vertices[6], vertices[7]});
}
/// <summary>
/// Locate the vertices and the codewords area of a black blob using the Start
/// and Stop patterns as locators.
/// </summary>
/// <param name="matrix"> the scanned barcode image. </param>
/// <returns> an array containing the vertices:
/// vertices[0] x, y top left barcode
/// vertices[1] x, y bottom left barcode
/// vertices[2] x, y top right barcode
/// vertices[3] x, y bottom right barcode
/// vertices[4] x, y top left codeword area
/// vertices[5] x, y bottom left codeword area
/// vertices[6] x, y top right codeword area
/// vertices[7] x, y bottom right codeword area </returns>
private static ResultPoint[] findVertices(BitMatrix matrix, bool tryHarder)
{
int height = matrix.Height;
int width = matrix.Width;
ResultPoint[] result = new ResultPoint[8];
bool found = false;
int[] counters = new int[START_PATTERN.Length];
int rowStep = Math.Max(1, height >> (tryHarder ? 9 : 7));
// Top Left
for (int i = 0; i < height; i += rowStep)
{
int[] loc = findGuardPattern(matrix, 0, i, width, false, START_PATTERN, counters);
if (loc != null)
{
result[0] = new ResultPoint(loc[0], i);
result[4] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
// Bottom left
if (found) // Found the Top Left vertex
{
found = false;
for (int i = height - 1; i > 0; i -= rowStep)
{
int[] loc = findGuardPattern(matrix, 0, i, width, false, START_PATTERN, counters);
if (loc != null)
{
result[1] = new ResultPoint(loc[0], i);
result[5] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
}
counters = new int[STOP_PATTERN.Length];
// Top right
if (found) // Found the Bottom Left vertex
{
found = false;
for (int i = 0; i < height; i += rowStep)
{
int[] loc = findGuardPattern(matrix, 0, i, width, false, STOP_PATTERN, counters);
if (loc != null)
{
result[2] = new ResultPoint(loc[1], i);
result[6] = new ResultPoint(loc[0], i);
found = true;
break;
}
}
}
// Bottom right
if (found) // Found the Top right vertex
{
found = false;
for (int i = height - 1; i > 0; i -= rowStep)
{
int[] loc = findGuardPattern(matrix, 0, i, width, false, STOP_PATTERN, counters);
if (loc != null)
{
result[3] = new ResultPoint(loc[1], i);
result[7] = new ResultPoint(loc[0], i);
found = true;
break;
}
}
}
return found ? result : null;
}
/// <summary>
/// Locate the vertices and the codewords area of a black blob using the Start
/// and Stop patterns as locators. This assumes that the image is rotated 180
/// degrees and if it locates the start and stop patterns at it will re-map
/// the vertices for a 0 degree rotation.
/// TODO: Change assumption about barcode location.
/// </summary>
/// <param name="matrix"> the scanned barcode image. </param>
/// <returns> an array containing the vertices:
/// vertices[0] x, y top left barcode
/// vertices[1] x, y bottom left barcode
/// vertices[2] x, y top right barcode
/// vertices[3] x, y bottom right barcode
/// vertices[4] x, y top left codeword area
/// vertices[5] x, y bottom left codeword area
/// vertices[6] x, y top right codeword area
/// vertices[7] x, y bottom right codeword area </returns>
private static ResultPoint[] findVertices180(BitMatrix matrix, bool tryHarder)
{
int height = matrix.Height;
int width = matrix.Width;
int halfWidth = width >> 1;
ResultPoint[] result = new ResultPoint[8];
bool found = false;
int[] counters = new int[START_PATTERN_REVERSE.Length];
int rowStep = Math.Max(1, height >> (tryHarder ? 9 : 7));
// Top Left
for (int i = height - 1; i > 0; i -= rowStep)
{
int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE, counters);
if (loc != null)
{
result[0] = new ResultPoint(loc[1], i);
result[4] = new ResultPoint(loc[0], i);
found = true;
break;
}
}
// Bottom Left
if (found) // Found the Top Left vertex
{
found = false;
for (int i = 0; i < height; i += rowStep)
{
int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE, counters);
if (loc != null)
{
result[1] = new ResultPoint(loc[1], i);
result[5] = new ResultPoint(loc[0], i);
found = true;
break;
}
}
}
counters = new int[STOP_PATTERN_REVERSE.Length];
// Top Right
if (found) // Found the Bottom Left vertex
{
found = false;
for (int i = height - 1; i > 0; i -= rowStep)
{
int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE, counters);
if (loc != null)
{
result[2] = new ResultPoint(loc[0], i);
result[6] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
}
// Bottom Right
if (found) // Found the Top Right vertex
{
found = false;
for (int i = 0; i < height; i += rowStep)
{
int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE, counters);
if (loc != null)
{
result[3] = new ResultPoint(loc[0], i);
result[7] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
}
return found ? result : null;
}
/// <summary>
/// Because we scan horizontally to detect the start and stop patterns, the vertical component of
/// the codeword coordinates will be slightly wrong if there is any skew or rotation in the image.
/// This method moves those points back onto the edges of the theoretically perfect bounding
/// quadrilateral if needed.
/// </summary>
/// <param name="vertices"> The eight vertices located by findVertices(). </param>
private static void correctCodeWordVertices(ResultPoint[] vertices, bool upsideDown)
{
float v0x = vertices[0].X;
float v0y = vertices[0].Y;
float v2x = vertices[2].X;
float v2y = vertices[2].Y;
float v4x = vertices[4].X;
float v4y = vertices[4].Y;
float v6x = vertices[6].X;
float v6y = vertices[6].Y;
float skew = v4y - v6y;
if (upsideDown)
{
skew = -skew;
}
if (skew > SKEW_THRESHOLD)
{
// Fix v4
float deltax = v6x - v0x;
float deltay = v6y - v0y;
float delta2 = deltax * deltax + deltay * deltay;
float correction = (v4x - v0x) * deltax / delta2;
vertices[4] = new ResultPoint(v0x + correction * deltax, v0y + correction * deltay);
}
else if (-skew > SKEW_THRESHOLD)
{
// Fix v6
float deltax = v2x - v4x;
float deltay = v2y - v4y;
float delta2 = deltax * deltax + deltay * deltay;
float correction = (v2x - v6x) * deltax / delta2;
vertices[6] = new ResultPoint(v2x - correction * deltax, v2y - correction * deltay);
}
float v1x = vertices[1].X;
float v1y = vertices[1].Y;
float v3x = vertices[3].X;
float v3y = vertices[3].Y;
float v5x = vertices[5].X;
float v5y = vertices[5].Y;
float v7x = vertices[7].X;
float v7y = vertices[7].Y;
skew = v7y - v5y;
if (upsideDown)
{
skew = -skew;
}
if (skew > SKEW_THRESHOLD)
{
// Fix v5
float deltax = v7x - v1x;
float deltay = v7y - v1y;
float delta2 = deltax * deltax + deltay * deltay;
float correction = (v5x - v1x) * deltax / delta2;
vertices[5] = new ResultPoint(v1x + correction * deltax, v1y + correction * deltay);
}
else if (-skew > SKEW_THRESHOLD)
{
// Fix v7
float deltax = v3x - v5x;
float deltay = v3y - v5y;
float delta2 = deltax * deltax + deltay * deltay;
float correction = (v3x - v7x) * deltax / delta2;
vertices[7] = new ResultPoint(v3x - correction * deltax, v3y - correction * deltay);
}
}
/// <summary>
/// <p>Estimates module size (pixels in a module) based on the Start and End
/// finder patterns.</p>
/// </summary>
/// <param name="vertices"> an array of vertices:
/// vertices[0] x, y top left barcode
/// vertices[1] x, y bottom left barcode
/// vertices[2] x, y top right barcode
/// vertices[3] x, y bottom right barcode
/// vertices[4] x, y top left codeword area
/// vertices[5] x, y bottom left codeword area
/// vertices[6] x, y top right codeword area
/// vertices[7] x, y bottom right codeword area </param>
/// <returns> the module size. </returns>
private static float computeModuleWidth(ResultPoint[] vertices)
{
float pixels1 = ResultPoint.distance(vertices[0], vertices[4]);
float pixels2 = ResultPoint.distance(vertices[1], vertices[5]);
float moduleWidth1 = (pixels1 + pixels2) / (17 * 2.0f);
float pixels3 = ResultPoint.distance(vertices[6], vertices[2]);
float pixels4 = ResultPoint.distance(vertices[7], vertices[3]);
float moduleWidth2 = (pixels3 + pixels4) / (18 * 2.0f);
return (moduleWidth1 + moduleWidth2) / 2.0f;
}
/// <summary>
/// Computes the dimension (number of modules in a row) of the PDF417 Code
/// based on vertices of the codeword area and estimated module size.
/// </summary>
/// <param name="topLeft"> of codeword area </param>
/// <param name="topRight"> of codeword area </param>
/// <param name="bottomLeft"> of codeword area </param>
/// <param name="bottomRight"> of codeword are </param>
/// <param name="moduleWidth"> estimated module size </param>
/// <returns> the number of modules in a row. </returns>
private static int computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint bottomRight, float moduleWidth)
{
int topRowDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleWidth);
int bottomRowDimension = MathUtils.round(ResultPoint.distance(bottomLeft, bottomRight) / moduleWidth);
return ((((topRowDimension + bottomRowDimension) >> 1) + 8) / 17) * 17;
}
/// <summary>
/// Computes the y dimension (number of modules in a column) of the PDF417 Code
/// based on vertices of the codeword area and estimated module size.
/// </summary>
/// <param name="topLeft"> of codeword area </param>
/// <param name="topRight"> of codeword area </param>
/// <param name="bottomLeft"> of codeword area </param>
/// <param name="bottomRight"> of codeword are </param>
/// <param name="moduleWidth"> estimated module size </param>
/// <returns> the number of modules in a row. </returns>
private static int computeYDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint bottomRight, float moduleWidth)
{
int leftColumnDimension = MathUtils.round(ResultPoint.distance(topLeft, bottomLeft) / moduleWidth);
int rightColumnDimension = MathUtils.round(ResultPoint.distance(topRight, bottomRight) / moduleWidth);
return (leftColumnDimension + rightColumnDimension) >> 1;
}
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: private static com.google.zxing.common.BitMatrix sampleGrid(com.google.zxing.common.BitMatrix matrix, com.google.zxing.ResultPoint topLeft, com.google.zxing.ResultPoint bottomLeft, com.google.zxing.ResultPoint topRight, com.google.zxing.ResultPoint bottomRight, int xdimension, int ydimension) throws com.google.zxing.NotFoundException
private static BitMatrix sampleGrid(BitMatrix matrix, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight, int xdimension, int ydimension)
{
// Note that unlike the QR Code sampler, we didn't find the center of modules, but the
// very corners. So there is no 0.5f here; 0.0f is right.
GridSampler sampler = GridSampler.Instance;
return sampler.sampleGrid(matrix, xdimension, ydimension, 0.0f, 0.0f, xdimension, 0.0f, xdimension, ydimension, 0.0f, ydimension, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y); // p4FromY - p4FromX - p3FromY - p3FromX - p2FromY - p2FromX - p1FromY - p1FromX - p4ToY - p4ToX - p3ToY - p3ToX - p2ToY - p2ToX - p1ToY - p1ToX
}
/// <param name="matrix"> row of black/white values to search </param>
/// <param name="column"> x position to start search </param>
/// <param name="row"> y position to start search </param>
/// <param name="width"> the number of pixels to search on this row </param>
/// <param name="pattern"> pattern of counts of number of black and white pixels that are
/// being searched for as a pattern </param>
/// <param name="counters"> array of counters, as long as pattern, to re-use </param>
/// <returns> start/end horizontal offset of guard pattern, as an array of two ints. </returns>
private static int[] findGuardPattern(BitMatrix matrix, int column, int row, int width, bool whiteFirst, int[] pattern, int[] counters)
{
//Arrays.fill(counters, 0, counters.Length, 0);
counters.Fill(0);
int patternLength = pattern.Length;
bool isWhite = whiteFirst;
int counterPosition = 0;
int patternStart = column;
for (int x = column; x < column + width; x++)
{
bool pixel = matrix.get(x, row);
if (pixel ^ isWhite)
{
counters[counterPosition]++;
}
else
{
if (counterPosition == patternLength - 1)
{
if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE)
{
return new int[]{patternStart, x};
}
patternStart += counters[0] + counters[1];
Array.Copy(counters, 2, counters, 0, patternLength - 2);
counters[patternLength - 2] = 0;
counters[patternLength - 1] = 0;
counterPosition--;
}
else
{
counterPosition++;
}
counters[counterPosition] = 1;
isWhite = !isWhite;
}
}
return null;
}
/// <summary>
/// Determines how closely a set of observed counts of runs of black/white
/// values matches a given target pattern. This is reported as the ratio of
/// the total variance from the expected pattern proportions across all
/// pattern elements, to the length of the pattern.
/// </summary>
/// <param name="counters"> observed counters </param>
/// <param name="pattern"> expected pattern </param>
/// <param name="maxIndividualVariance"> The most any counter can differ before we give up </param>
/// <returns> ratio of total variance between counters and pattern compared to
/// total pattern size, where the ratio has been multiplied by 256.
/// So, 0 means no variance (perfect match); 256 means the total
/// variance between counters and patterns equals the pattern length,
/// higher values mean even more variance </returns>
private static int patternMatchVariance(int[] counters, int[] pattern, int maxIndividualVariance)
{
int numCounters = counters.Length;
int total = 0;
int patternLength = 0;
for (int i = 0; i < numCounters; i++)
{
total += counters[i];
patternLength += pattern[i];
}
if (total < patternLength)
{
// If we don't even have one pixel per unit of bar width, assume this
// is too small to reliably match, so fail:
return int.MaxValue;
}
// We're going to fake floating-point math in integers. We just need to use more bits.
// Scale up patternLength so that intermediate values below like scaledCounter will have
// more "significant digits".
int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> 8;
int totalVariance = 0;
for (int x = 0; x < numCounters; x++)
{
int counter = counters[x] << INTEGER_MATH_SHIFT;
int scaledPattern = pattern[x] * unitBarWidth;
int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
if (variance > maxIndividualVariance)
{
return int.MaxValue;
}
totalVariance += variance;
}
return totalVariance / total;
}
}
}
counters = Enumerable.Repeat(0, counters.Length).ToArray(); // Clear out counters. (Java.Fill equiv)
//Array.ConvertAll(counters, ConvertAllToZero);
int patternLength = pattern.Length;
bool isWhite = whiteFirst;
int patternStart = column;
int pixelDrift = 0;
// if there are black pixels left of the current pixel shift to the left, but only for MAX_PIXEL_DRIFT pixels
while (matrix[patternStart, row] && patternStart > 0 && pixelDrift++ < MAX_PIXEL_DRIFT) {
patternStart--;
}
int x = patternStart;
int counterPosition = 0;
for (; x < width; x++) {
bool pixel = matrix[x, row];
if (pixel ^ isWhite) {
counters[counterPosition]++;
} else {
if (counterPosition == patternLength - 1) {
if (PatternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
return new int[] {patternStart, x};
}
patternStart += counters[0] + counters[1];
Array.Copy(counters, 2, counters, 0, patternLength - 2);
counters[patternLength - 2] = 0;
counters[patternLength - 1] = 0;
counterPosition--;
} else {
counterPosition++;
}
counters[counterPosition] = 1;
isWhite = !isWhite;
}
}
if (counterPosition == patternLength - 1) {
if (PatternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
return new int[] {patternStart, x - 1};
}
}
return null;
}
/// <summary>
/// Determines how closely a set of observed counts of runs of black/white.
/// values matches a given target pattern. This is reported as the ratio of
/// the total variance from the expected pattern proportions across all
/// pattern elements, to the length of the pattern.
/// </summary>
/// <returns>
/// ratio of total variance between counters and pattern compared to
/// total pattern size, where the ratio has been multiplied by 256.
/// So, 0 means no variance (perfect match); 256 means the total
/// variance between counters and patterns equals the pattern length,
/// higher values mean even more variance
/// </returns>
/// <param name="counters">observed counters.</param>
/// <param name="pattern">expected pattern.</param>
/// <param name="maxIndividualVariance">The most any counter can differ before we give up.</param>
private static int PatternMatchVariance(int[] counters, int[] pattern, int maxIndividualVariance) {
int numCounters = counters.Length;
int total = 0;
int patternLength = 0;
for (int i = 0; i < numCounters; i++) {
total += counters[i];
patternLength += pattern[i];
}
if (total < patternLength) {
// If we don't even have one pixel per unit of bar width, assume this
// is too small to reliably match, so fail:
return int.MaxValue;
}
// We're going to fake floating-point math in integers. We just need to use more bits.
// Scale up patternLength so that intermediate values below like scaledCounter will have
// more "significant digits".
int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
int totalVariance = 0;
for (int x = 0; x < numCounters; x++) {
int counter = counters[x] << INTEGER_MATH_SHIFT;
int scaledPattern = pattern[x] * unitBarWidth;
int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
if (variance > maxIndividualVariance) {
return int.MaxValue;
}
totalVariance += variance;
}
return totalVariance / total;
}
}
}

View file

@ -0,0 +1,45 @@
// /*
// * Copyright 2009 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 System.Collections.Generic;
namespace ZXing.PDF417.Internal
{
/// <summary>
/// PDF 417 Detector Result class. Skipped private backing stores.
/// <author>Guenther Grau (Java Core)</author>
/// <author>Stephen Furlani (C# Port)</author>
/// </summary>
public sealed class PDF417DetectorResult
{
public BitMatrix Bits { get; private set; }
public List<ResultPoint[]> Points { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="ZXing.PDF417.Internal.PDF417DetectorResult"/> class.
/// </summary>
/// <param name="bits">Bits.</param>
/// <param name="points">Points.</param>
public PDF417DetectorResult(BitMatrix bits, List<ResultPoint[]> points)
{
this.Bits = bits;
this.Points = points;
}
}
}

View file

@ -0,0 +1,92 @@
/*
* Copyright 2011 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.PDF417.Internal
{
/// <summary>
/// Holds all of the information for a barcode in a format where it can be easily accessable
///
/// <author>Jacob Haynes</author>
/// </summary>
internal sealed class BarcodeMatrix
{
private BarcodeRow[] matrix;
private int currentRow;
private int height;
private int width;
/// <summary>
/// <param name="height">the height of the matrix (Rows)</param>
/// <param name="width">the width of the matrix (Cols)</param>
/// </summary>
internal BarcodeMatrix(int height, int width)
{
matrix = new BarcodeRow[height + 2];
//Initializes the array to the correct width
for (int i = 0, matrixLength = matrix.Length; i < matrixLength; i++)
{
matrix[i] = new BarcodeRow((width + 4) * 17 + 1);
}
this.width = width * 17;
this.height = height + 2;
this.currentRow = 0;
}
internal void set(int x, int y, sbyte value)
{
matrix[y][x] = value;
}
internal void setMatrix(int x, int y, bool black)
{
set(x, y, (sbyte)(black ? 1 : 0));
}
internal void startRow()
{
++currentRow;
}
internal BarcodeRow getCurrentRow()
{
return matrix[currentRow];
}
internal sbyte[][] getMatrix()
{
return getScaledMatrix(1, 1);
}
internal sbyte[][] getScaledMatrix(int Scale)
{
return getScaledMatrix(Scale, Scale);
}
internal sbyte[][] getScaledMatrix(int xScale, int yScale)
{
sbyte[][] matrixOut = new sbyte[height * yScale][];
for (int idx = 0; idx < height * yScale; idx++)
matrixOut[idx] = new sbyte[width * xScale];
int yMax = height*yScale;
for (int ii = 0; ii < yMax; ii++)
{
matrixOut[yMax - ii - 1] = matrix[ii/yScale].getScaledRow(xScale);
}
return matrixOut;
}
}
}

View file

@ -0,0 +1,95 @@
/*
* Copyright 2011 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.PDF417.Internal
{
/// <summary>
/// <author>Jacob Haynes</author>
/// </summary>
internal sealed class BarcodeRow
{
private sbyte[] row;
//A tacker for position in the bar
private int currentLocation;
/// <summary>
/// Creates a Barcode row of the width
///
/// @param width
/// </summary>
internal BarcodeRow(int width)
{
this.row = new sbyte[width];
currentLocation = 0;
}
/// <summary>
/// Sets a specific location in the bar
///
/// <param name="x">The location in the bar</param>
/// <param name="value">Black if true, white if false;</param>
/// </summary>
internal sbyte this[int x]
{
get { return row[x]; }
set { row[x] = value; }
}
/// <summary>
/// Sets a specific location in the bar
///
/// <param name="x">The location in the bar</param>
/// <param name="black">Black if true, white if false;</param>
/// </summary>
internal void set(int x, bool black)
{
row[x] = (sbyte)(black ? 1 : 0);
}
/// <summary>
/// <param name="black">A boolean which is true if the bar black false if it is white</param>
/// <param name="width">How many spots wide the bar is.</param>
/// </summary>
internal void addBar(bool black, int width)
{
for (int ii = 0; ii < width; ii++)
{
set(currentLocation++, black);
}
}
internal sbyte[] Row
{
get { return row; }
}
/// <summary>
/// This function scales the row
///
/// <param name="scale">How much you want the image to be scaled, must be greater than or equal to 1.</param>
/// <returns>the scaled row</returns>
/// </summary>
internal sbyte[] getScaledRow(int scale)
{
sbyte[] output = new sbyte[row.Length * scale];
for (int i = 0; i < output.Length; i++)
{
output[i] = row[i / scale];
}
return output;
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright 2011 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.PDF417.Internal
{
/// <summary>
/// PDF417 compaction mode
/// </summary>
public enum Compaction
{
/// <summary>
///
/// </summary>
AUTO,
/// <summary>
///
/// </summary>
TEXT,
/// <summary>
///
/// </summary>
BYTE,
/// <summary>
///
/// </summary>
NUMERIC
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright 2012 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.PDF417.Internal
{
/// <summary>
/// Data object to specify the minimum and maximum number of rows and columns for a PDF417 barcode.
/// @author qwandor@google.com (Andrew Walbran)
/// </summary>
public sealed class Dimensions
{
private readonly int minCols;
private readonly int maxCols;
private readonly int minRows;
private readonly int maxRows;
/// <summary>
/// Initializes a new instance of the <see cref="Dimensions"/> class.
/// </summary>
/// <param name="minCols">The min cols.</param>
/// <param name="maxCols">The max cols.</param>
/// <param name="minRows">The min rows.</param>
/// <param name="maxRows">The max rows.</param>
public Dimensions(int minCols, int maxCols, int minRows, int maxRows)
{
this.minCols = minCols;
this.maxCols = maxCols;
this.minRows = minRows;
this.maxRows = maxRows;
}
/// <summary>
/// Gets the min cols.
/// </summary>
public int MinCols
{
get { return minCols; }
}
/// <summary>
/// Gets the max cols.
/// </summary>
public int MaxCols
{
get { return maxCols; }
}
/// <summary>
/// Gets the min rows.
/// </summary>
public int MinRows
{
get { return minRows; }
}
/// <summary>
/// Gets the max rows.
/// </summary>
public int MaxRows
{
get { return maxRows; }
}
}
}

View file

@ -0,0 +1,795 @@
/*
* Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part
*
* 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.
*/
/*
* This file has been modified from its original form in Barcode4J.
*/
using System;
using System.Text;
namespace ZXing.PDF417.Internal
{
/// <summary>
/// Top-level class for the logic part of the PDF417 implementation.
/// </summary>
sealed class PDF417
{
/// <summary>
/// The start pattern (17 bits)
/// </summary>
private const int START_PATTERN = 0x1fea8;
/// <summary>
/// The stop pattern (18 bits)
/// </summary>
private const int STOP_PATTERN = 0x3fa29;
/// <summary>
/// The codeword table from the Annex A of ISO/IEC 15438:2001(E).
/// </summary>
private static readonly int[][] CODEWORD_TABLE = {
new[]
{
0x1d5c0, 0x1eaf0, 0x1f57c, 0x1d4e0, 0x1ea78, 0x1f53e,
0x1a8c0, 0x1d470, 0x1a860, 0x15040, 0x1a830, 0x15020,
0x1adc0, 0x1d6f0, 0x1eb7c, 0x1ace0, 0x1d678, 0x1eb3e,
0x158c0, 0x1ac70, 0x15860, 0x15dc0, 0x1aef0, 0x1d77c,
0x15ce0, 0x1ae78, 0x1d73e, 0x15c70, 0x1ae3c, 0x15ef0,
0x1af7c, 0x15e78, 0x1af3e, 0x15f7c, 0x1f5fa, 0x1d2e0,
0x1e978, 0x1f4be, 0x1a4c0, 0x1d270, 0x1e93c, 0x1a460,
0x1d238, 0x14840, 0x1a430, 0x1d21c, 0x14820, 0x1a418,
0x14810, 0x1a6e0, 0x1d378, 0x1e9be, 0x14cc0, 0x1a670,
0x1d33c, 0x14c60, 0x1a638, 0x1d31e, 0x14c30, 0x1a61c,
0x14ee0, 0x1a778, 0x1d3be, 0x14e70, 0x1a73c, 0x14e38,
0x1a71e, 0x14f78, 0x1a7be, 0x14f3c, 0x14f1e, 0x1a2c0,
0x1d170, 0x1e8bc, 0x1a260, 0x1d138, 0x1e89e, 0x14440,
0x1a230, 0x1d11c, 0x14420, 0x1a218, 0x14410, 0x14408,
0x146c0, 0x1a370, 0x1d1bc, 0x14660, 0x1a338, 0x1d19e,
0x14630, 0x1a31c, 0x14618, 0x1460c, 0x14770, 0x1a3bc,
0x14738, 0x1a39e, 0x1471c, 0x147bc, 0x1a160, 0x1d0b8,
0x1e85e, 0x14240, 0x1a130, 0x1d09c, 0x14220, 0x1a118,
0x1d08e, 0x14210, 0x1a10c, 0x14208, 0x1a106, 0x14360,
0x1a1b8, 0x1d0de, 0x14330, 0x1a19c, 0x14318, 0x1a18e,
0x1430c, 0x14306, 0x1a1de, 0x1438e, 0x14140, 0x1a0b0,
0x1d05c, 0x14120, 0x1a098, 0x1d04e, 0x14110, 0x1a08c,
0x14108, 0x1a086, 0x14104, 0x141b0, 0x14198, 0x1418c,
0x140a0, 0x1d02e, 0x1a04c, 0x1a046, 0x14082, 0x1cae0,
0x1e578, 0x1f2be, 0x194c0, 0x1ca70, 0x1e53c, 0x19460,
0x1ca38, 0x1e51e, 0x12840, 0x19430, 0x12820, 0x196e0,
0x1cb78, 0x1e5be, 0x12cc0, 0x19670, 0x1cb3c, 0x12c60,
0x19638, 0x12c30, 0x12c18, 0x12ee0, 0x19778, 0x1cbbe,
0x12e70, 0x1973c, 0x12e38, 0x12e1c, 0x12f78, 0x197be,
0x12f3c, 0x12fbe, 0x1dac0, 0x1ed70, 0x1f6bc, 0x1da60,
0x1ed38, 0x1f69e, 0x1b440, 0x1da30, 0x1ed1c, 0x1b420,
0x1da18, 0x1ed0e, 0x1b410, 0x1da0c, 0x192c0, 0x1c970,
0x1e4bc, 0x1b6c0, 0x19260, 0x1c938, 0x1e49e, 0x1b660,
0x1db38, 0x1ed9e, 0x16c40, 0x12420, 0x19218, 0x1c90e,
0x16c20, 0x1b618, 0x16c10, 0x126c0, 0x19370, 0x1c9bc,
0x16ec0, 0x12660, 0x19338, 0x1c99e, 0x16e60, 0x1b738,
0x1db9e, 0x16e30, 0x12618, 0x16e18, 0x12770, 0x193bc,
0x16f70, 0x12738, 0x1939e, 0x16f38, 0x1b79e, 0x16f1c,
0x127bc, 0x16fbc, 0x1279e, 0x16f9e, 0x1d960, 0x1ecb8,
0x1f65e, 0x1b240, 0x1d930, 0x1ec9c, 0x1b220, 0x1d918,
0x1ec8e, 0x1b210, 0x1d90c, 0x1b208, 0x1b204, 0x19160,
0x1c8b8, 0x1e45e, 0x1b360, 0x19130, 0x1c89c, 0x16640,
0x12220, 0x1d99c, 0x1c88e, 0x16620, 0x12210, 0x1910c,
0x16610, 0x1b30c, 0x19106, 0x12204, 0x12360, 0x191b8,
0x1c8de, 0x16760, 0x12330, 0x1919c, 0x16730, 0x1b39c,
0x1918e, 0x16718, 0x1230c, 0x12306, 0x123b8, 0x191de,
0x167b8, 0x1239c, 0x1679c, 0x1238e, 0x1678e, 0x167de,
0x1b140, 0x1d8b0, 0x1ec5c, 0x1b120, 0x1d898, 0x1ec4e,
0x1b110, 0x1d88c, 0x1b108, 0x1d886, 0x1b104, 0x1b102,
0x12140, 0x190b0, 0x1c85c, 0x16340, 0x12120, 0x19098,
0x1c84e, 0x16320, 0x1b198, 0x1d8ce, 0x16310, 0x12108,
0x19086, 0x16308, 0x1b186, 0x16304, 0x121b0, 0x190dc,
0x163b0, 0x12198, 0x190ce, 0x16398, 0x1b1ce, 0x1638c,
0x12186, 0x16386, 0x163dc, 0x163ce, 0x1b0a0, 0x1d858,
0x1ec2e, 0x1b090, 0x1d84c, 0x1b088, 0x1d846, 0x1b084,
0x1b082, 0x120a0, 0x19058, 0x1c82e, 0x161a0, 0x12090,
0x1904c, 0x16190, 0x1b0cc, 0x19046, 0x16188, 0x12084,
0x16184, 0x12082, 0x120d8, 0x161d8, 0x161cc, 0x161c6,
0x1d82c, 0x1d826, 0x1b042, 0x1902c, 0x12048, 0x160c8,
0x160c4, 0x160c2, 0x18ac0, 0x1c570, 0x1e2bc, 0x18a60,
0x1c538, 0x11440, 0x18a30, 0x1c51c, 0x11420, 0x18a18,
0x11410, 0x11408, 0x116c0, 0x18b70, 0x1c5bc, 0x11660,
0x18b38, 0x1c59e, 0x11630, 0x18b1c, 0x11618, 0x1160c,
0x11770, 0x18bbc, 0x11738, 0x18b9e, 0x1171c, 0x117bc,
0x1179e, 0x1cd60, 0x1e6b8, 0x1f35e, 0x19a40, 0x1cd30,
0x1e69c, 0x19a20, 0x1cd18, 0x1e68e, 0x19a10, 0x1cd0c,
0x19a08, 0x1cd06, 0x18960, 0x1c4b8, 0x1e25e, 0x19b60,
0x18930, 0x1c49c, 0x13640, 0x11220, 0x1cd9c, 0x1c48e,
0x13620, 0x19b18, 0x1890c, 0x13610, 0x11208, 0x13608,
0x11360, 0x189b8, 0x1c4de, 0x13760, 0x11330, 0x1cdde,
0x13730, 0x19b9c, 0x1898e, 0x13718, 0x1130c, 0x1370c,
0x113b8, 0x189de, 0x137b8, 0x1139c, 0x1379c, 0x1138e,
0x113de, 0x137de, 0x1dd40, 0x1eeb0, 0x1f75c, 0x1dd20,
0x1ee98, 0x1f74e, 0x1dd10, 0x1ee8c, 0x1dd08, 0x1ee86,
0x1dd04, 0x19940, 0x1ccb0, 0x1e65c, 0x1bb40, 0x19920,
0x1eedc, 0x1e64e, 0x1bb20, 0x1dd98, 0x1eece, 0x1bb10,
0x19908, 0x1cc86, 0x1bb08, 0x1dd86, 0x19902, 0x11140,
0x188b0, 0x1c45c, 0x13340, 0x11120, 0x18898, 0x1c44e,
0x17740, 0x13320, 0x19998, 0x1ccce, 0x17720, 0x1bb98,
0x1ddce, 0x18886, 0x17710, 0x13308, 0x19986, 0x17708,
0x11102, 0x111b0, 0x188dc, 0x133b0, 0x11198, 0x188ce,
0x177b0, 0x13398, 0x199ce, 0x17798, 0x1bbce, 0x11186,
0x13386, 0x111dc, 0x133dc, 0x111ce, 0x177dc, 0x133ce,
0x1dca0, 0x1ee58, 0x1f72e, 0x1dc90, 0x1ee4c, 0x1dc88,
0x1ee46, 0x1dc84, 0x1dc82, 0x198a0, 0x1cc58, 0x1e62e,
0x1b9a0, 0x19890, 0x1ee6e, 0x1b990, 0x1dccc, 0x1cc46,
0x1b988, 0x19884, 0x1b984, 0x19882, 0x1b982, 0x110a0,
0x18858, 0x1c42e, 0x131a0, 0x11090, 0x1884c, 0x173a0,
0x13190, 0x198cc, 0x18846, 0x17390, 0x1b9cc, 0x11084,
0x17388, 0x13184, 0x11082, 0x13182, 0x110d8, 0x1886e,
0x131d8, 0x110cc, 0x173d8, 0x131cc, 0x110c6, 0x173cc,
0x131c6, 0x110ee, 0x173ee, 0x1dc50, 0x1ee2c, 0x1dc48,
0x1ee26, 0x1dc44, 0x1dc42, 0x19850, 0x1cc2c, 0x1b8d0,
0x19848, 0x1cc26, 0x1b8c8, 0x1dc66, 0x1b8c4, 0x19842,
0x1b8c2, 0x11050, 0x1882c, 0x130d0, 0x11048, 0x18826,
0x171d0, 0x130c8, 0x19866, 0x171c8, 0x1b8e6, 0x11042,
0x171c4, 0x130c2, 0x171c2, 0x130ec, 0x171ec, 0x171e6,
0x1ee16, 0x1dc22, 0x1cc16, 0x19824, 0x19822, 0x11028,
0x13068, 0x170e8, 0x11022, 0x13062, 0x18560, 0x10a40,
0x18530, 0x10a20, 0x18518, 0x1c28e, 0x10a10, 0x1850c,
0x10a08, 0x18506, 0x10b60, 0x185b8, 0x1c2de, 0x10b30,
0x1859c, 0x10b18, 0x1858e, 0x10b0c, 0x10b06, 0x10bb8,
0x185de, 0x10b9c, 0x10b8e, 0x10bde, 0x18d40, 0x1c6b0,
0x1e35c, 0x18d20, 0x1c698, 0x18d10, 0x1c68c, 0x18d08,
0x1c686, 0x18d04, 0x10940, 0x184b0, 0x1c25c, 0x11b40,
0x10920, 0x1c6dc, 0x1c24e, 0x11b20, 0x18d98, 0x1c6ce,
0x11b10, 0x10908, 0x18486, 0x11b08, 0x18d86, 0x10902,
0x109b0, 0x184dc, 0x11bb0, 0x10998, 0x184ce, 0x11b98,
0x18dce, 0x11b8c, 0x10986, 0x109dc, 0x11bdc, 0x109ce,
0x11bce, 0x1cea0, 0x1e758, 0x1f3ae, 0x1ce90, 0x1e74c,
0x1ce88, 0x1e746, 0x1ce84, 0x1ce82, 0x18ca0, 0x1c658,
0x19da0, 0x18c90, 0x1c64c, 0x19d90, 0x1cecc, 0x1c646,
0x19d88, 0x18c84, 0x19d84, 0x18c82, 0x19d82, 0x108a0,
0x18458, 0x119a0, 0x10890, 0x1c66e, 0x13ba0, 0x11990,
0x18ccc, 0x18446, 0x13b90, 0x19dcc, 0x10884, 0x13b88,
0x11984, 0x10882, 0x11982, 0x108d8, 0x1846e, 0x119d8,
0x108cc, 0x13bd8, 0x119cc, 0x108c6, 0x13bcc, 0x119c6,
0x108ee, 0x119ee, 0x13bee, 0x1ef50, 0x1f7ac, 0x1ef48,
0x1f7a6, 0x1ef44, 0x1ef42, 0x1ce50, 0x1e72c, 0x1ded0,
0x1ef6c, 0x1e726, 0x1dec8, 0x1ef66, 0x1dec4, 0x1ce42,
0x1dec2, 0x18c50, 0x1c62c, 0x19cd0, 0x18c48, 0x1c626,
0x1bdd0, 0x19cc8, 0x1ce66, 0x1bdc8, 0x1dee6, 0x18c42,
0x1bdc4, 0x19cc2, 0x1bdc2, 0x10850, 0x1842c, 0x118d0,
0x10848, 0x18426, 0x139d0, 0x118c8, 0x18c66, 0x17bd0,
0x139c8, 0x19ce6, 0x10842, 0x17bc8, 0x1bde6, 0x118c2,
0x17bc4, 0x1086c, 0x118ec, 0x10866, 0x139ec, 0x118e6,
0x17bec, 0x139e6, 0x17be6, 0x1ef28, 0x1f796, 0x1ef24,
0x1ef22, 0x1ce28, 0x1e716, 0x1de68, 0x1ef36, 0x1de64,
0x1ce22, 0x1de62, 0x18c28, 0x1c616, 0x19c68, 0x18c24,
0x1bce8, 0x19c64, 0x18c22, 0x1bce4, 0x19c62, 0x1bce2,
0x10828, 0x18416, 0x11868, 0x18c36, 0x138e8, 0x11864,
0x10822, 0x179e8, 0x138e4, 0x11862, 0x179e4, 0x138e2,
0x179e2, 0x11876, 0x179f6, 0x1ef12, 0x1de34, 0x1de32,
0x19c34, 0x1bc74, 0x1bc72, 0x11834, 0x13874, 0x178f4,
0x178f2, 0x10540, 0x10520, 0x18298, 0x10510, 0x10508,
0x10504, 0x105b0, 0x10598, 0x1058c, 0x10586, 0x105dc,
0x105ce, 0x186a0, 0x18690, 0x1c34c, 0x18688, 0x1c346,
0x18684, 0x18682, 0x104a0, 0x18258, 0x10da0, 0x186d8,
0x1824c, 0x10d90, 0x186cc, 0x10d88, 0x186c6, 0x10d84,
0x10482, 0x10d82, 0x104d8, 0x1826e, 0x10dd8, 0x186ee,
0x10dcc, 0x104c6, 0x10dc6, 0x104ee, 0x10dee, 0x1c750,
0x1c748, 0x1c744, 0x1c742, 0x18650, 0x18ed0, 0x1c76c,
0x1c326, 0x18ec8, 0x1c766, 0x18ec4, 0x18642, 0x18ec2,
0x10450, 0x10cd0, 0x10448, 0x18226, 0x11dd0, 0x10cc8,
0x10444, 0x11dc8, 0x10cc4, 0x10442, 0x11dc4, 0x10cc2,
0x1046c, 0x10cec, 0x10466, 0x11dec, 0x10ce6, 0x11de6,
0x1e7a8, 0x1e7a4, 0x1e7a2, 0x1c728, 0x1cf68, 0x1e7b6,
0x1cf64, 0x1c722, 0x1cf62, 0x18628, 0x1c316, 0x18e68,
0x1c736, 0x19ee8, 0x18e64, 0x18622, 0x19ee4, 0x18e62,
0x19ee2, 0x10428, 0x18216, 0x10c68, 0x18636, 0x11ce8,
0x10c64, 0x10422, 0x13de8, 0x11ce4, 0x10c62, 0x13de4,
0x11ce2, 0x10436, 0x10c76, 0x11cf6, 0x13df6, 0x1f7d4,
0x1f7d2, 0x1e794, 0x1efb4, 0x1e792, 0x1efb2, 0x1c714,
0x1cf34, 0x1c712, 0x1df74, 0x1cf32, 0x1df72, 0x18614,
0x18e34, 0x18612, 0x19e74, 0x18e32, 0x1bef4
},
new[]
{
0x1f560, 0x1fab8, 0x1ea40, 0x1f530, 0x1fa9c, 0x1ea20,
0x1f518, 0x1fa8e, 0x1ea10, 0x1f50c, 0x1ea08, 0x1f506,
0x1ea04, 0x1eb60, 0x1f5b8, 0x1fade, 0x1d640, 0x1eb30,
0x1f59c, 0x1d620, 0x1eb18, 0x1f58e, 0x1d610, 0x1eb0c,
0x1d608, 0x1eb06, 0x1d604, 0x1d760, 0x1ebb8, 0x1f5de,
0x1ae40, 0x1d730, 0x1eb9c, 0x1ae20, 0x1d718, 0x1eb8e,
0x1ae10, 0x1d70c, 0x1ae08, 0x1d706, 0x1ae04, 0x1af60,
0x1d7b8, 0x1ebde, 0x15e40, 0x1af30, 0x1d79c, 0x15e20,
0x1af18, 0x1d78e, 0x15e10, 0x1af0c, 0x15e08, 0x1af06,
0x15f60, 0x1afb8, 0x1d7de, 0x15f30, 0x1af9c, 0x15f18,
0x1af8e, 0x15f0c, 0x15fb8, 0x1afde, 0x15f9c, 0x15f8e,
0x1e940, 0x1f4b0, 0x1fa5c, 0x1e920, 0x1f498, 0x1fa4e,
0x1e910, 0x1f48c, 0x1e908, 0x1f486, 0x1e904, 0x1e902,
0x1d340, 0x1e9b0, 0x1f4dc, 0x1d320, 0x1e998, 0x1f4ce,
0x1d310, 0x1e98c, 0x1d308, 0x1e986, 0x1d304, 0x1d302,
0x1a740, 0x1d3b0, 0x1e9dc, 0x1a720, 0x1d398, 0x1e9ce,
0x1a710, 0x1d38c, 0x1a708, 0x1d386, 0x1a704, 0x1a702,
0x14f40, 0x1a7b0, 0x1d3dc, 0x14f20, 0x1a798, 0x1d3ce,
0x14f10, 0x1a78c, 0x14f08, 0x1a786, 0x14f04, 0x14fb0,
0x1a7dc, 0x14f98, 0x1a7ce, 0x14f8c, 0x14f86, 0x14fdc,
0x14fce, 0x1e8a0, 0x1f458, 0x1fa2e, 0x1e890, 0x1f44c,
0x1e888, 0x1f446, 0x1e884, 0x1e882, 0x1d1a0, 0x1e8d8,
0x1f46e, 0x1d190, 0x1e8cc, 0x1d188, 0x1e8c6, 0x1d184,
0x1d182, 0x1a3a0, 0x1d1d8, 0x1e8ee, 0x1a390, 0x1d1cc,
0x1a388, 0x1d1c6, 0x1a384, 0x1a382, 0x147a0, 0x1a3d8,
0x1d1ee, 0x14790, 0x1a3cc, 0x14788, 0x1a3c6, 0x14784,
0x14782, 0x147d8, 0x1a3ee, 0x147cc, 0x147c6, 0x147ee,
0x1e850, 0x1f42c, 0x1e848, 0x1f426, 0x1e844, 0x1e842,
0x1d0d0, 0x1e86c, 0x1d0c8, 0x1e866, 0x1d0c4, 0x1d0c2,
0x1a1d0, 0x1d0ec, 0x1a1c8, 0x1d0e6, 0x1a1c4, 0x1a1c2,
0x143d0, 0x1a1ec, 0x143c8, 0x1a1e6, 0x143c4, 0x143c2,
0x143ec, 0x143e6, 0x1e828, 0x1f416, 0x1e824, 0x1e822,
0x1d068, 0x1e836, 0x1d064, 0x1d062, 0x1a0e8, 0x1d076,
0x1a0e4, 0x1a0e2, 0x141e8, 0x1a0f6, 0x141e4, 0x141e2,
0x1e814, 0x1e812, 0x1d034, 0x1d032, 0x1a074, 0x1a072,
0x1e540, 0x1f2b0, 0x1f95c, 0x1e520, 0x1f298, 0x1f94e,
0x1e510, 0x1f28c, 0x1e508, 0x1f286, 0x1e504, 0x1e502,
0x1cb40, 0x1e5b0, 0x1f2dc, 0x1cb20, 0x1e598, 0x1f2ce,
0x1cb10, 0x1e58c, 0x1cb08, 0x1e586, 0x1cb04, 0x1cb02,
0x19740, 0x1cbb0, 0x1e5dc, 0x19720, 0x1cb98, 0x1e5ce,
0x19710, 0x1cb8c, 0x19708, 0x1cb86, 0x19704, 0x19702,
0x12f40, 0x197b0, 0x1cbdc, 0x12f20, 0x19798, 0x1cbce,
0x12f10, 0x1978c, 0x12f08, 0x19786, 0x12f04, 0x12fb0,
0x197dc, 0x12f98, 0x197ce, 0x12f8c, 0x12f86, 0x12fdc,
0x12fce, 0x1f6a0, 0x1fb58, 0x16bf0, 0x1f690, 0x1fb4c,
0x169f8, 0x1f688, 0x1fb46, 0x168fc, 0x1f684, 0x1f682,
0x1e4a0, 0x1f258, 0x1f92e, 0x1eda0, 0x1e490, 0x1fb6e,
0x1ed90, 0x1f6cc, 0x1f246, 0x1ed88, 0x1e484, 0x1ed84,
0x1e482, 0x1ed82, 0x1c9a0, 0x1e4d8, 0x1f26e, 0x1dba0,
0x1c990, 0x1e4cc, 0x1db90, 0x1edcc, 0x1e4c6, 0x1db88,
0x1c984, 0x1db84, 0x1c982, 0x1db82, 0x193a0, 0x1c9d8,
0x1e4ee, 0x1b7a0, 0x19390, 0x1c9cc, 0x1b790, 0x1dbcc,
0x1c9c6, 0x1b788, 0x19384, 0x1b784, 0x19382, 0x1b782,
0x127a0, 0x193d8, 0x1c9ee, 0x16fa0, 0x12790, 0x193cc,
0x16f90, 0x1b7cc, 0x193c6, 0x16f88, 0x12784, 0x16f84,
0x12782, 0x127d8, 0x193ee, 0x16fd8, 0x127cc, 0x16fcc,
0x127c6, 0x16fc6, 0x127ee, 0x1f650, 0x1fb2c, 0x165f8,
0x1f648, 0x1fb26, 0x164fc, 0x1f644, 0x1647e, 0x1f642,
0x1e450, 0x1f22c, 0x1ecd0, 0x1e448, 0x1f226, 0x1ecc8,
0x1f666, 0x1ecc4, 0x1e442, 0x1ecc2, 0x1c8d0, 0x1e46c,
0x1d9d0, 0x1c8c8, 0x1e466, 0x1d9c8, 0x1ece6, 0x1d9c4,
0x1c8c2, 0x1d9c2, 0x191d0, 0x1c8ec, 0x1b3d0, 0x191c8,
0x1c8e6, 0x1b3c8, 0x1d9e6, 0x1b3c4, 0x191c2, 0x1b3c2,
0x123d0, 0x191ec, 0x167d0, 0x123c8, 0x191e6, 0x167c8,
0x1b3e6, 0x167c4, 0x123c2, 0x167c2, 0x123ec, 0x167ec,
0x123e6, 0x167e6, 0x1f628, 0x1fb16, 0x162fc, 0x1f624,
0x1627e, 0x1f622, 0x1e428, 0x1f216, 0x1ec68, 0x1f636,
0x1ec64, 0x1e422, 0x1ec62, 0x1c868, 0x1e436, 0x1d8e8,
0x1c864, 0x1d8e4, 0x1c862, 0x1d8e2, 0x190e8, 0x1c876,
0x1b1e8, 0x1d8f6, 0x1b1e4, 0x190e2, 0x1b1e2, 0x121e8,
0x190f6, 0x163e8, 0x121e4, 0x163e4, 0x121e2, 0x163e2,
0x121f6, 0x163f6, 0x1f614, 0x1617e, 0x1f612, 0x1e414,
0x1ec34, 0x1e412, 0x1ec32, 0x1c834, 0x1d874, 0x1c832,
0x1d872, 0x19074, 0x1b0f4, 0x19072, 0x1b0f2, 0x120f4,
0x161f4, 0x120f2, 0x161f2, 0x1f60a, 0x1e40a, 0x1ec1a,
0x1c81a, 0x1d83a, 0x1903a, 0x1b07a, 0x1e2a0, 0x1f158,
0x1f8ae, 0x1e290, 0x1f14c, 0x1e288, 0x1f146, 0x1e284,
0x1e282, 0x1c5a0, 0x1e2d8, 0x1f16e, 0x1c590, 0x1e2cc,
0x1c588, 0x1e2c6, 0x1c584, 0x1c582, 0x18ba0, 0x1c5d8,
0x1e2ee, 0x18b90, 0x1c5cc, 0x18b88, 0x1c5c6, 0x18b84,
0x18b82, 0x117a0, 0x18bd8, 0x1c5ee, 0x11790, 0x18bcc,
0x11788, 0x18bc6, 0x11784, 0x11782, 0x117d8, 0x18bee,
0x117cc, 0x117c6, 0x117ee, 0x1f350, 0x1f9ac, 0x135f8,
0x1f348, 0x1f9a6, 0x134fc, 0x1f344, 0x1347e, 0x1f342,
0x1e250, 0x1f12c, 0x1e6d0, 0x1e248, 0x1f126, 0x1e6c8,
0x1f366, 0x1e6c4, 0x1e242, 0x1e6c2, 0x1c4d0, 0x1e26c,
0x1cdd0, 0x1c4c8, 0x1e266, 0x1cdc8, 0x1e6e6, 0x1cdc4,
0x1c4c2, 0x1cdc2, 0x189d0, 0x1c4ec, 0x19bd0, 0x189c8,
0x1c4e6, 0x19bc8, 0x1cde6, 0x19bc4, 0x189c2, 0x19bc2,
0x113d0, 0x189ec, 0x137d0, 0x113c8, 0x189e6, 0x137c8,
0x19be6, 0x137c4, 0x113c2, 0x137c2, 0x113ec, 0x137ec,
0x113e6, 0x137e6, 0x1fba8, 0x175f0, 0x1bafc, 0x1fba4,
0x174f8, 0x1ba7e, 0x1fba2, 0x1747c, 0x1743e, 0x1f328,
0x1f996, 0x132fc, 0x1f768, 0x1fbb6, 0x176fc, 0x1327e,
0x1f764, 0x1f322, 0x1767e, 0x1f762, 0x1e228, 0x1f116,
0x1e668, 0x1e224, 0x1eee8, 0x1f776, 0x1e222, 0x1eee4,
0x1e662, 0x1eee2, 0x1c468, 0x1e236, 0x1cce8, 0x1c464,
0x1dde8, 0x1cce4, 0x1c462, 0x1dde4, 0x1cce2, 0x1dde2,
0x188e8, 0x1c476, 0x199e8, 0x188e4, 0x1bbe8, 0x199e4,
0x188e2, 0x1bbe4, 0x199e2, 0x1bbe2, 0x111e8, 0x188f6,
0x133e8, 0x111e4, 0x177e8, 0x133e4, 0x111e2, 0x177e4,
0x133e2, 0x177e2, 0x111f6, 0x133f6, 0x1fb94, 0x172f8,
0x1b97e, 0x1fb92, 0x1727c, 0x1723e, 0x1f314, 0x1317e,
0x1f734, 0x1f312, 0x1737e, 0x1f732, 0x1e214, 0x1e634,
0x1e212, 0x1ee74, 0x1e632, 0x1ee72, 0x1c434, 0x1cc74,
0x1c432, 0x1dcf4, 0x1cc72, 0x1dcf2, 0x18874, 0x198f4,
0x18872, 0x1b9f4, 0x198f2, 0x1b9f2, 0x110f4, 0x131f4,
0x110f2, 0x173f4, 0x131f2, 0x173f2, 0x1fb8a, 0x1717c,
0x1713e, 0x1f30a, 0x1f71a, 0x1e20a, 0x1e61a, 0x1ee3a,
0x1c41a, 0x1cc3a, 0x1dc7a, 0x1883a, 0x1987a, 0x1b8fa,
0x1107a, 0x130fa, 0x171fa, 0x170be, 0x1e150, 0x1f0ac,
0x1e148, 0x1f0a6, 0x1e144, 0x1e142, 0x1c2d0, 0x1e16c,
0x1c2c8, 0x1e166, 0x1c2c4, 0x1c2c2, 0x185d0, 0x1c2ec,
0x185c8, 0x1c2e6, 0x185c4, 0x185c2, 0x10bd0, 0x185ec,
0x10bc8, 0x185e6, 0x10bc4, 0x10bc2, 0x10bec, 0x10be6,
0x1f1a8, 0x1f8d6, 0x11afc, 0x1f1a4, 0x11a7e, 0x1f1a2,
0x1e128, 0x1f096, 0x1e368, 0x1e124, 0x1e364, 0x1e122,
0x1e362, 0x1c268, 0x1e136, 0x1c6e8, 0x1c264, 0x1c6e4,
0x1c262, 0x1c6e2, 0x184e8, 0x1c276, 0x18de8, 0x184e4,
0x18de4, 0x184e2, 0x18de2, 0x109e8, 0x184f6, 0x11be8,
0x109e4, 0x11be4, 0x109e2, 0x11be2, 0x109f6, 0x11bf6,
0x1f9d4, 0x13af8, 0x19d7e, 0x1f9d2, 0x13a7c, 0x13a3e,
0x1f194, 0x1197e, 0x1f3b4, 0x1f192, 0x13b7e, 0x1f3b2,
0x1e114, 0x1e334, 0x1e112, 0x1e774, 0x1e332, 0x1e772,
0x1c234, 0x1c674, 0x1c232, 0x1cef4, 0x1c672, 0x1cef2,
0x18474, 0x18cf4, 0x18472, 0x19df4, 0x18cf2, 0x19df2,
0x108f4, 0x119f4, 0x108f2, 0x13bf4, 0x119f2, 0x13bf2,
0x17af0, 0x1bd7c, 0x17a78, 0x1bd3e, 0x17a3c, 0x17a1e,
0x1f9ca, 0x1397c, 0x1fbda, 0x17b7c, 0x1393e, 0x17b3e,
0x1f18a, 0x1f39a, 0x1f7ba, 0x1e10a, 0x1e31a, 0x1e73a,
0x1ef7a, 0x1c21a, 0x1c63a, 0x1ce7a, 0x1defa, 0x1843a,
0x18c7a, 0x19cfa, 0x1bdfa, 0x1087a, 0x118fa, 0x139fa,
0x17978, 0x1bcbe, 0x1793c, 0x1791e, 0x138be, 0x179be,
0x178bc, 0x1789e, 0x1785e, 0x1e0a8, 0x1e0a4, 0x1e0a2,
0x1c168, 0x1e0b6, 0x1c164, 0x1c162, 0x182e8, 0x1c176,
0x182e4, 0x182e2, 0x105e8, 0x182f6, 0x105e4, 0x105e2,
0x105f6, 0x1f0d4, 0x10d7e, 0x1f0d2, 0x1e094, 0x1e1b4,
0x1e092, 0x1e1b2, 0x1c134, 0x1c374, 0x1c132, 0x1c372,
0x18274, 0x186f4, 0x18272, 0x186f2, 0x104f4, 0x10df4,
0x104f2, 0x10df2, 0x1f8ea, 0x11d7c, 0x11d3e, 0x1f0ca,
0x1f1da, 0x1e08a, 0x1e19a, 0x1e3ba, 0x1c11a, 0x1c33a,
0x1c77a, 0x1823a, 0x1867a, 0x18efa, 0x1047a, 0x10cfa,
0x11dfa, 0x13d78, 0x19ebe, 0x13d3c, 0x13d1e, 0x11cbe,
0x13dbe, 0x17d70, 0x1bebc, 0x17d38, 0x1be9e, 0x17d1c,
0x17d0e, 0x13cbc, 0x17dbc, 0x13c9e, 0x17d9e, 0x17cb8,
0x1be5e, 0x17c9c, 0x17c8e, 0x13c5e, 0x17cde, 0x17c5c,
0x17c4e, 0x17c2e, 0x1c0b4, 0x1c0b2, 0x18174, 0x18172,
0x102f4, 0x102f2, 0x1e0da, 0x1c09a, 0x1c1ba, 0x1813a,
0x1837a, 0x1027a, 0x106fa, 0x10ebe, 0x11ebc, 0x11e9e,
0x13eb8, 0x19f5e, 0x13e9c, 0x13e8e, 0x11e5e, 0x13ede,
0x17eb0, 0x1bf5c, 0x17e98, 0x1bf4e, 0x17e8c, 0x17e86,
0x13e5c, 0x17edc, 0x13e4e, 0x17ece, 0x17e58, 0x1bf2e,
0x17e4c, 0x17e46, 0x13e2e, 0x17e6e, 0x17e2c, 0x17e26,
0x10f5e, 0x11f5c, 0x11f4e, 0x13f58, 0x19fae, 0x13f4c,
0x13f46, 0x11f2e, 0x13f6e, 0x13f2c, 0x13f26
},
new[]
{
0x1abe0, 0x1d5f8, 0x153c0, 0x1a9f0, 0x1d4fc, 0x151e0,
0x1a8f8, 0x1d47e, 0x150f0, 0x1a87c, 0x15078, 0x1fad0,
0x15be0, 0x1adf8, 0x1fac8, 0x159f0, 0x1acfc, 0x1fac4,
0x158f8, 0x1ac7e, 0x1fac2, 0x1587c, 0x1f5d0, 0x1faec,
0x15df8, 0x1f5c8, 0x1fae6, 0x15cfc, 0x1f5c4, 0x15c7e,
0x1f5c2, 0x1ebd0, 0x1f5ec, 0x1ebc8, 0x1f5e6, 0x1ebc4,
0x1ebc2, 0x1d7d0, 0x1ebec, 0x1d7c8, 0x1ebe6, 0x1d7c4,
0x1d7c2, 0x1afd0, 0x1d7ec, 0x1afc8, 0x1d7e6, 0x1afc4,
0x14bc0, 0x1a5f0, 0x1d2fc, 0x149e0, 0x1a4f8, 0x1d27e,
0x148f0, 0x1a47c, 0x14878, 0x1a43e, 0x1483c, 0x1fa68,
0x14df0, 0x1a6fc, 0x1fa64, 0x14cf8, 0x1a67e, 0x1fa62,
0x14c7c, 0x14c3e, 0x1f4e8, 0x1fa76, 0x14efc, 0x1f4e4,
0x14e7e, 0x1f4e2, 0x1e9e8, 0x1f4f6, 0x1e9e4, 0x1e9e2,
0x1d3e8, 0x1e9f6, 0x1d3e4, 0x1d3e2, 0x1a7e8, 0x1d3f6,
0x1a7e4, 0x1a7e2, 0x145e0, 0x1a2f8, 0x1d17e, 0x144f0,
0x1a27c, 0x14478, 0x1a23e, 0x1443c, 0x1441e, 0x1fa34,
0x146f8, 0x1a37e, 0x1fa32, 0x1467c, 0x1463e, 0x1f474,
0x1477e, 0x1f472, 0x1e8f4, 0x1e8f2, 0x1d1f4, 0x1d1f2,
0x1a3f4, 0x1a3f2, 0x142f0, 0x1a17c, 0x14278, 0x1a13e,
0x1423c, 0x1421e, 0x1fa1a, 0x1437c, 0x1433e, 0x1f43a,
0x1e87a, 0x1d0fa, 0x14178, 0x1a0be, 0x1413c, 0x1411e,
0x141be, 0x140bc, 0x1409e, 0x12bc0, 0x195f0, 0x1cafc,
0x129e0, 0x194f8, 0x1ca7e, 0x128f0, 0x1947c, 0x12878,
0x1943e, 0x1283c, 0x1f968, 0x12df0, 0x196fc, 0x1f964,
0x12cf8, 0x1967e, 0x1f962, 0x12c7c, 0x12c3e, 0x1f2e8,
0x1f976, 0x12efc, 0x1f2e4, 0x12e7e, 0x1f2e2, 0x1e5e8,
0x1f2f6, 0x1e5e4, 0x1e5e2, 0x1cbe8, 0x1e5f6, 0x1cbe4,
0x1cbe2, 0x197e8, 0x1cbf6, 0x197e4, 0x197e2, 0x1b5e0,
0x1daf8, 0x1ed7e, 0x169c0, 0x1b4f0, 0x1da7c, 0x168e0,
0x1b478, 0x1da3e, 0x16870, 0x1b43c, 0x16838, 0x1b41e,
0x1681c, 0x125e0, 0x192f8, 0x1c97e, 0x16de0, 0x124f0,
0x1927c, 0x16cf0, 0x1b67c, 0x1923e, 0x16c78, 0x1243c,
0x16c3c, 0x1241e, 0x16c1e, 0x1f934, 0x126f8, 0x1937e,
0x1fb74, 0x1f932, 0x16ef8, 0x1267c, 0x1fb72, 0x16e7c,
0x1263e, 0x16e3e, 0x1f274, 0x1277e, 0x1f6f4, 0x1f272,
0x16f7e, 0x1f6f2, 0x1e4f4, 0x1edf4, 0x1e4f2, 0x1edf2,
0x1c9f4, 0x1dbf4, 0x1c9f2, 0x1dbf2, 0x193f4, 0x193f2,
0x165c0, 0x1b2f0, 0x1d97c, 0x164e0, 0x1b278, 0x1d93e,
0x16470, 0x1b23c, 0x16438, 0x1b21e, 0x1641c, 0x1640e,
0x122f0, 0x1917c, 0x166f0, 0x12278, 0x1913e, 0x16678,
0x1b33e, 0x1663c, 0x1221e, 0x1661e, 0x1f91a, 0x1237c,
0x1fb3a, 0x1677c, 0x1233e, 0x1673e, 0x1f23a, 0x1f67a,
0x1e47a, 0x1ecfa, 0x1c8fa, 0x1d9fa, 0x191fa, 0x162e0,
0x1b178, 0x1d8be, 0x16270, 0x1b13c, 0x16238, 0x1b11e,
0x1621c, 0x1620e, 0x12178, 0x190be, 0x16378, 0x1213c,
0x1633c, 0x1211e, 0x1631e, 0x121be, 0x163be, 0x16170,
0x1b0bc, 0x16138, 0x1b09e, 0x1611c, 0x1610e, 0x120bc,
0x161bc, 0x1209e, 0x1619e, 0x160b8, 0x1b05e, 0x1609c,
0x1608e, 0x1205e, 0x160de, 0x1605c, 0x1604e, 0x115e0,
0x18af8, 0x1c57e, 0x114f0, 0x18a7c, 0x11478, 0x18a3e,
0x1143c, 0x1141e, 0x1f8b4, 0x116f8, 0x18b7e, 0x1f8b2,
0x1167c, 0x1163e, 0x1f174, 0x1177e, 0x1f172, 0x1e2f4,
0x1e2f2, 0x1c5f4, 0x1c5f2, 0x18bf4, 0x18bf2, 0x135c0,
0x19af0, 0x1cd7c, 0x134e0, 0x19a78, 0x1cd3e, 0x13470,
0x19a3c, 0x13438, 0x19a1e, 0x1341c, 0x1340e, 0x112f0,
0x1897c, 0x136f0, 0x11278, 0x1893e, 0x13678, 0x19b3e,
0x1363c, 0x1121e, 0x1361e, 0x1f89a, 0x1137c, 0x1f9ba,
0x1377c, 0x1133e, 0x1373e, 0x1f13a, 0x1f37a, 0x1e27a,
0x1e6fa, 0x1c4fa, 0x1cdfa, 0x189fa, 0x1bae0, 0x1dd78,
0x1eebe, 0x174c0, 0x1ba70, 0x1dd3c, 0x17460, 0x1ba38,
0x1dd1e, 0x17430, 0x1ba1c, 0x17418, 0x1ba0e, 0x1740c,
0x132e0, 0x19978, 0x1ccbe, 0x176e0, 0x13270, 0x1993c,
0x17670, 0x1bb3c, 0x1991e, 0x17638, 0x1321c, 0x1761c,
0x1320e, 0x1760e, 0x11178, 0x188be, 0x13378, 0x1113c,
0x17778, 0x1333c, 0x1111e, 0x1773c, 0x1331e, 0x1771e,
0x111be, 0x133be, 0x177be, 0x172c0, 0x1b970, 0x1dcbc,
0x17260, 0x1b938, 0x1dc9e, 0x17230, 0x1b91c, 0x17218,
0x1b90e, 0x1720c, 0x17206, 0x13170, 0x198bc, 0x17370,
0x13138, 0x1989e, 0x17338, 0x1b99e, 0x1731c, 0x1310e,
0x1730e, 0x110bc, 0x131bc, 0x1109e, 0x173bc, 0x1319e,
0x1739e, 0x17160, 0x1b8b8, 0x1dc5e, 0x17130, 0x1b89c,
0x17118, 0x1b88e, 0x1710c, 0x17106, 0x130b8, 0x1985e,
0x171b8, 0x1309c, 0x1719c, 0x1308e, 0x1718e, 0x1105e,
0x130de, 0x171de, 0x170b0, 0x1b85c, 0x17098, 0x1b84e,
0x1708c, 0x17086, 0x1305c, 0x170dc, 0x1304e, 0x170ce,
0x17058, 0x1b82e, 0x1704c, 0x17046, 0x1302e, 0x1706e,
0x1702c, 0x17026, 0x10af0, 0x1857c, 0x10a78, 0x1853e,
0x10a3c, 0x10a1e, 0x10b7c, 0x10b3e, 0x1f0ba, 0x1e17a,
0x1c2fa, 0x185fa, 0x11ae0, 0x18d78, 0x1c6be, 0x11a70,
0x18d3c, 0x11a38, 0x18d1e, 0x11a1c, 0x11a0e, 0x10978,
0x184be, 0x11b78, 0x1093c, 0x11b3c, 0x1091e, 0x11b1e,
0x109be, 0x11bbe, 0x13ac0, 0x19d70, 0x1cebc, 0x13a60,
0x19d38, 0x1ce9e, 0x13a30, 0x19d1c, 0x13a18, 0x19d0e,
0x13a0c, 0x13a06, 0x11970, 0x18cbc, 0x13b70, 0x11938,
0x18c9e, 0x13b38, 0x1191c, 0x13b1c, 0x1190e, 0x13b0e,
0x108bc, 0x119bc, 0x1089e, 0x13bbc, 0x1199e, 0x13b9e,
0x1bd60, 0x1deb8, 0x1ef5e, 0x17a40, 0x1bd30, 0x1de9c,
0x17a20, 0x1bd18, 0x1de8e, 0x17a10, 0x1bd0c, 0x17a08,
0x1bd06, 0x17a04, 0x13960, 0x19cb8, 0x1ce5e, 0x17b60,
0x13930, 0x19c9c, 0x17b30, 0x1bd9c, 0x19c8e, 0x17b18,
0x1390c, 0x17b0c, 0x13906, 0x17b06, 0x118b8, 0x18c5e,
0x139b8, 0x1189c, 0x17bb8, 0x1399c, 0x1188e, 0x17b9c,
0x1398e, 0x17b8e, 0x1085e, 0x118de, 0x139de, 0x17bde,
0x17940, 0x1bcb0, 0x1de5c, 0x17920, 0x1bc98, 0x1de4e,
0x17910, 0x1bc8c, 0x17908, 0x1bc86, 0x17904, 0x17902,
0x138b0, 0x19c5c, 0x179b0, 0x13898, 0x19c4e, 0x17998,
0x1bcce, 0x1798c, 0x13886, 0x17986, 0x1185c, 0x138dc,
0x1184e, 0x179dc, 0x138ce, 0x179ce, 0x178a0, 0x1bc58,
0x1de2e, 0x17890, 0x1bc4c, 0x17888, 0x1bc46, 0x17884,
0x17882, 0x13858, 0x19c2e, 0x178d8, 0x1384c, 0x178cc,
0x13846, 0x178c6, 0x1182e, 0x1386e, 0x178ee, 0x17850,
0x1bc2c, 0x17848, 0x1bc26, 0x17844, 0x17842, 0x1382c,
0x1786c, 0x13826, 0x17866, 0x17828, 0x1bc16, 0x17824,
0x17822, 0x13816, 0x17836, 0x10578, 0x182be, 0x1053c,
0x1051e, 0x105be, 0x10d70, 0x186bc, 0x10d38, 0x1869e,
0x10d1c, 0x10d0e, 0x104bc, 0x10dbc, 0x1049e, 0x10d9e,
0x11d60, 0x18eb8, 0x1c75e, 0x11d30, 0x18e9c, 0x11d18,
0x18e8e, 0x11d0c, 0x11d06, 0x10cb8, 0x1865e, 0x11db8,
0x10c9c, 0x11d9c, 0x10c8e, 0x11d8e, 0x1045e, 0x10cde,
0x11dde, 0x13d40, 0x19eb0, 0x1cf5c, 0x13d20, 0x19e98,
0x1cf4e, 0x13d10, 0x19e8c, 0x13d08, 0x19e86, 0x13d04,
0x13d02, 0x11cb0, 0x18e5c, 0x13db0, 0x11c98, 0x18e4e,
0x13d98, 0x19ece, 0x13d8c, 0x11c86, 0x13d86, 0x10c5c,
0x11cdc, 0x10c4e, 0x13ddc, 0x11cce, 0x13dce, 0x1bea0,
0x1df58, 0x1efae, 0x1be90, 0x1df4c, 0x1be88, 0x1df46,
0x1be84, 0x1be82, 0x13ca0, 0x19e58, 0x1cf2e, 0x17da0,
0x13c90, 0x19e4c, 0x17d90, 0x1becc, 0x19e46, 0x17d88,
0x13c84, 0x17d84, 0x13c82, 0x17d82, 0x11c58, 0x18e2e,
0x13cd8, 0x11c4c, 0x17dd8, 0x13ccc, 0x11c46, 0x17dcc,
0x13cc6, 0x17dc6, 0x10c2e, 0x11c6e, 0x13cee, 0x17dee,
0x1be50, 0x1df2c, 0x1be48, 0x1df26, 0x1be44, 0x1be42,
0x13c50, 0x19e2c, 0x17cd0, 0x13c48, 0x19e26, 0x17cc8,
0x1be66, 0x17cc4, 0x13c42, 0x17cc2, 0x11c2c, 0x13c6c,
0x11c26, 0x17cec, 0x13c66, 0x17ce6, 0x1be28, 0x1df16,
0x1be24, 0x1be22, 0x13c28, 0x19e16, 0x17c68, 0x13c24,
0x17c64, 0x13c22, 0x17c62, 0x11c16, 0x13c36, 0x17c76,
0x1be14, 0x1be12, 0x13c14, 0x17c34, 0x13c12, 0x17c32,
0x102bc, 0x1029e, 0x106b8, 0x1835e, 0x1069c, 0x1068e,
0x1025e, 0x106de, 0x10eb0, 0x1875c, 0x10e98, 0x1874e,
0x10e8c, 0x10e86, 0x1065c, 0x10edc, 0x1064e, 0x10ece,
0x11ea0, 0x18f58, 0x1c7ae, 0x11e90, 0x18f4c, 0x11e88,
0x18f46, 0x11e84, 0x11e82, 0x10e58, 0x1872e, 0x11ed8,
0x18f6e, 0x11ecc, 0x10e46, 0x11ec6, 0x1062e, 0x10e6e,
0x11eee, 0x19f50, 0x1cfac, 0x19f48, 0x1cfa6, 0x19f44,
0x19f42, 0x11e50, 0x18f2c, 0x13ed0, 0x19f6c, 0x18f26,
0x13ec8, 0x11e44, 0x13ec4, 0x11e42, 0x13ec2, 0x10e2c,
0x11e6c, 0x10e26, 0x13eec, 0x11e66, 0x13ee6, 0x1dfa8,
0x1efd6, 0x1dfa4, 0x1dfa2, 0x19f28, 0x1cf96, 0x1bf68,
0x19f24, 0x1bf64, 0x19f22, 0x1bf62, 0x11e28, 0x18f16,
0x13e68, 0x11e24, 0x17ee8, 0x13e64, 0x11e22, 0x17ee4,
0x13e62, 0x17ee2, 0x10e16, 0x11e36, 0x13e76, 0x17ef6,
0x1df94, 0x1df92, 0x19f14, 0x1bf34, 0x19f12, 0x1bf32,
0x11e14, 0x13e34, 0x11e12, 0x17e74, 0x13e32, 0x17e72,
0x1df8a, 0x19f0a, 0x1bf1a, 0x11e0a, 0x13e1a, 0x17e3a,
0x1035c, 0x1034e, 0x10758, 0x183ae, 0x1074c, 0x10746,
0x1032e, 0x1076e, 0x10f50, 0x187ac, 0x10f48, 0x187a6,
0x10f44, 0x10f42, 0x1072c, 0x10f6c, 0x10726, 0x10f66,
0x18fa8, 0x1c7d6, 0x18fa4, 0x18fa2, 0x10f28, 0x18796,
0x11f68, 0x18fb6, 0x11f64, 0x10f22, 0x11f62, 0x10716,
0x10f36, 0x11f76, 0x1cfd4, 0x1cfd2, 0x18f94, 0x19fb4,
0x18f92, 0x19fb2, 0x10f14, 0x11f34, 0x10f12, 0x13f74,
0x11f32, 0x13f72, 0x1cfca, 0x18f8a, 0x19f9a, 0x10f0a,
0x11f1a, 0x13f3a, 0x103ac, 0x103a6, 0x107a8, 0x183d6,
0x107a4, 0x107a2, 0x10396, 0x107b6, 0x187d4, 0x187d2,
0x10794, 0x10fb4, 0x10792, 0x10fb2, 0x1c7ea
}
};
private const float PREFERRED_RATIO = 3.0f;
private const float DEFAULT_MODULE_WIDTH = 0.357f; //1px in mm
private const float HEIGHT = 2.0f; //mm
private BarcodeMatrix barcodeMatrix;
private bool compact;
private Compaction compaction;
private int minCols;
private int maxCols;
private int maxRows;
private int minRows;
internal PDF417()
: this(false)
{
}
internal PDF417(bool compact)
{
this.compact = compact;
compaction = Compaction.AUTO;
minCols = 2;
maxCols = 30;
maxRows = 30;
minRows = 2;
}
internal BarcodeMatrix BarcodeMatrix
{
get { return barcodeMatrix; }
}
/// <summary>
/// Calculates the necessary number of rows as described in annex Q of ISO/IEC 15438:2001(E).
/// </summary>
/// <param name="m">the number of source codewords prior to the additional of the Symbol Length</param>
/// Descriptor and any pad codewords
/// <param name="k">the number of error correction codewords</param>
/// <param name="c">the number of columns in the symbol in the data region (excluding start, stop and</param>
/// row indicator codewords)
/// <returns>the number of rows in the symbol (r)</returns>
private static int calculateNumberOfRows(int m, int k, int c)
{
int r = ((m + 1 + k) / c) + 1;
if (c * r >= (m + 1 + k + c))
{
r--;
}
return r;
}
/// <summary>
/// Calculates the number of pad codewords as described in 4.9.2 of ISO/IEC 15438:2001(E).
/// </summary>
/// <param name="m">the number of source codewords prior to the additional of the Symbol Length</param>
/// Descriptor and any pad codewords
/// <param name="k">the number of error correction codewords</param>
/// <param name="c">the number of columns in the symbol in the data region (excluding start, stop and</param>
/// row indicator codewords)
/// <param name="r">the number of rows in the symbol</param>
/// <returns>the number of pad codewords</returns>
private static int getNumberOfPadCodewords(int m, int k, int c, int r)
{
int n = c * r - k;
return n > m + 1 ? n - m - 1 : 0;
}
private static void encodeChar(int pattern, int len, BarcodeRow logic)
{
int map = 1 << len - 1;
bool last = (pattern & map) != 0; //Initialize to inverse of first bit
int width = 0;
for (int i = 0; i < len; i++)
{
bool black = (pattern & map) != 0;
if (last == black)
{
width++;
}
else
{
logic.addBar(last, width);
last = black;
width = 1;
}
map >>= 1;
}
logic.addBar(last, width);
}
private void encodeLowLevel(String fullCodewords,
int c,
int r,
int errorCorrectionLevel,
BarcodeMatrix logic)
{
int idx = 0;
for (int y = 0; y < r; y++)
{
int cluster = y % 3;
logic.startRow();
encodeChar(START_PATTERN, 17, logic.getCurrentRow());
int left;
int right;
if (cluster == 0)
{
left = (30 * (y / 3)) + ((r - 1) / 3);
right = (30 * (y / 3)) + (c - 1);
}
else if (cluster == 1)
{
left = (30 * (y / 3)) + (errorCorrectionLevel * 3) + ((r - 1) % 3);
right = (30 * (y / 3)) + ((r - 1) / 3);
}
else
{
left = (30 * (y / 3)) + (c - 1);
right = (30 * (y / 3)) + (errorCorrectionLevel * 3) + ((r - 1) % 3);
}
int pattern = CODEWORD_TABLE[cluster][left];
encodeChar(pattern, 17, logic.getCurrentRow());
for (int x = 0; x < c; x++)
{
pattern = CODEWORD_TABLE[cluster][fullCodewords[idx]];
encodeChar(pattern, 17, logic.getCurrentRow());
idx++;
}
if (compact)
{
encodeChar(STOP_PATTERN, 1, logic.getCurrentRow()); // encodes stop line for compact pdf417
}
else
{
pattern = CODEWORD_TABLE[cluster][right];
encodeChar(pattern, 17, logic.getCurrentRow());
encodeChar(STOP_PATTERN, 18, logic.getCurrentRow());
}
}
}
/// <summary>
/// Generates the barcode logic.
/// </summary>
/// <param name="msg">the message to encode</param>
internal void generateBarcodeLogic(String msg, int errorCorrectionLevel)
{
//1. step: High-level encoding
int errorCorrectionCodeWords = PDF417ErrorCorrection.getErrorCorrectionCodewordCount(errorCorrectionLevel);
String highLevel = PDF417HighLevelEncoder.encodeHighLevel(msg, compaction);
int sourceCodeWords = highLevel.Length;
int[] dimension = determineDimensions(sourceCodeWords, errorCorrectionCodeWords);
int cols = dimension[0];
int rows = dimension[1];
int pad = getNumberOfPadCodewords(sourceCodeWords, errorCorrectionCodeWords, cols, rows);
//2. step: construct data codewords
if (sourceCodeWords + errorCorrectionCodeWords + 1 > 929)
{ // +1 for symbol length CW
throw new WriterException(
"Encoded message contains to many code words, message to big (" + msg.Length + " bytes)");
}
int n = sourceCodeWords + pad + 1;
StringBuilder sb = new StringBuilder(n);
sb.Append((char)n);
sb.Append(highLevel);
for (int i = 0; i < pad; i++)
{
sb.Append((char)900); //PAD characters
}
String dataCodewords = sb.ToString();
//3. step: Error correction
String ec = PDF417ErrorCorrection.generateErrorCorrection(dataCodewords, errorCorrectionLevel);
String fullCodewords = dataCodewords + ec;
//4. step: low-level encoding
barcodeMatrix = new BarcodeMatrix(rows, cols);
encodeLowLevel(fullCodewords, cols, rows, errorCorrectionLevel, barcodeMatrix);
}
/// <summary>
/// Determine optimal nr of columns and rows for the specified number of
/// codewords.
/// </summary>
/// <param name="sourceCodeWords">number of code words</param>
/// <param name="errorCorrectionCodeWords">number of error correction code words</param>
/// <returns>dimension object containing cols as width and rows as height</returns>
int[] determineDimensions(int sourceCodeWords, int errorCorrectionCodeWords)
{
float ratio = 0.0f;
int[] dimension = null;
for (int cols = minCols; cols <= maxCols; cols++)
{
int rows = calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, cols);
if (rows < minRows)
{
break;
}
if (rows > maxRows)
{
continue;
}
float newRatio = ((17 * cols + 69) * DEFAULT_MODULE_WIDTH) / (rows * HEIGHT);
// ignore if previous ratio is closer to preferred ratio
if (dimension != null && Math.Abs(newRatio - PREFERRED_RATIO) > Math.Abs(ratio - PREFERRED_RATIO))
{
continue;
}
ratio = newRatio;
dimension = new int[] { cols, rows };
}
// Handle case when min values were larger than necessary
if (dimension == null)
{
int rows = calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, minCols);
if (rows < minRows)
{
dimension = new int[] { minCols, minRows };
}
}
if (dimension == null)
{
throw new WriterException("Unable to fit message in columns");
}
return dimension;
}
/// <summary>
/// Sets max/min row/col values
/// </summary>
internal void setDimensions(int maxCols, int minCols, int maxRows, int minRows)
{
this.maxCols = maxCols;
this.minCols = minCols;
this.maxRows = maxRows;
this.minRows = minRows;
}
/// <summary>
/// Sets compaction to values stored in <see cref="Compaction" />enum
/// </summary>
internal void setCompaction(Compaction compaction)
{
this.compaction = compaction;
}
/// <summary>
/// Sets compact to be true or false
/// </summary>
internal void setCompact(bool compact)
{
this.compact = compact;
}
}
}

View file

@ -0,0 +1,89 @@
???/*
* Copyright 2012 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;
using ZXing.PDF417.Internal;
namespace ZXing.PDF417
{
/// <summary>
/// The class holds the available options for the <see cref="PDF417Writer" />
/// </summary>
[Serializable]
public class PDF417EncodingOptions : EncodingOptions
{
/// <summary>
/// Specifies whether to use compact mode for PDF417 (type <see cref="bool" />).
/// </summary>
public bool Compact
{
get
{
if (Hints.ContainsKey(EncodeHintType.PDF417_COMPACT))
{
return (bool)Hints[EncodeHintType.PDF417_COMPACT];
}
return false;
}
set
{
Hints[EncodeHintType.PDF417_COMPACT] = value;
}
}
/// <summary>
/// Specifies what compaction mode to use for PDF417 (type
/// <see cref="Compaction" />).
/// </summary>
public Compaction Compaction
{
get
{
if (Hints.ContainsKey(EncodeHintType.PDF417_COMPACTION))
{
return (Compaction)Hints[EncodeHintType.PDF417_COMPACTION];
}
return Compaction.AUTO;
}
set
{
Hints[EncodeHintType.PDF417_COMPACTION] = value;
}
}
/// <summary>
/// Specifies the minimum and maximum number of rows and columns for PDF417 (type
/// <see cref="Dimensions" />).
/// </summary>
public Dimensions Dimensions
{
get
{
if (Hints.ContainsKey(EncodeHintType.PDF417_DIMENSIONS))
{
return (Dimensions)Hints[EncodeHintType.PDF417_DIMENSIONS];
}
return null;
}
set
{
Hints[EncodeHintType.PDF417_DIMENSIONS] = value;
}
}
}
}

View file

@ -0,0 +1,240 @@
/*
* Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part
*
* 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.
*/
/*
* This file has been modified from its original form in Barcode4J.
*/
using System;
using System.Text;
namespace ZXing.PDF417.Internal
{
/// <summary>
/// PDF417 error correction code following the algorithm described in ISO/IEC 15438:2001(E) in
/// chapter 4.10.
/// </summary>
sealed class PDF417ErrorCorrection
{
/// <summary>
/// Tables of coefficients for calculating error correction words
/// (see annex F, ISO/IEC 15438:2001(E))
/// </summary>
private static int[][] EC_COEFFICIENTS = {
new[] {27, 917},
new[] {522, 568, 723, 809},
new[] {237, 308, 436, 284, 646, 653, 428, 379},
new[]
{
274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295,
42, 176, 65
},
new[]
{
361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687,
284, 193, 517, 273, 494, 263, 147, 593, 800, 571, 320, 803,
133, 231, 390, 685, 330, 63, 410
},
new[]
{
539, 422, 6, 93, 862, 771, 453, 106, 610, 287, 107, 505, 733,
877, 381, 612, 723, 476, 462, 172, 430, 609, 858, 822, 543,
376, 511, 400, 672, 762, 283, 184, 440, 35, 519, 31, 460,
594, 225, 535, 517, 352, 605, 158, 651, 201, 488, 502, 648,
733, 717, 83, 404, 97, 280, 771, 840, 629, 4, 381, 843,
623, 264, 543
},
new[]
{
521, 310, 864, 547, 858, 580, 296, 379, 53, 779, 897, 444, 400,
925, 749, 415, 822, 93, 217, 208, 928, 244, 583, 620, 246,
148, 447, 631, 292, 908, 490, 704, 516, 258, 457, 907, 594,
723, 674, 292, 272, 96, 684, 432, 686, 606, 860, 569, 193,
219, 129, 186, 236, 287, 192, 775, 278, 173, 40, 379, 712,
463, 646, 776, 171, 491, 297, 763, 156, 732, 95, 270, 447,
90, 507, 48, 228, 821, 808, 898, 784, 663, 627, 378, 382,
262, 380, 602, 754, 336, 89, 614, 87, 432, 670, 616, 157,
374, 242, 726, 600, 269, 375, 898, 845, 454, 354, 130, 814,
587, 804, 34, 211, 330, 539, 297, 827, 865, 37, 517, 834,
315, 550, 86, 801, 4, 108, 539
},
new[]
{
524, 894, 75, 766, 882, 857, 74, 204, 82, 586, 708, 250, 905,
786, 138, 720, 858, 194, 311, 913, 275, 190, 375, 850, 438,
733, 194, 280, 201, 280, 828, 757, 710, 814, 919, 89, 68,
569, 11, 204, 796, 605, 540, 913, 801, 700, 799, 137, 439,
418, 592, 668, 353, 859, 370, 694, 325, 240, 216, 257, 284,
549, 209, 884, 315, 70, 329, 793, 490, 274, 877, 162, 749,
812, 684, 461, 334, 376, 849, 521, 307, 291, 803, 712, 19,
358, 399, 908, 103, 511, 51, 8, 517, 225, 289, 470, 637,
731, 66, 255, 917, 269, 463, 830, 730, 433, 848, 585, 136,
538, 906, 90, 2, 290, 743, 199, 655, 903, 329, 49, 802,
580, 355, 588, 188, 462, 10, 134, 628, 320, 479, 130, 739,
71, 263, 318, 374, 601, 192, 605, 142, 673, 687, 234, 722,
384, 177, 752, 607, 640, 455, 193, 689, 707, 805, 641, 48,
60, 732, 621, 895, 544, 261, 852, 655, 309, 697, 755, 756,
60, 231, 773, 434, 421, 726, 528, 503, 118, 49, 795, 32,
144, 500, 238, 836, 394, 280, 566, 319, 9, 647, 550, 73,
914, 342, 126, 32, 681, 331, 792, 620, 60, 609, 441, 180,
791, 893, 754, 605, 383, 228, 749, 760, 213, 54, 297, 134,
54, 834, 299, 922, 191, 910, 532, 609, 829, 189, 20, 167,
29, 872, 449, 83, 402, 41, 656, 505, 579, 481, 173, 404,
251, 688, 95, 497, 555, 642, 543, 307, 159, 924, 558, 648,
55, 497, 10
},
new[]
{
352, 77, 373, 504, 35, 599, 428, 207, 409, 574, 118, 498, 285,
380, 350, 492, 197, 265, 920, 155, 914, 299, 229, 643, 294,
871, 306, 88, 87, 193, 352, 781, 846, 75, 327, 520, 435,
543, 203, 666, 249, 346, 781, 621, 640, 268, 794, 534, 539,
781, 408, 390, 644, 102, 476, 499, 290, 632, 545, 37, 858,
916, 552, 41, 542, 289, 122, 272, 383, 800, 485, 98, 752,
472, 761, 107, 784, 860, 658, 741, 290, 204, 681, 407, 855,
85, 99, 62, 482, 180, 20, 297, 451, 593, 913, 142, 808,
684, 287, 536, 561, 76, 653, 899, 729, 567, 744, 390, 513,
192, 516, 258, 240, 518, 794, 395, 768, 848, 51, 610, 384,
168, 190, 826, 328, 596, 786, 303, 570, 381, 415, 641, 156,
237, 151, 429, 531, 207, 676, 710, 89, 168, 304, 402, 40,
708, 575, 162, 864, 229, 65, 861, 841, 512, 164, 477, 221,
92, 358, 785, 288, 357, 850, 836, 827, 736, 707, 94, 8,
494, 114, 521, 2, 499, 851, 543, 152, 729, 771, 95, 248,
361, 578, 323, 856, 797, 289, 51, 684, 466, 533, 820, 669,
45, 902, 452, 167, 342, 244, 173, 35, 463, 651, 51, 699,
591, 452, 578, 37, 124, 298, 332, 552, 43, 427, 119, 662,
777, 475, 850, 764, 364, 578, 911, 283, 711, 472, 420, 245,
288, 594, 394, 511, 327, 589, 777, 699, 688, 43, 408, 842,
383, 721, 521, 560, 644, 714, 559, 62, 145, 873, 663, 713,
159, 672, 729, 624, 59, 193, 417, 158, 209, 563, 564, 343,
693, 109, 608, 563, 365, 181, 772, 677, 310, 248, 353, 708,
410, 579, 870, 617, 841, 632, 860, 289, 536, 35, 777, 618,
586, 424, 833, 77, 597, 346, 269, 757, 632, 695, 751, 331,
247, 184, 45, 787, 680, 18, 66, 407, 369, 54, 492, 228,
613, 830, 922, 437, 519, 644, 905, 789, 420, 305, 441, 207,
300, 892, 827, 141, 537, 381, 662, 513, 56, 252, 341, 242,
797, 838, 837, 720, 224, 307, 631, 61, 87, 560, 310, 756,
665, 397, 808, 851, 309, 473, 795, 378, 31, 647, 915, 459,
806, 590, 731, 425, 216, 548, 249, 321, 881, 699, 535, 673,
782, 210, 815, 905, 303, 843, 922, 281, 73, 469, 791, 660,
162, 498, 308, 155, 422, 907, 817, 187, 62, 16, 425, 535,
336, 286, 437, 375, 273, 610, 296, 183, 923, 116, 667, 751,
353, 62, 366, 691, 379, 687, 842, 37, 357, 720, 742, 330,
5, 39, 923, 311, 424, 242, 749, 321, 54, 669, 316, 342,
299, 534, 105, 667, 488, 640, 672, 576, 540, 316, 486, 721,
610, 46, 656, 447, 171, 616, 464, 190, 531, 297, 321, 762,
752, 533, 175, 134, 14, 381, 433, 717, 45, 111, 20, 596,
284, 736, 138, 646, 411, 877, 669, 141, 919, 45, 780, 407,
164, 332, 899, 165, 726, 600, 325, 498, 655, 357, 752, 768,
223, 849, 647, 63, 310, 863, 251, 366, 304, 282, 738, 675,
410, 389, 244, 31, 121, 303, 263
}
};
private PDF417ErrorCorrection()
{
}
/// <summary>
/// Determines the number of error correction codewords for a specified error correction
/// level.
///
/// <param name="errorCorrectionLevel">the error correction level (0-8)</param>
/// <returns>the number of codewords generated for error correction</returns>
/// </summary>
internal static int getErrorCorrectionCodewordCount(int errorCorrectionLevel)
{
if (errorCorrectionLevel < 0 || errorCorrectionLevel > 8)
{
throw new ArgumentException("Error correction level must be between 0 and 8!");
}
return 1 << (errorCorrectionLevel + 1);
}
/// <summary>
/// Returns the recommended minimum error correction level as described in annex E of
/// ISO/IEC 15438:2001(E).
///
/// <param name="n">the number of data codewords</param>
/// <returns>the recommended minimum error correction level</returns>
/// </summary>
internal static int getRecommendedMinimumErrorCorrectionLevel(int n)
{
if (n <= 0)
{
throw new ArgumentException("n must be > 0");
}
if (n <= 40)
{
return 2;
}
if (n <= 160)
{
return 3;
}
if (n <= 320)
{
return 4;
}
if (n <= 863)
{
return 5;
}
throw new WriterException("No recommendation possible");
}
/// <summary>
/// Generates the error correction codewords according to 4.10 in ISO/IEC 15438:2001(E).
///
/// <param name="dataCodewords">the data codewords</param>
/// <param name="errorCorrectionLevel">the error correction level (0-8)</param>
/// <returns>the String representing the error correction codewords</returns>
/// </summary>
internal static String generateErrorCorrection(String dataCodewords, int errorCorrectionLevel)
{
int k = getErrorCorrectionCodewordCount(errorCorrectionLevel);
char[] e = new char[k];
int sld = dataCodewords.Length;
for (int i = 0; i < sld; i++)
{
int t1 = (dataCodewords[i] + e[e.Length - 1]) % 929;
int t2;
int t3;
for (int j = k - 1; j >= 1; j--)
{
t2 = (t1 * EC_COEFFICIENTS[errorCorrectionLevel][j]) % 929;
t3 = 929 - t2;
e[j] = (char)((e[j - 1] + t3) % 929);
}
t2 = (t1 * EC_COEFFICIENTS[errorCorrectionLevel][0]) % 929;
t3 = 929 - t2;
e[0] = (char)(t3 % 929);
}
StringBuilder sb = new StringBuilder(k);
for (int j = k - 1; j >= 0; j--)
{
if (e[j] != 0)
{
e[j] = (char)(929 - e[j]);
}
sb.Append(e[j]);
}
return sb.ToString();
}
}
}

View file

@ -0,0 +1,722 @@
/*
* Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part
*
* 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.
*/
/*
* This file has been modified from its original form in Barcode4J.
*/
using System;
#if SILVERLIGHT4 || SILVERLIGHT5 || NET40 || NET45 || NETFX_CORE
using System.Numerics;
#else
using BigIntegerLibrary;
#endif
using System.Text;
namespace ZXing.PDF417.Internal
{
/// <summary>
/// PDF417 high-level encoder following the algorithm described in ISO/IEC 15438:2001(E) in
/// annex P.
/// </summary>
sealed class PDF417HighLevelEncoder
{
/// <summary>
/// code for Text compaction
/// </summary>
private const int TEXT_COMPACTION = 0;
/// <summary>
/// code for Byte compaction
/// </summary>
private const int BYTE_COMPACTION = 1;
/// <summary>
/// code for Numeric compaction
/// </summary>
private const int NUMERIC_COMPACTION = 2;
/// <summary>
/// Text compaction submode Alpha
/// </summary>
private const int SUBMODE_ALPHA = 0;
/// <summary>
/// Text compaction submode Lower
/// </summary>
private const int SUBMODE_LOWER = 1;
/// <summary>
/// Text compaction submode Mixed
/// </summary>
private const int SUBMODE_MIXED = 2;
/// <summary>
/// Text compaction submode Punctuation
/// </summary>
private const int SUBMODE_PUNCTUATION = 3;
/// <summary>
/// mode latch to Text Compaction mode
/// </summary>
private const int LATCH_TO_TEXT = 900;
/// <summary>
/// mode latch to Byte Compaction mode (number of characters NOT a multiple of 6)
/// </summary>
private const int LATCH_TO_BYTE_PADDED = 901;
/// <summary>
/// mode latch to Numeric Compaction mode
/// </summary>
private const int LATCH_TO_NUMERIC = 902;
/// <summary>
/// mode shift to Byte Compaction mode
/// </summary>
private const int SHIFT_TO_BYTE = 913;
/// <summary>
/// mode latch to Byte Compaction mode (number of characters a multiple of 6)
/// </summary>
private const int LATCH_TO_BYTE = 924;
/// <summary>
/// Raw code table for text compaction Mixed sub-mode
/// </summary>
private static readonly sbyte[] TEXT_MIXED_RAW = {
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 38, 13, 9, 44, 58,
35, 45, 46, 36, 47, 43, 37, 42, 61, 94, 0, 32, 0, 0, 0
};
/// <summary>
/// Raw code table for text compaction: Punctuation sub-mode
/// </summary>
private static readonly sbyte[] TEXT_PUNCTUATION_RAW = {
59, 60, 62, 64, 91, 92, 93, 95, 96, 126, 33, 13, 9, 44, 58,
10, 45, 46, 36, 47, 34, 124, 42, 40, 41, 63, 123, 125, 39, 0
};
private static readonly sbyte[] MIXED = new sbyte[128];
private static readonly sbyte[] PUNCTUATION = new sbyte[128];
private PDF417HighLevelEncoder()
{
}
static PDF417HighLevelEncoder()
{
//Construct inverse lookups
for (int idx = 0; idx < MIXED.Length; idx++)
MIXED[idx] = -1;
for (sbyte i = 0; i < TEXT_MIXED_RAW.Length; i++)
{
sbyte b = TEXT_MIXED_RAW[i];
if (b > 0)
{
MIXED[b] = i;
}
}
for (int idx = 0; idx < PUNCTUATION.Length; idx++)
PUNCTUATION[idx] = -1;
for (sbyte i = 0; i < TEXT_PUNCTUATION_RAW.Length; i++)
{
sbyte b = TEXT_PUNCTUATION_RAW[i];
if (b > 0)
{
PUNCTUATION[b] = i;
}
}
}
/// <summary>
/// Converts the message to a byte array using the default encoding (cp437) as defined by the
/// specification
///
/// <param name="msg">the message</param>
/// <returns>the byte array of the message</returns>
/// </summary>
private static byte[] getBytesForMessage(String msg)
{
#if WindowsCE
try
{
return Encoding.GetEncoding("CP437").GetBytes(msg);
}
catch (PlatformNotSupportedException)
{
// WindowsCE doesn't support all encodings. But it is device depended.
// So we try here the some different ones
return Encoding.GetEncoding(1252).GetBytes(msg);
}
#else
return Encoding.GetEncoding("CP437").GetBytes(msg);
#endif
}
/// <summary>
/// Performs high-level encoding of a PDF417 message using the algorithm described in annex P
/// of ISO/IEC 15438:2001(E). If byte compaction has been selected, then only byte compaction
/// is used.
///
/// <param name="msg">the message</param>
/// <returns>the encoded message (the char values range from 0 to 928)</returns>
/// </summary>
internal static String encodeHighLevel(String msg, Compaction compaction)
{
byte[] bytes = null; //Fill later and only if needed
//the codewords 0..928 are encoded as Unicode characters
StringBuilder sb = new StringBuilder(msg.Length);
int len = msg.Length;
int p = 0;
int textSubMode = SUBMODE_ALPHA;
// User selected encoding mode
if (compaction == Compaction.TEXT)
{
encodeText(msg, p, len, sb, textSubMode);
}
else if (compaction == Compaction.BYTE)
{
bytes = getBytesForMessage(msg);
encodeBinary(bytes, p, bytes.Length, BYTE_COMPACTION, sb);
}
else if (compaction == Compaction.NUMERIC)
{
sb.Append((char)LATCH_TO_NUMERIC);
encodeNumeric(msg, p, len, sb);
}
else
{
int encodingMode = TEXT_COMPACTION; //Default mode, see 4.4.2.1
while (p < len)
{
int n = determineConsecutiveDigitCount(msg, p);
if (n >= 13)
{
sb.Append((char)LATCH_TO_NUMERIC);
encodingMode = NUMERIC_COMPACTION;
textSubMode = SUBMODE_ALPHA; //Reset after latch
encodeNumeric(msg, p, n, sb);
p += n;
}
else
{
int t = determineConsecutiveTextCount(msg, p);
if (t >= 5 || n == len)
{
if (encodingMode != TEXT_COMPACTION)
{
sb.Append((char)LATCH_TO_TEXT);
encodingMode = TEXT_COMPACTION;
textSubMode = SUBMODE_ALPHA; //start with submode alpha after latch
}
textSubMode = encodeText(msg, p, t, sb, textSubMode);
p += t;
}
else
{
if (bytes == null)
{
bytes = getBytesForMessage(msg);
}
int b = determineConsecutiveBinaryCount(msg, bytes, p);
if (b == 0)
{
b = 1;
}
if (b == 1 && encodingMode == TEXT_COMPACTION)
{
//Switch for one byte (instead of latch)
encodeBinary(bytes, p, 1, TEXT_COMPACTION, sb);
}
else
{
//Mode latch performed by encodeBinary()
encodeBinary(bytes, p, b, encodingMode, sb);
encodingMode = BYTE_COMPACTION;
textSubMode = SUBMODE_ALPHA; //Reset after latch
}
p += b;
}
}
}
}
return sb.ToString();
}
/// <summary>
/// Encode parts of the message using Text Compaction as described in ISO/IEC 15438:2001(E),
/// chapter 4.4.2.
///
/// <param name="msg">the message</param>
/// <param name="startpos">the start position within the message</param>
/// <param name="count">the number of characters to encode</param>
/// <param name="sb">receives the encoded codewords</param>
/// <param name="initialSubmode">should normally be SUBMODE_ALPHA</param>
/// <returns>the text submode in which this method ends</returns>
/// </summary>
private static int encodeText(String msg,
int startpos,
int count,
StringBuilder sb,
int initialSubmode)
{
StringBuilder tmp = new StringBuilder(count);
int submode = initialSubmode;
int idx = 0;
while (true)
{
char ch = msg[startpos + idx];
switch (submode)
{
case SUBMODE_ALPHA:
if (isAlphaUpper(ch))
{
if (ch == ' ')
{
tmp.Append((char)26); //space
}
else
{
tmp.Append((char)(ch - 65));
}
}
else
{
if (isAlphaLower(ch))
{
submode = SUBMODE_LOWER;
tmp.Append((char)27); //ll
continue;
}
else if (isMixed(ch))
{
submode = SUBMODE_MIXED;
tmp.Append((char)28); //ml
continue;
}
else
{
tmp.Append((char)29); //ps
tmp.Append((char)PUNCTUATION[ch]);
break;
}
}
break;
case SUBMODE_LOWER:
if (isAlphaLower(ch))
{
if (ch == ' ')
{
tmp.Append((char)26); //space
}
else
{
tmp.Append((char)(ch - 97));
}
}
else
{
if (isAlphaUpper(ch))
{
tmp.Append((char)27); //as
tmp.Append((char)(ch - 65));
//space cannot happen here, it is also in "Lower"
break;
}
else if (isMixed(ch))
{
submode = SUBMODE_MIXED;
tmp.Append((char)28); //ml
continue;
}
else
{
tmp.Append((char)29); //ps
tmp.Append((char)PUNCTUATION[ch]);
break;
}
}
break;
case SUBMODE_MIXED:
if (isMixed(ch))
{
tmp.Append((char)MIXED[ch]);
}
else
{
if (isAlphaUpper(ch))
{
submode = SUBMODE_ALPHA;
tmp.Append((char)28); //al
continue;
}
else if (isAlphaLower(ch))
{
submode = SUBMODE_LOWER;
tmp.Append((char)27); //ll
continue;
}
else
{
if (startpos + idx + 1 < count)
{
char next = msg[startpos + idx + 1];
if (isPunctuation(next))
{
submode = SUBMODE_PUNCTUATION;
tmp.Append((char)25); //pl
continue;
}
}
tmp.Append((char)29); //ps
tmp.Append((char)PUNCTUATION[ch]);
}
}
break;
default: //SUBMODE_PUNCTUATION
if (isPunctuation(ch))
{
tmp.Append((char)PUNCTUATION[ch]);
}
else
{
submode = SUBMODE_ALPHA;
tmp.Append((char)29); //al
continue;
}
break;
}
idx++;
if (idx >= count)
{
break;
}
}
char h = (char)0;
int len = tmp.Length;
for (int i = 0; i < len; i++)
{
bool odd = (i % 2) != 0;
if (odd)
{
h = (char)((h * 30) + tmp[i]);
sb.Append(h);
}
else
{
h = tmp[i];
}
}
if ((len % 2) != 0)
{
sb.Append((char)((h * 30) + 29)); //ps
}
return submode;
}
/// <summary>
/// Encode parts of the message using Byte Compaction as described in ISO/IEC 15438:2001(E),
/// chapter 4.4.3. The Unicode characters will be converted to binary using the cp437
/// codepage.
///
/// <param name="bytes">the message converted to a byte array</param>
/// <param name="startpos">the start position within the message</param>
/// <param name="count">the number of bytes to encode</param>
/// <param name="startmode">the mode from which this method starts</param>
/// <param name="sb">receives the encoded codewords</param>
/// </summary>
private static void encodeBinary(byte[] bytes,
int startpos,
int count,
int startmode,
StringBuilder sb)
{
if (count == 1 && startmode == TEXT_COMPACTION)
{
sb.Append((char)SHIFT_TO_BYTE);
}
int idx = startpos;
// Encode sixpacks
if (count >= 6)
{
sb.Append((char)LATCH_TO_BYTE);
char[] chars = new char[5];
while ((startpos + count - idx) >= 6)
{
long t = 0;
for (int i = 0; i < 6; i++)
{
t <<= 8;
t += bytes[idx + i] & 0xff;
}
for (int i = 0; i < 5; i++)
{
chars[i] = (char)(t % 900);
t /= 900;
}
for (int i = chars.Length - 1; i >= 0; i--)
{
sb.Append(chars[i]);
}
idx += 6;
}
}
//Encode rest (remaining n<5 bytes if any)
if (idx < startpos + count)
{
sb.Append((char)LATCH_TO_BYTE_PADDED);
}
for (int i = idx; i < startpos + count; i++)
{
int ch = bytes[i] & 0xff;
sb.Append((char)ch);
}
}
private static void encodeNumeric(String msg, int startpos, int count, StringBuilder sb)
{
#if SILVERLIGHT4 || SILVERLIGHT5 || NET40 || NET45 || NETFX_CORE
int idx = 0;
StringBuilder tmp = new StringBuilder(count / 3 + 1);
BigInteger num900 = new BigInteger(900);
BigInteger num0 = new BigInteger(0);
while (idx < count - 1)
{
tmp.Length = 0;
int len = Math.Min(44, count - idx);
String part = '1' + msg.Substring(startpos + idx, len);
#if SILVERLIGHT4 || SILVERLIGHT5
BigInteger bigint = BigIntegerExtensions.Parse(part);
#else
BigInteger bigint = BigInteger.Parse(part);
#endif
do
{
BigInteger c = bigint % num900;
tmp.Append((char)c);
bigint = BigInteger.Divide(bigint, num900);
} while (!bigint.Equals(num0));
//Reverse temporary string
for (int i = tmp.Length - 1; i >= 0; i--)
{
sb.Append(tmp[i]);
}
idx += len;
}
#else
int idx = 0;
StringBuilder tmp = new StringBuilder(count / 3 + 1);
BigInteger num900 = new BigInteger(900);
BigInteger num0 = new BigInteger(0);
while (idx < count - 1)
{
tmp.Length = 0;
int len = Math.Min(44, count - idx);
String part = '1' + msg.Substring(startpos + idx, len);
BigInteger bigint = BigInteger.Parse(part);
do
{
BigInteger c = BigInteger.Modulo(bigint, num900);
tmp.Append((char)c.GetHashCode());
bigint = BigInteger.Division(bigint, num900);
} while (!bigint.Equals(num0));
//Reverse temporary string
for (int i = tmp.Length - 1; i >= 0; i--)
{
sb.Append(tmp[i]);
}
idx += len;
}
#endif
}
private static bool isDigit(char ch)
{
return ch >= '0' && ch <= '9';
}
private static bool isAlphaUpper(char ch)
{
return ch == ' ' || (ch >= 'A' && ch <= 'Z');
}
private static bool isAlphaLower(char ch)
{
return ch == ' ' || (ch >= 'a' && ch <= 'z');
}
private static bool isMixed(char ch)
{
return MIXED[ch] != -1;
}
private static bool isPunctuation(char ch)
{
return PUNCTUATION[ch] != -1;
}
private static bool isText(char ch)
{
return ch == '\t' || ch == '\n' || ch == '\r' || (ch >= 32 && ch <= 126);
}
/// <summary>
/// Determines the number of consecutive characters that are encodable using numeric compaction.
///
/// <param name="msg">the message</param>
/// <param name="startpos">the start position within the message</param>
/// <returns>the requested character count</returns>
/// </summary>
private 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;
}
/// <summary>
/// Determines the number of consecutive characters that are encodable using text compaction.
///
/// <param name="msg">the message</param>
/// <param name="startpos">the start position within the message</param>
/// <returns>the requested character count</returns>
/// </summary>
private static int determineConsecutiveTextCount(String msg, int startpos)
{
int len = msg.Length;
int idx = startpos;
while (idx < len)
{
char ch = msg[idx];
int numericCount = 0;
while (numericCount < 13 && isDigit(ch) && idx < len)
{
numericCount++;
idx++;
if (idx < len)
{
ch = msg[idx];
}
}
if (numericCount >= 13)
{
return idx - startpos - numericCount;
}
if (numericCount > 0)
{
//Heuristic: All text-encodable chars or digits are binary encodable
continue;
}
ch = msg[idx];
//Check if character is encodable
if (!isText(ch))
{
break;
}
idx++;
}
return idx - startpos;
}
/// <summary>
/// Determines the number of consecutive characters that are encodable using binary compaction.
///
/// <param name="msg">the message</param>
/// <param name="bytes">the message converted to a byte array</param>
/// <param name="startpos">the start position within the message</param>
/// <returns>the requested character count</returns>
/// </summary>
private static int determineConsecutiveBinaryCount(String msg, byte[] bytes, int startpos)
{
int len = msg.Length;
int idx = startpos;
while (idx < len)
{
char ch = msg[idx];
int numericCount = 0;
while (numericCount < 13 && isDigit(ch))
{
numericCount++;
//textCount++;
int i = idx + numericCount;
if (i >= len)
{
break;
}
ch = msg[i];
}
if (numericCount >= 13)
{
return idx - startpos;
}
int textCount = 0;
while (textCount < 5 && isText(ch))
{
textCount++;
int i = idx + textCount;
if (i >= len)
{
break;
}
ch = msg[i];
}
if (textCount >= 5)
{
return idx - startpos;
}
ch = msg[idx];
//Check if character is encodable
//Sun returns a ASCII 63 (?) for a character that cannot be mapped. Let's hope all
//other VMs do the same
if (bytes[idx] == 63 && ch != '?')
{
throw new WriterException("Non-encodable character detected: " + ch + " (Unicode: " + (int)ch + ')');
}
idx++;
}
return idx - startpos;
}
}
}

View file

@ -5,13 +5,9 @@
<SchemaVersion>2.0</SchemaVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ApplicationIcon>
</ApplicationIcon>
<AssemblyKeyContainerName>
</AssemblyKeyContainerName>
<AssemblyName>zxing</AssemblyName>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
<DefaultClientScript>JScript</DefaultClientScript>
<DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
<DefaultTargetSchema>IE50</DefaultTargetSchema>
@ -20,8 +16,6 @@
<RootNamespace>zxing</RootNamespace>
<NoStandardLibraries>false</NoStandardLibraries>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<StartupObject>
</StartupObject>
<FileUpgradeFlags>
</FileUpgradeFlags>
<ProjectGuid>{6431CF13-7A7B-4602-B96A-47CDA6F0B008}</ProjectGuid>
@ -30,52 +24,39 @@
<OldToolsVersion>3.5</OldToolsVersion>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile />
<ProductVersion>10.0.0</ProductVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>
</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>.\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<OutputPath>.</OutputPath>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>
</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
<Optimize>false</Optimize>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib">
@ -114,7 +95,6 @@
<Compile Include="BarcodeFormat.cs" />
<Compile Include="Binarizer.cs" />
<Compile Include="BinaryBitmap.cs" />
<Compile Include="ChecksumException.cs" />
<Compile Include="client\result\AbstractDoCoMoResultParser.cs" />
<Compile Include="client\result\AddressBookAUResultParser.cs" />
<Compile Include="client\result\AddressBookDoCoMoResultParser.cs" />
@ -183,7 +163,6 @@
<Compile Include="datamatrix\detector\Detector.cs" />
<Compile Include="DecodeHintType.cs" />
<Compile Include="EncodeHintType.cs" />
<Compile Include="FormatException.cs" />
<Compile Include="LuminanceSource.cs" />
<Compile Include="maxicode\decoder\BitMatrixParser.cs" />
<Compile Include="maxicode\decoder\DecodedBitStreamParser.cs" />
@ -197,7 +176,6 @@
<Compile Include="multi\qrcode\detector\MultiDetector.cs" />
<Compile Include="multi\qrcode\detector\MultiFinderPatternFinder.cs" />
<Compile Include="multi\qrcode\QRCodeMultiReader.cs" />
<Compile Include="NotFoundException.cs" />
<Compile Include="oned\CodaBarReader.cs" />
<Compile Include="oned\CodaBarWriter.cs" />
<Compile Include="oned\Code128Reader.cs" />
@ -252,7 +230,6 @@
<Compile Include="oned\UPCEANReader.cs" />
<Compile Include="oned\UPCEANWriter.cs" />
<Compile Include="oned\UPCEReader.cs" />
<Compile Include="pdf417\decoder\BitMatrixParser.cs" />
<Compile Include="pdf417\decoder\DecodedBitStreamParser.cs" />
<Compile Include="pdf417\decoder\Decoder.cs" />
<Compile Include="pdf417\decoder\ec\ErrorCorrection.cs" />
@ -266,10 +243,7 @@
<Compile Include="pdf417\encoder\PDF417.cs" />
<Compile Include="pdf417\encoder\PDF417ErrorCorrection.cs" />
<Compile Include="pdf417\encoder\PDF417HighLevelEncoder.cs" />
<Compile Include="pdf417\encoder\PDF417Writer.cs" />
<Compile Include="pdf417\PDF417Reader.cs" />
<Compile Include="pdf417\RectangularArrays.cs" />
<Compile Include="PlanarYUVLuminanceSource.cs" />
<Compile Include="qrcode\decoder\BitMatrixParser.cs" />
<Compile Include="qrcode\decoder\DataBlock.cs" />
<Compile Include="qrcode\decoder\DataMask.cs" />
@ -304,6 +278,21 @@
<Compile Include="Writer.cs" />
<Compile Include="WriterException.cs" />
<Compile Include="oned\Code39Writer.cs" />
<Compile Include="pdf417\PDF417Common.cs" />
<Compile Include="pdf417\PDF417ResultMetadata.cs" />
<Compile Include="pdf417\PDF417Writer.cs" />
<Compile Include="pdf417\decoder\BarcodeMetadata.cs" />
<Compile Include="pdf417\decoder\BarcodeValue.cs" />
<Compile Include="pdf417\decoder\BoundingBox.cs" />
<Compile Include="pdf417\decoder\Codeword.cs" />
<Compile Include="pdf417\decoder\DetectionResult.cs" />
<Compile Include="pdf417\decoder\DetectionResultColumn.cs" />
<Compile Include="pdf417\decoder\DetectionResultRowIndicatorColumn.cs" />
<Compile Include="pdf417\decoder\PDF417CodewordDecoder.cs" />
<Compile Include="pdf417\decoder\PDF417ScanningDecoder.cs" />
<Compile Include="pdf417\detector\BitMatrixExtensions.cs" />
<Compile Include="pdf417\detector\PDF417DetectorResult.cs" />
<Compile Include="pdf417\encoder\PDF417EncodingOptions.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="client\result\optional\" />
@ -315,4 +304,4 @@
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
</Project>