Files
SuperVPN/output/Libraries/MessagingToolkit.QRCode/MessagingToolkit/QRCode/Codec/Reader/QRCodeImageReader.cs
2025-10-09 09:57:24 +09:00

544 lines
14 KiB
C#

using System;
using System.Collections;
using MessagingToolkit.QRCode.Codec.Data;
using MessagingToolkit.QRCode.Codec.Reader.Pattern;
using MessagingToolkit.QRCode.Codec.Util;
using MessagingToolkit.QRCode.ExceptionHandler;
using MessagingToolkit.QRCode.Geom;
namespace MessagingToolkit.QRCode.Codec.Reader;
public class QRCodeImageReader
{
private class ModulePitch
{
public int top;
public int left;
public int bottom;
public int right;
private QRCodeImageReader enclosingInstance;
public QRCodeImageReader Enclosing_Instance => enclosingInstance;
public ModulePitch(QRCodeImageReader enclosingInstance)
{
InitBlock(enclosingInstance);
}
private void InitBlock(QRCodeImageReader enclosingInstance)
{
this.enclosingInstance = enclosingInstance;
}
}
public const bool POINT_DARK = true;
public const bool POINT_LIGHT = false;
internal DebugCanvas canvas;
public static int DECIMAL_POINT = 21;
internal SamplingGrid samplingGrid;
internal bool[][] bitmap;
public QRCodeImageReader()
{
canvas = QRCodeDecoder.Canvas;
}
internal virtual bool[][] applyMedianFilter(bool[][] image, int threshold)
{
bool[][] array = new bool[image.Length][];
for (int i = 0; i < image.Length; i++)
{
array[i] = new bool[image[0].Length];
}
for (int j = 1; j < image[0].Length - 1; j++)
{
for (int k = 1; k < image.Length - 1; k++)
{
int num = 0;
for (int l = -1; l < 2; l++)
{
for (int m = -1; m < 2; m++)
{
if (image[k + m][j + l])
{
num++;
}
}
}
if (num > threshold)
{
array[k][j] = true;
}
}
}
return array;
}
internal virtual bool[][] applyCrossMaskingMedianFilter(bool[][] image, int threshold)
{
bool[][] array = new bool[image.Length][];
for (int i = 0; i < image.Length; i++)
{
array[i] = new bool[image[0].Length];
}
for (int j = 2; j < image[0].Length - 2; j++)
{
for (int k = 2; k < image.Length - 2; k++)
{
int num = 0;
for (int l = -2; l < 3; l++)
{
if (image[k + l][j])
{
num++;
}
if (image[k][j + l])
{
num++;
}
}
if (num > threshold)
{
array[k][j] = true;
}
}
}
return array;
}
internal virtual bool[][] filterImage(int[][] image)
{
imageToGrayScale(image);
return grayScaleToBitmap(image);
}
internal virtual void imageToGrayScale(int[][] image)
{
for (int i = 0; i < image[0].Length; i++)
{
for (int j = 0; j < image.Length; j++)
{
int num = (image[j][i] >> 16) & 0xFF;
int num2 = (image[j][i] >> 8) & 0xFF;
int num3 = image[j][i] & 0xFF;
int num4 = (num * 30 + num2 * 59 + num3 * 11) / 100;
image[j][i] = num4;
}
}
}
internal virtual bool[][] grayScaleToBitmap(int[][] grayScale)
{
int[][] middleBrightnessPerArea = getMiddleBrightnessPerArea(grayScale);
int num = middleBrightnessPerArea.Length;
int num2 = grayScale.Length / num;
int num3 = grayScale[0].Length / num;
bool[][] array = new bool[grayScale.Length][];
for (int i = 0; i < grayScale.Length; i++)
{
array[i] = new bool[grayScale[0].Length];
}
for (int j = 0; j < num; j++)
{
for (int k = 0; k < num; k++)
{
for (int l = 0; l < num3; l++)
{
for (int m = 0; m < num2; m++)
{
array[num2 * k + m][num3 * j + l] = ((grayScale[num2 * k + m][num3 * j + l] < middleBrightnessPerArea[k][j]) ? true : false);
}
}
}
}
return array;
}
internal virtual int[][] getMiddleBrightnessPerArea(int[][] image)
{
int num = 4;
int num2 = image.Length / num;
int num3 = image[0].Length / num;
int[][][] array = new int[num][][];
for (int i = 0; i < num; i++)
{
array[i] = new int[num][];
for (int j = 0; j < num; j++)
{
array[i][j] = new int[2];
}
}
for (int k = 0; k < num; k++)
{
for (int l = 0; l < num; l++)
{
array[l][k][0] = 255;
for (int m = 0; m < num3; m++)
{
for (int n = 0; n < num2; n++)
{
int num4 = image[num2 * l + n][num3 * k + m];
if (num4 < array[l][k][0])
{
array[l][k][0] = num4;
}
if (num4 > array[l][k][1])
{
array[l][k][1] = num4;
}
}
}
}
}
int[][] array2 = new int[num][];
for (int num5 = 0; num5 < num; num5++)
{
array2[num5] = new int[num];
}
for (int k = 0; k < num; k++)
{
for (int l = 0; l < num; l++)
{
array2[l][k] = (array[l][k][0] + array[l][k][1]) / 2;
}
}
return array2;
}
public virtual QRCodeSymbol getQRCodeSymbol(int[][] image)
{
int num = ((image.Length < image[0].Length) ? image[0].Length : image.Length);
DECIMAL_POINT = 23 - QRCodeUtility.sqrt(num / 256);
bitmap = filterImage(image);
canvas.println("Drawing matrix.");
canvas.drawMatrix(bitmap);
canvas.println("Scanning Finder Pattern.");
FinderPattern finderPattern = null;
try
{
finderPattern = FinderPattern.findFinderPattern(bitmap);
}
catch (FinderPatternNotFoundException)
{
canvas.println("Not found, now retrying...");
bitmap = applyCrossMaskingMedianFilter(bitmap, 5);
canvas.drawMatrix(bitmap);
for (int i = 0; i < 1000000000; i++)
{
}
try
{
finderPattern = FinderPattern.findFinderPattern(bitmap);
}
catch (FinderPatternNotFoundException ex2)
{
throw new SymbolNotFoundException(ex2.Message);
}
catch (VersionInformationException ex3)
{
throw new SymbolNotFoundException(ex3.Message);
}
}
catch (VersionInformationException ex4)
{
throw new SymbolNotFoundException(ex4.Message);
}
canvas.println("FinderPattern at");
string str = finderPattern.getCenter(0).ToString() + finderPattern.getCenter(1).ToString() + finderPattern.getCenter(2).ToString();
canvas.println(str);
int[] angle = finderPattern.getAngle();
canvas.println("Angle*4098: Sin " + Convert.ToString(angle[0]) + " Cos " + Convert.ToString(angle[1]));
int version = finderPattern.Version;
canvas.println("Version: " + Convert.ToString(version));
if (version < 1 || version > 40)
{
throw new InvalidVersionException("Invalid version: " + version);
}
AlignmentPattern alignmentPattern = null;
try
{
alignmentPattern = AlignmentPattern.findAlignmentPattern(bitmap, finderPattern);
}
catch (AlignmentPatternNotFoundException ex5)
{
throw new SymbolNotFoundException(ex5.Message);
}
int num2 = alignmentPattern.getCenter().Length;
canvas.println("AlignmentPatterns at");
for (int j = 0; j < num2; j++)
{
string text = "";
for (int k = 0; k < num2; k++)
{
text += alignmentPattern.getCenter()[k][j].ToString();
}
canvas.println(text);
}
canvas.println("Creating sampling grid.");
samplingGrid = getSamplingGrid(finderPattern, alignmentPattern);
canvas.println("Reading grid.");
bool[][] array = null;
try
{
array = getQRCodeMatrix(bitmap, samplingGrid);
}
catch (IndexOutOfRangeException)
{
throw new SymbolNotFoundException("Sampling grid exceeded image boundary");
}
return new QRCodeSymbol(array);
}
public virtual QRCodeSymbol getQRCodeSymbolWithAdjustedGrid(Point adjust)
{
if (bitmap == null || samplingGrid == null)
{
throw new SystemException("This method must be called after QRCodeImageReader.getQRCodeSymbol() called");
}
samplingGrid.adjust(adjust);
canvas.println("Sampling grid adjusted d(" + adjust.X + "," + adjust.Y + ")");
bool[][] array = null;
try
{
array = getQRCodeMatrix(bitmap, samplingGrid);
}
catch (IndexOutOfRangeException)
{
throw new SymbolNotFoundException("Sampling grid exceeded image boundary");
}
return new QRCodeSymbol(array);
}
internal virtual SamplingGrid getSamplingGrid(FinderPattern finderPattern, AlignmentPattern alignmentPattern)
{
Point[][] center = alignmentPattern.getCenter();
int version = finderPattern.Version;
int num = version / 7 + 2;
center[0][0] = finderPattern.getCenter(0);
center[num - 1][0] = finderPattern.getCenter(1);
center[0][num - 1] = finderPattern.getCenter(2);
int num2 = num - 1;
SamplingGrid samplingGrid = new SamplingGrid(num2);
Axis axis = new Axis(finderPattern.getAngle(), finderPattern.getModuleSize());
for (int i = 0; i < num2; i++)
{
for (int j = 0; j < num2; j++)
{
ModulePitch modulePitch = new ModulePitch(this);
Line line = new Line();
Line line2 = new Line();
axis.ModulePitch = finderPattern.getModuleSize();
Point[][] logicalCenter = AlignmentPattern.getLogicalCenter(finderPattern);
Point point = center[j][i];
Point point2 = center[j + 1][i];
Point point3 = center[j][i + 1];
Point point4 = center[j + 1][i + 1];
Point point5 = logicalCenter[j][i];
Point point6 = logicalCenter[j + 1][i];
Point point7 = logicalCenter[j][i + 1];
Point point8 = logicalCenter[j + 1][i + 1];
if (j == 0 && i == 0)
{
if (num2 == 1)
{
point = axis.translate(point, -3, -3);
point2 = axis.translate(point2, 3, -3);
point3 = axis.translate(point3, -3, 3);
point4 = axis.translate(point4, 6, 6);
point5.translate(-6, -6);
point6.translate(3, -3);
point7.translate(-3, 3);
point8.translate(6, 6);
}
else
{
point = axis.translate(point, -3, -3);
point2 = axis.translate(point2, 0, -6);
point3 = axis.translate(point3, -6, 0);
point5.translate(-6, -6);
point6.translate(0, -6);
point7.translate(-6, 0);
}
}
else if (j == 0 && i == num2 - 1)
{
point = axis.translate(point, -6, 0);
point3 = axis.translate(point3, -3, 3);
point4 = axis.translate(point4, 0, 6);
point5.translate(-6, 0);
point7.translate(-6, 6);
point8.translate(0, 6);
}
else if (j == num2 - 1 && i == 0)
{
point = axis.translate(point, 0, -6);
point2 = axis.translate(point2, 3, -3);
point4 = axis.translate(point4, 6, 0);
point5.translate(0, -6);
point6.translate(6, -6);
point8.translate(6, 0);
}
else if (j == num2 - 1 && i == num2 - 1)
{
point3 = axis.translate(point3, 0, 6);
point2 = axis.translate(point2, 6, 0);
point4 = axis.translate(point4, 6, 6);
point7.translate(0, 6);
point6.translate(6, 0);
point8.translate(6, 6);
}
else if (j == 0)
{
point = axis.translate(point, -6, 0);
point3 = axis.translate(point3, -6, 0);
point5.translate(-6, 0);
point7.translate(-6, 0);
}
else if (j == num2 - 1)
{
point2 = axis.translate(point2, 6, 0);
point4 = axis.translate(point4, 6, 0);
point6.translate(6, 0);
point8.translate(6, 0);
}
else if (i == 0)
{
point = axis.translate(point, 0, -6);
point2 = axis.translate(point2, 0, -6);
point5.translate(0, -6);
point6.translate(0, -6);
}
else if (i == num2 - 1)
{
point3 = axis.translate(point3, 0, 6);
point4 = axis.translate(point4, 0, 6);
point7.translate(0, 6);
point8.translate(0, 6);
}
if (j == 0)
{
point6.translate(1, 0);
point8.translate(1, 0);
}
else
{
point5.translate(-1, 0);
point7.translate(-1, 0);
}
if (i == 0)
{
point7.translate(0, 1);
point8.translate(0, 1);
}
else
{
point5.translate(0, -1);
point6.translate(0, -1);
}
int num3 = point6.X - point5.X;
int num4 = point7.Y - point5.Y;
if (version < 7)
{
num3 += 3;
num4 += 3;
}
modulePitch.top = getAreaModulePitch(point, point2, num3 - 1);
modulePitch.left = getAreaModulePitch(point, point3, num4 - 1);
modulePitch.bottom = getAreaModulePitch(point3, point4, num3 - 1);
modulePitch.right = getAreaModulePitch(point2, point4, num4 - 1);
line.setP1(point);
line2.setP1(point);
line.setP2(point3);
line2.setP2(point2);
samplingGrid.initGrid(j, i, num3, num4);
for (int k = 0; k < num3; k++)
{
Line line3 = new Line(line.getP1(), line.getP2());
axis.Origin = line3.getP1();
axis.ModulePitch = modulePitch.top;
line3.setP1(axis.translate(k, 0));
axis.Origin = line3.getP2();
axis.ModulePitch = modulePitch.bottom;
line3.setP2(axis.translate(k, 0));
samplingGrid.setXLine(j, i, k, line3);
}
for (int k = 0; k < num4; k++)
{
Line line4 = new Line(line2.getP1(), line2.getP2());
axis.Origin = line4.getP1();
axis.ModulePitch = modulePitch.left;
line4.setP1(axis.translate(0, k));
axis.Origin = line4.getP2();
axis.ModulePitch = modulePitch.right;
line4.setP2(axis.translate(0, k));
samplingGrid.setYLine(j, i, k, line4);
}
}
}
return samplingGrid;
}
internal virtual int getAreaModulePitch(Point start, Point end, int logicalDistance)
{
Line line = new Line(start, end);
int length = line.Length;
return (length << DECIMAL_POINT) / logicalDistance;
}
internal virtual bool[][] getQRCodeMatrix(bool[][] image, SamplingGrid gridLines)
{
int totalWidth = gridLines.TotalWidth;
canvas.println("gridSize=" + totalWidth);
Point point = null;
bool[][] array = new bool[totalWidth][];
for (int i = 0; i < totalWidth; i++)
{
array[i] = new bool[totalWidth];
}
for (int j = 0; j < gridLines.getHeight(); j++)
{
for (int k = 0; k < gridLines.getWidth(); k++)
{
ArrayList arrayList = ArrayList.Synchronized(new ArrayList(10));
for (int l = 0; l < gridLines.getHeight(k, j); l++)
{
for (int m = 0; m < gridLines.getWidth(k, j); m++)
{
int x = gridLines.getXLine(k, j, m).getP1().X;
int y = gridLines.getXLine(k, j, m).getP1().Y;
int x2 = gridLines.getXLine(k, j, m).getP2().X;
int y2 = gridLines.getXLine(k, j, m).getP2().Y;
int x3 = gridLines.getYLine(k, j, l).getP1().X;
int y3 = gridLines.getYLine(k, j, l).getP1().Y;
int x4 = gridLines.getYLine(k, j, l).getP2().X;
int y4 = gridLines.getYLine(k, j, l).getP2().Y;
int num = (y2 - y) * (x3 - x4) - (y4 - y3) * (x - x2);
int num2 = (x * y2 - x2 * y) * (x3 - x4) - (x3 * y4 - x4 * y3) * (x - x2);
int num3 = (x3 * y4 - x4 * y3) * (y2 - y) - (x * y2 - x2 * y) * (y4 - y3);
array[gridLines.getX(k, m)][gridLines.getY(j, l)] = image[num2 / num][num3 / num];
if (j == gridLines.getHeight() - 1 && k == gridLines.getWidth() - 1 && l == gridLines.getHeight(k, j) - 1 && m == gridLines.getWidth(k, j) - 1)
{
point = new Point(num2 / num, num3 / num);
}
}
}
}
}
if (point.X > image.Length - 1 || point.Y > image[0].Length - 1)
{
throw new IndexOutOfRangeException("Sampling grid pointed out of image");
}
canvas.drawPoint(point, Color_Fields.BLUE);
return array;
}
}