init commit
This commit is contained in:
@@ -0,0 +1,406 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using MessagingToolkit.QRCode.Codec.Data;
|
||||
using MessagingToolkit.QRCode.Codec.Ecc;
|
||||
using MessagingToolkit.QRCode.Codec.Reader;
|
||||
using MessagingToolkit.QRCode.Codec.Util;
|
||||
using MessagingToolkit.QRCode.ExceptionHandler;
|
||||
using MessagingToolkit.QRCode.Geom;
|
||||
|
||||
namespace MessagingToolkit.QRCode.Codec;
|
||||
|
||||
public class QRCodeDecoder
|
||||
{
|
||||
internal class DecodeResult
|
||||
{
|
||||
internal int numCorrections;
|
||||
|
||||
internal bool correctionSucceeded;
|
||||
|
||||
internal sbyte[] decodedBytes;
|
||||
|
||||
private QRCodeDecoder enclosingInstance;
|
||||
|
||||
public virtual sbyte[] DecodedBytes => decodedBytes;
|
||||
|
||||
public virtual int NumErrors => numCorrections;
|
||||
|
||||
public virtual bool CorrectionSucceeded => correctionSucceeded;
|
||||
|
||||
public QRCodeDecoder Enclosing_Instance => enclosingInstance;
|
||||
|
||||
public DecodeResult(QRCodeDecoder enclosingInstance, sbyte[] decodedBytes, int numErrors, bool correctionSucceeded)
|
||||
{
|
||||
InitBlock(enclosingInstance);
|
||||
this.decodedBytes = decodedBytes;
|
||||
numCorrections = numErrors;
|
||||
this.correctionSucceeded = correctionSucceeded;
|
||||
}
|
||||
|
||||
private void InitBlock(QRCodeDecoder enclosingInstance)
|
||||
{
|
||||
this.enclosingInstance = enclosingInstance;
|
||||
}
|
||||
}
|
||||
|
||||
internal QRCodeSymbol qrCodeSymbol;
|
||||
|
||||
internal int numTryDecode;
|
||||
|
||||
internal ArrayList results;
|
||||
|
||||
internal ArrayList lastResults = ArrayList.Synchronized(new ArrayList(10));
|
||||
|
||||
internal static DebugCanvas canvas;
|
||||
|
||||
internal QRCodeImageReader imageReader;
|
||||
|
||||
internal int numLastCorrections;
|
||||
|
||||
internal bool correctionSucceeded;
|
||||
|
||||
public static DebugCanvas Canvas
|
||||
{
|
||||
get
|
||||
{
|
||||
return canvas;
|
||||
}
|
||||
set
|
||||
{
|
||||
canvas = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual Point[] AdjustPoints
|
||||
{
|
||||
get
|
||||
{
|
||||
ArrayList arrayList = ArrayList.Synchronized(new ArrayList(10));
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
arrayList.Add(new Point(1, 1));
|
||||
}
|
||||
int num = 0;
|
||||
int num2 = 0;
|
||||
for (int num3 = 0; num3 > -4; num3--)
|
||||
{
|
||||
for (int num4 = 0; num4 > -4; num4--)
|
||||
{
|
||||
if (num4 != num3 && (num4 + num3) % 2 == 0)
|
||||
{
|
||||
arrayList.Add(new Point(num4 - num, num3 - num2));
|
||||
num = num4;
|
||||
num2 = num3;
|
||||
}
|
||||
}
|
||||
}
|
||||
Point[] array = new Point[arrayList.Count];
|
||||
for (int j = 0; j < array.Length; j++)
|
||||
{
|
||||
array[j] = (Point)arrayList[j];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
public QRCodeDecoder()
|
||||
{
|
||||
numTryDecode = 0;
|
||||
results = ArrayList.Synchronized(new ArrayList(10));
|
||||
canvas = new DebugCanvasAdapter();
|
||||
}
|
||||
|
||||
public virtual sbyte[] decodeBytes(QRCodeImage qrCodeImage)
|
||||
{
|
||||
Point[] adjustPoints = AdjustPoints;
|
||||
ArrayList arrayList = ArrayList.Synchronized(new ArrayList(10));
|
||||
while (numTryDecode < adjustPoints.Length)
|
||||
{
|
||||
try
|
||||
{
|
||||
DecodeResult decodeResult = decode(qrCodeImage, adjustPoints[numTryDecode]);
|
||||
if (decodeResult.CorrectionSucceeded)
|
||||
{
|
||||
return decodeResult.DecodedBytes;
|
||||
}
|
||||
arrayList.Add(decodeResult);
|
||||
canvas.println("Decoding succeeded but could not correct");
|
||||
canvas.println("all errors. Retrying..");
|
||||
}
|
||||
catch (DecodingFailedException ex)
|
||||
{
|
||||
if (ex.Message.IndexOf("Finder Pattern") >= 0)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
numTryDecode++;
|
||||
}
|
||||
}
|
||||
if (arrayList.Count == 0)
|
||||
{
|
||||
throw new DecodingFailedException("Give up decoding");
|
||||
}
|
||||
int num = -1;
|
||||
int num2 = int.MaxValue;
|
||||
for (int i = 0; i < arrayList.Count; i++)
|
||||
{
|
||||
DecodeResult decodeResult = (DecodeResult)arrayList[i];
|
||||
if (decodeResult.NumErrors < num2)
|
||||
{
|
||||
num2 = decodeResult.NumErrors;
|
||||
num = i;
|
||||
}
|
||||
}
|
||||
canvas.println("All trials need for correct error");
|
||||
canvas.println("Reporting #" + num + " that,");
|
||||
canvas.println("corrected minimum errors (" + num2 + ")");
|
||||
canvas.println("Decoding finished.");
|
||||
return ((DecodeResult)arrayList[num]).DecodedBytes;
|
||||
}
|
||||
|
||||
public virtual string decode(QRCodeImage qrCodeImage, Encoding encoding)
|
||||
{
|
||||
sbyte[] array = decodeBytes(qrCodeImage);
|
||||
byte[] array2 = new byte[array.Length];
|
||||
Buffer.BlockCopy(array, 0, array2, 0, array2.Length);
|
||||
return encoding.GetString(array2);
|
||||
}
|
||||
|
||||
public virtual string decode(QRCodeImage qrCodeImage)
|
||||
{
|
||||
sbyte[] array = decodeBytes(qrCodeImage);
|
||||
byte[] array2 = new byte[array.Length];
|
||||
Buffer.BlockCopy(array, 0, array2, 0, array2.Length);
|
||||
Encoding encoding = ((!QRCodeUtility.IsUnicode(array2)) ? Encoding.ASCII : Encoding.Unicode);
|
||||
return encoding.GetString(array2);
|
||||
}
|
||||
|
||||
internal virtual DecodeResult decode(QRCodeImage qrCodeImage, Point adjust)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (numTryDecode == 0)
|
||||
{
|
||||
canvas.println("Decoding started");
|
||||
int[][] image = imageToIntArray(qrCodeImage);
|
||||
imageReader = new QRCodeImageReader();
|
||||
qrCodeSymbol = imageReader.getQRCodeSymbol(image);
|
||||
}
|
||||
else
|
||||
{
|
||||
canvas.println("--");
|
||||
canvas.println("Decoding restarted #" + numTryDecode);
|
||||
qrCodeSymbol = imageReader.getQRCodeSymbolWithAdjustedGrid(adjust);
|
||||
}
|
||||
}
|
||||
catch (SymbolNotFoundException ex)
|
||||
{
|
||||
throw new DecodingFailedException(ex.Message);
|
||||
}
|
||||
canvas.println("Created QRCode symbol.");
|
||||
canvas.println("Reading symbol.");
|
||||
canvas.println("Version: " + qrCodeSymbol.VersionReference);
|
||||
canvas.println("Mask pattern: " + qrCodeSymbol.MaskPatternRefererAsString);
|
||||
int[] blocks = qrCodeSymbol.Blocks;
|
||||
canvas.println("Correcting data errors.");
|
||||
blocks = correctDataBlocks(blocks);
|
||||
try
|
||||
{
|
||||
sbyte[] decodedByteArray = getDecodedByteArray(blocks, qrCodeSymbol.Version, qrCodeSymbol.NumErrorCollectionCode);
|
||||
return new DecodeResult(this, decodedByteArray, numLastCorrections, correctionSucceeded);
|
||||
}
|
||||
catch (InvalidDataBlockException ex2)
|
||||
{
|
||||
canvas.println(ex2.Message);
|
||||
throw new DecodingFailedException(ex2.Message);
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual int[][] imageToIntArray(QRCodeImage image)
|
||||
{
|
||||
int width = image.Width;
|
||||
int height = image.Height;
|
||||
int[][] array = new int[width][];
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
array[i] = new int[height];
|
||||
}
|
||||
for (int j = 0; j < height; j++)
|
||||
{
|
||||
for (int k = 0; k < width; k++)
|
||||
{
|
||||
array[k][j] = image.getPixel(k, j);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal virtual int[] correctDataBlocks(int[] blocks)
|
||||
{
|
||||
int num = 0;
|
||||
int dataCapacity = qrCodeSymbol.DataCapacity;
|
||||
int[] array = new int[dataCapacity];
|
||||
int numErrorCollectionCode = qrCodeSymbol.NumErrorCollectionCode;
|
||||
int numRSBlocks = qrCodeSymbol.NumRSBlocks;
|
||||
int num2 = numErrorCollectionCode / numRSBlocks;
|
||||
if (numRSBlocks == 1)
|
||||
{
|
||||
ReedSolomon reedSolomon = new ReedSolomon(blocks, num2);
|
||||
reedSolomon.correct();
|
||||
num += reedSolomon.NumCorrectedErrors;
|
||||
if (num > 0)
|
||||
{
|
||||
canvas.println(Convert.ToString(num) + " data errors corrected.");
|
||||
}
|
||||
else
|
||||
{
|
||||
canvas.println("No errors found.");
|
||||
}
|
||||
numLastCorrections = num;
|
||||
correctionSucceeded = reedSolomon.CorrectionSucceeded;
|
||||
return blocks;
|
||||
}
|
||||
int num3 = dataCapacity % numRSBlocks;
|
||||
if (num3 == 0)
|
||||
{
|
||||
int num4 = dataCapacity / numRSBlocks;
|
||||
int[][] array2 = new int[numRSBlocks][];
|
||||
for (int i = 0; i < numRSBlocks; i++)
|
||||
{
|
||||
array2[i] = new int[num4];
|
||||
}
|
||||
int[][] array3 = array2;
|
||||
for (int i = 0; i < numRSBlocks; i++)
|
||||
{
|
||||
for (int j = 0; j < num4; j++)
|
||||
{
|
||||
array3[i][j] = blocks[j * numRSBlocks + i];
|
||||
}
|
||||
ReedSolomon reedSolomon = new ReedSolomon(array3[i], num2);
|
||||
reedSolomon.correct();
|
||||
num += reedSolomon.NumCorrectedErrors;
|
||||
correctionSucceeded = reedSolomon.CorrectionSucceeded;
|
||||
}
|
||||
int num5 = 0;
|
||||
for (int i = 0; i < numRSBlocks; i++)
|
||||
{
|
||||
for (int j = 0; j < num4 - num2; j++)
|
||||
{
|
||||
array[num5++] = array3[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int num6 = dataCapacity / numRSBlocks;
|
||||
int num7 = dataCapacity / numRSBlocks + 1;
|
||||
int num8 = numRSBlocks - num3;
|
||||
int[][] array4 = new int[num8][];
|
||||
for (int k = 0; k < num8; k++)
|
||||
{
|
||||
array4[k] = new int[num6];
|
||||
}
|
||||
int[][] array5 = array4;
|
||||
int[][] array6 = new int[num3][];
|
||||
for (int l = 0; l < num3; l++)
|
||||
{
|
||||
array6[l] = new int[num7];
|
||||
}
|
||||
int[][] array7 = array6;
|
||||
for (int i = 0; i < numRSBlocks; i++)
|
||||
{
|
||||
int num9;
|
||||
ReedSolomon reedSolomon;
|
||||
if (i < num8)
|
||||
{
|
||||
num9 = 0;
|
||||
for (int j = 0; j < num6; j++)
|
||||
{
|
||||
if (j == num6 - num2)
|
||||
{
|
||||
num9 = num3;
|
||||
}
|
||||
array5[i][j] = blocks[j * numRSBlocks + i + num9];
|
||||
}
|
||||
reedSolomon = new ReedSolomon(array5[i], num2);
|
||||
reedSolomon.correct();
|
||||
num += reedSolomon.NumCorrectedErrors;
|
||||
correctionSucceeded = reedSolomon.CorrectionSucceeded;
|
||||
continue;
|
||||
}
|
||||
num9 = 0;
|
||||
for (int j = 0; j < num7; j++)
|
||||
{
|
||||
if (j == num6 - num2)
|
||||
{
|
||||
num9 = num8;
|
||||
}
|
||||
array7[i - num8][j] = blocks[j * numRSBlocks + i - num9];
|
||||
}
|
||||
reedSolomon = new ReedSolomon(array7[i - num8], num2);
|
||||
reedSolomon.correct();
|
||||
num += reedSolomon.NumCorrectedErrors;
|
||||
correctionSucceeded = reedSolomon.CorrectionSucceeded;
|
||||
}
|
||||
int num5 = 0;
|
||||
for (int i = 0; i < numRSBlocks; i++)
|
||||
{
|
||||
if (i < num8)
|
||||
{
|
||||
for (int j = 0; j < num6 - num2; j++)
|
||||
{
|
||||
array[num5++] = array5[i][j];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < num7 - num2; j++)
|
||||
{
|
||||
array[num5++] = array7[i - num8][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num > 0)
|
||||
{
|
||||
canvas.println(Convert.ToString(num) + " data errors corrected.");
|
||||
}
|
||||
else
|
||||
{
|
||||
canvas.println("No errors found.");
|
||||
}
|
||||
numLastCorrections = num;
|
||||
return array;
|
||||
}
|
||||
|
||||
internal virtual sbyte[] getDecodedByteArray(int[] blocks, int version, int numErrorCorrectionCode)
|
||||
{
|
||||
QRCodeDataBlockReader qRCodeDataBlockReader = new QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode);
|
||||
try
|
||||
{
|
||||
return qRCodeDataBlockReader.DataByte;
|
||||
}
|
||||
catch (InvalidDataBlockException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual string getDecodedString(int[] blocks, int version, int numErrorCorrectionCode)
|
||||
{
|
||||
string text = null;
|
||||
QRCodeDataBlockReader qRCodeDataBlockReader = new QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode);
|
||||
try
|
||||
{
|
||||
return qRCodeDataBlockReader.DataString;
|
||||
}
|
||||
catch (IndexOutOfRangeException ex)
|
||||
{
|
||||
throw new InvalidDataBlockException(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user