最近手头的软件项目需要用到指纹采集器,于是上某宝淘了下,发现成熟的指纹采集模块厂家不多。找了一家销量最高的。价格也挺便宜的。
大多数都有桌面版和IE浏览器插件,但是都没有谷歌浏览器版本的。郁闷!
项目是基于谷歌浏览器做的,但是谷歌浏览器不支持activeX控件。网上也有可以让activeX控件适配谷歌浏览器的方法,但是都不保证可用。本着网上没有就自己造的原则,我开始了适配之旅。
曲线救国,既然浏览器端不行那就走客户端,我的思路是这样的:
1、在桌面搭建websocket服务端,监听某个特定的端口的websocket连接 。服务端使用官方提供的客户端SDK来做采集指纹操作。采集到指纹后把数据转换成红色的指纹图片,然后把图片转成base64数据,传给客户端。
2、客户端,即谷歌浏览器端,通过websocket和服务端的服务进行连接,客户端连接服务后,服务端自动记录连接ID,通过该ID把base64格式图片数据发送到浏览器,浏览器把图片进行转换,变成图片显示。效果如下
以上为思路,说干就干,上代码前先把必须的websocket包安装一下,在vs2019里,项目-》引用,右键,管理NuGet程序包,搜索并安装SuperWebSocket.
下面是代码:
服务端主程序:
using libzkfpcsharp;
using Microsoft.Win32;
using SuperSocket.SocketBase.Config;
using SuperWebSocket;
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace FP_Service
{
public partial class Form1 : Form
{
IntPtr mDevHandle = IntPtr.Zero;
IntPtr FormHandle = IntPtr.Zero;
string strBase64 = "";
private bool isclose;
bool bIsTimeToDie = false;
byte[] FPBuffer;
byte[][] RegTmps = new byte[3][];
byte[] CapTmp = new byte[2048];
int cbCapTmp = 2048;
private int mfpWidth = 0;
private int mfpHeight = 0;
private WebSocketServer mWebSocketServer;
private string mSessionID = "";
const int MESSAGE_CAPTURED_OK = 0x0400 + 6;
[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
FormHandle = this.Handle;
base.Left = Screen.GetBounds(this).Width - base.Width - 5;
base.Top = Screen.GetBounds(this).Height - base.Height - 50;
FirstAutoRun(true);//添加进系统服务,开机自启动。
CheckAutoRun(Application.ExecutablePath, true);//添加进系统服务,开机自启动。
int ret = zkfperrdef.ZKFP_ERR_OK;
if ((ret = zkfp2.Init()) == zkfperrdef.ZKFP_ERR_OK)
{
int nCount = zkfp2.GetDeviceCount();
if (nCount < 0)
{
zkfp2.Terminate();
label1.Text="未发现指纹采集设备!";
}
}
else
{
label1.Text = "初始化失败, 返回值为:" + ret;
}
//Setup();
ServerConfig config = new ServerConfig{
Ip = "127.0.0.1",
Port = 8891,
MaxConnectionNumber = 100,
Name = "FPServer"
};
mWebSocketServer = new WebSocketServer();
if (mWebSocketServer.Setup(config))
{
label1.Text = "初始化服务成功。";
mWebSocketServer.NewSessionConnected += MWebSocketServer_NewSessionConnected1;
}
else {
label1.Text = "初始化服务失败!";
}
if( mWebSocketServer.Start()) { label1.Text = "开启服务成功。";
} else { label1.Text = "开启服务失败!"; }
if (IntPtr.Zero == (mDevHandle = zkfp2.OpenDevice(0)))
{
label1.Text = "开启设备失败!";
return;
}
else
{
for (int i = 0; i < 3; i++)
{
RegTmps[i] = new byte[2048];
}
byte[] paramValue = new byte[4];
int size = 4;
zkfp2.GetParameters(mDevHandle, 1, paramValue, ref size);
zkfp2.ByteArray2Int(paramValue, ref mfpWidth);
size = 4;
zkfp2.GetParameters(mDevHandle, 2, paramValue, ref size);
zkfp2.ByteArray2Int(paramValue, ref mfpHeight);
FPBuffer = new byte[mfpWidth * mfpHeight];
Thread captureThread = new Thread(new ThreadStart(DoCapture));
captureThread.IsBackground = true;
captureThread.Start();
bIsTimeToDie = false;
label1.Text = "设备已连接";
}
}
private void DoCapture()
{
while (!bIsTimeToDie)
{
cbCapTmp = 2048;
int ret = zkfp2.AcquireFingerprint(mDevHandle, FPBuffer, CapTmp, ref cbCapTmp);
if (ret == zkfp.ZKFP_ERR_OK)
{
SendMessage(FormHandle, MESSAGE_CAPTURED_OK, IntPtr.Zero, IntPtr.Zero);
}
Thread.Sleep(200);
}
}
private string ToBase64(Bitmap bmp)
{
try
{
MemoryStream ms = new MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
byte[] arr = new byte[ms.Length];
ms.Position = 0;
ms.Read(arr, 0, (int)ms.Length);
ms.Close();
String strbaser64 = Convert.ToBase64String(arr);
return strbaser64;
}
catch (Exception ex)
{
MessageBox.Show("转换失败:" + ex.Message);
return "";
}
}
private static Bitmap UpdateColor(Bitmap bitmap)
{
int width = bitmap.Width;
int height = bitmap.Height;
Bitmap newmap = new Bitmap(width, height);
Color pixel;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
pixel = bitmap.GetPixel(i, j); // 获取原图的像素点颜色值
int r, g, b, a;
r = pixel.R;
g = pixel.G;
b = pixel.B;
a = pixel.A;
// 判断是否为白色背景
if ( b > 120|| r > 120 || g > 120)
{
newmap.SetPixel(i, j, Color.FromArgb(0,255, 255, 255));
}
else
{
newmap.SetPixel(i, j, Color.Red);
}
}
}
return newmap;
}
protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case MESSAGE_CAPTURED_OK:
{
MemoryStream ms = new MemoryStream();
BitmapFormat.GetBitmap(FPBuffer, mfpWidth, mfpHeight, ref ms);
Bitmap bmp = UpdateColor( new Bitmap(ms));
//Bitmap bmp =new Bitmap(ms);
strBase64 = ToBase64(bmp);
pictureBox2.Image = bmp;
foreach (WebSocketSession sendSession in mWebSocketServer.GetAllSessions())
{
if (sendSession.SessionID.Equals(mSessionID))
{
sendSession.Send(strBase64);
break;
}
}
}
break;
default:
base.DefWndProc(ref m);
break;
}
}
private void MWebSocketServer_NewSessionConnected1(WebSocketSession session)
{
mSessionID = session.SessionID;//客户端连接成功保存ID至session
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (!isclose)
{
e.Cancel = true;
base.Hide();
}
}
private void button2_Click(object sender, EventArgs e)
{
isclose = true;
this.Close();
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (checkBox1.Checked)
{
SetAutoRun(Application.ExecutablePath, false, true);
}
else
{
SetAutoRun(Application.ExecutablePath, true, true);
}
}
public void SetAutoRun(string fileName, bool isAutoRun, bool isCurrentUser)
{
RegistryKey reg = null;
try
{
if (!File.Exists(fileName))
{
throw new Exception("Not File!");
}
string name = fileName.Substring(fileName.LastIndexOf("\\") + 1);
if (isCurrentUser)
{
reg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (reg == null)
{
reg = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
}
if (isAutoRun)
{
if (reg.GetValue(name) == null)
{
reg.SetValue(name, fileName);
}
else if (!reg.GetValue(name).Equals(fileName))
{
reg.SetValue(name, fileName);
}
}
else
{
reg.DeleteValue(name);
}
}
else
{
reg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (reg == null)
{
reg = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
}
if (isAutoRun)
{
if (reg.GetValue(name) == null)
{
reg.SetValue(name, fileName);
}
else if (!reg.GetValue(name).Equals(fileName))
{
reg.SetValue(name, fileName);
}
}
else
{
reg.DeleteValue(name);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
finally
{
if (reg != null)
{
reg.Close();
}
}
}
public void FirstAutoRun(bool isCurrentUser)
{
RegistryKey reg = null;
try
{
string name = "Run";
if (isCurrentUser)
{
reg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\WC\\FPWebServer\\", true);
if (reg == null)
{
reg = Registry.CurrentUser.CreateSubKey("SOFTWARE\\WC\\FPWebServer\\");
}
if (reg.GetValue(name) == null)
{
this.SetAutoRun(Application.ExecutablePath, true, true);
reg.SetValue(name, true);
}
}
else
{
reg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\WC\\FPWebServer\\", true);
if (reg == null)
{
reg = Registry.LocalMachine.CreateSubKey("SOFTWARE\\WC\\FPWebServer\\");
}
if (reg.GetValue(name) == null)
{
this.SetAutoRun(Application.ExecutablePath, true, false);
reg.SetValue(name, true);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
finally
{
if (reg != null)
{
reg.Close();
}
}
}
public void CheckAutoRun(string fileName, bool isCurrentUser)
{
RegistryKey reg = null;
try
{
if (!File.Exists(fileName))
{
throw new Exception("Not File!");
}
string name = fileName.Substring(fileName.LastIndexOf("\\") + 1);
if (isCurrentUser)
{
reg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (reg == null)
{
reg = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
}
if (reg.GetValue(name) == null)
{
checkBox1.Checked = false;
}
else
{
checkBox1.Checked = true;
}
}
else
{
reg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (reg == null)
{
reg = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
}
if (reg.GetValue(name) == null)
{
checkBox1.Checked = false;
}
else
{
checkBox1.Checked = true;
}
}
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
finally
{
if (reg != null)
{
reg.Close();
}
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
mWebSocketServer.Stop();
}
private void button1_Click(object sender, EventArgs e)
{
int ret = zkfperrdef.ZKFP_ERR_OK;
if ((ret = zkfp2.Init()) == zkfperrdef.ZKFP_ERR_OK)
{
int nCount = zkfp2.GetDeviceCount();
if (nCount < 0)
{
zkfp2.Terminate();
label1.Text = "未发现指纹采集设备!";
}
}
else
{
label1.Text = "初始化失败, 返回值为:" + ret;
}
}
private void notifyIcon1_Click(object sender, EventArgs e)
{
if (base.Visible)
{
base.Hide();
return;
}
base.Show();
}
}
}
using libzkfpcsharp;
using Microsoft.Win32;
using SuperSocket.SocketBase.Config;
using SuperWebSocket;
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace FP_Service
{
public partial class Form1 : Form
{
IntPtr mDevHandle = IntPtr.Zero;
IntPtr FormHandle = IntPtr.Zero;
string strBase64 = "";
private bool isclose;
bool bIsTimeToDie = false;
byte[] FPBuffer;
byte[][] RegTmps = new byte[3][];
byte[] CapTmp = new byte[2048];
int cbCapTmp = 2048;
private int mfpWidth = 0;
private int mfpHeight = 0;
private WebSocketServer mWebSocketServer;
private string mSessionID = "";
const int MESSAGE_CAPTURED_OK = 0x0400 + 6;
[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
FormHandle = this.Handle;
base.Left = Screen.GetBounds(this).Width - base.Width - 5;
base.Top = Screen.GetBounds(this).Height - base.Height - 50;
FirstAutoRun(true);//添加进系统服务,开机自启动。
CheckAutoRun(Application.ExecutablePath, true);//添加进系统服务,开机自启动。
int ret = zkfperrdef.ZKFP_ERR_OK;
if ((ret = zkfp2.Init()) == zkfperrdef.ZKFP_ERR_OK)
{
int nCount = zkfp2.GetDeviceCount();
if (nCount < 0)
{
zkfp2.Terminate();
label1.Text="未发现指纹采集设备!";
}
}
else
{
label1.Text = "初始化失败, 返回值为:" + ret;
}
//Setup();
ServerConfig config = new ServerConfig{
Ip = "127.0.0.1",
Port = 8891,
MaxConnectionNumber = 100,
Name = "FPServer"
};
mWebSocketServer = new WebSocketServer();
if (mWebSocketServer.Setup(config))
{
label1.Text = "初始化服务成功。";
mWebSocketServer.NewSessionConnected += MWebSocketServer_NewSessionConnected1;
}
else {
label1.Text = "初始化服务失败!";
}
if( mWebSocketServer.Start()) { label1.Text = "开启服务成功。";
} else { label1.Text = "开启服务失败!"; }
if (IntPtr.Zero == (mDevHandle = zkfp2.OpenDevice(0)))
{
label1.Text = "开启设备失败!";
return;
}
else
{
for (int i = 0; i < 3; i++)
{
RegTmps[i] = new byte[2048];
}
byte[] paramValue = new byte[4];
int size = 4;
zkfp2.GetParameters(mDevHandle, 1, paramValue, ref size);
zkfp2.ByteArray2Int(paramValue, ref mfpWidth);
size = 4;
zkfp2.GetParameters(mDevHandle, 2, paramValue, ref size);
zkfp2.ByteArray2Int(paramValue, ref mfpHeight);
FPBuffer = new byte[mfpWidth * mfpHeight];
Thread captureThread = new Thread(new ThreadStart(DoCapture));
captureThread.IsBackground = true;
captureThread.Start();
bIsTimeToDie = false;
label1.Text = "设备已连接";
}
}
private void DoCapture()
{
while (!bIsTimeToDie)
{
cbCapTmp = 2048;
int ret = zkfp2.AcquireFingerprint(mDevHandle, FPBuffer, CapTmp, ref cbCapTmp);
if (ret == zkfp.ZKFP_ERR_OK)
{
SendMessage(FormHandle, MESSAGE_CAPTURED_OK, IntPtr.Zero, IntPtr.Zero);
}
Thread.Sleep(200);
}
}
private string ToBase64(Bitmap bmp)
{
try
{
MemoryStream ms = new MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
byte[] arr = new byte[ms.Length];
ms.Position = 0;
ms.Read(arr, 0, (int)ms.Length);
ms.Close();
String strbaser64 = Convert.ToBase64String(arr);
return strbaser64;
}
catch (Exception ex)
{
MessageBox.Show("转换失败:" + ex.Message);
return "";
}
}
private static Bitmap UpdateColor(Bitmap bitmap)
{
int width = bitmap.Width;
int height = bitmap.Height;
Bitmap newmap = new Bitmap(width, height);
Color pixel;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
pixel = bitmap.GetPixel(i, j); // 获取原图的像素点颜色值
int r, g, b, a;
r = pixel.R;
g = pixel.G;
b = pixel.B;
a = pixel.A;
// 判断是否为白色背景
if ( b > 120|| r > 120 || g > 120)
{
newmap.SetPixel(i, j, Color.FromArgb(0,255, 255, 255));
}
else
{
newmap.SetPixel(i, j, Color.Red);
}
}
}
return newmap;
}
protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case MESSAGE_CAPTURED_OK:
{
MemoryStream ms = new MemoryStream();
BitmapFormat.GetBitmap(FPBuffer, mfpWidth, mfpHeight, ref ms);
Bitmap bmp = UpdateColor( new Bitmap(ms));
//Bitmap bmp =new Bitmap(ms);
strBase64 = ToBase64(bmp);
pictureBox2.Image = bmp;
foreach (WebSocketSession sendSession in mWebSocketServer.GetAllSessions())
{
if (sendSession.SessionID.Equals(mSessionID))
{
sendSession.Send(strBase64);
break;
}
}
}
break;
default:
base.DefWndProc(ref m);
break;
}
}
private void MWebSocketServer_NewSessionConnected1(WebSocketSession session)
{
mSessionID = session.SessionID;//客户端连接成功保存ID至session
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (!isclose)
{
e.Cancel = true;
base.Hide();
}
}
private void button2_Click(object sender, EventArgs e)
{
isclose = true;
this.Close();
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (checkBox1.Checked)
{
SetAutoRun(Application.ExecutablePath, false, true);
}
else
{
SetAutoRun(Application.ExecutablePath, true, true);
}
}
public void SetAutoRun(string fileName, bool isAutoRun, bool isCurrentUser)
{
RegistryKey reg = null;
try
{
if (!File.Exists(fileName))
{
throw new Exception("Not File!");
}
string name = fileName.Substring(fileName.LastIndexOf("\\") + 1);
if (isCurrentUser)
{
reg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (reg == null)
{
reg = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
}
if (isAutoRun)
{
if (reg.GetValue(name) == null)
{
reg.SetValue(name, fileName);
}
else if (!reg.GetValue(name).Equals(fileName))
{
reg.SetValue(name, fileName);
}
}
else
{
reg.DeleteValue(name);
}
}
else
{
reg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (reg == null)
{
reg = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
}
if (isAutoRun)
{
if (reg.GetValue(name) == null)
{
reg.SetValue(name, fileName);
}
else if (!reg.GetValue(name).Equals(fileName))
{
reg.SetValue(name, fileName);
}
}
else
{
reg.DeleteValue(name);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
finally
{
if (reg != null)
{
reg.Close();
}
}
}
public void FirstAutoRun(bool isCurrentUser)
{
RegistryKey reg = null;
try
{
string name = "Run";
if (isCurrentUser)
{
reg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\WC\\FPWebServer\\", true);
if (reg == null)
{
reg = Registry.CurrentUser.CreateSubKey("SOFTWARE\\WC\\FPWebServer\\");
}
if (reg.GetValue(name) == null)
{
this.SetAutoRun(Application.ExecutablePath, true, true);
reg.SetValue(name, true);
}
}
else
{
reg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\WC\\FPWebServer\\", true);
if (reg == null)
{
reg = Registry.LocalMachine.CreateSubKey("SOFTWARE\\WC\\FPWebServer\\");
}
if (reg.GetValue(name) == null)
{
this.SetAutoRun(Application.ExecutablePath, true, false);
reg.SetValue(name, true);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
finally
{
if (reg != null)
{
reg.Close();
}
}
}
public void CheckAutoRun(string fileName, bool isCurrentUser)
{
RegistryKey reg = null;
try
{
if (!File.Exists(fileName))
{
throw new Exception("Not File!");
}
string name = fileName.Substring(fileName.LastIndexOf("\\") + 1);
if (isCurrentUser)
{
reg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (reg == null)
{
reg = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
}
if (reg.GetValue(name) == null)
{
checkBox1.Checked = false;
}
else
{
checkBox1.Checked = true;
}
}
else
{
reg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (reg == null)
{
reg = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
}
if (reg.GetValue(name) == null)
{
checkBox1.Checked = false;
}
else
{
checkBox1.Checked = true;
}
}
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
finally
{
if (reg != null)
{
reg.Close();
}
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
mWebSocketServer.Stop();
}
private void button1_Click(object sender, EventArgs e)
{
int ret = zkfperrdef.ZKFP_ERR_OK;
if ((ret = zkfp2.Init()) == zkfperrdef.ZKFP_ERR_OK)
{
int nCount = zkfp2.GetDeviceCount();
if (nCount < 0)
{
zkfp2.Terminate();
label1.Text = "未发现指纹采集设备!";
}
}
else
{
label1.Text = "初始化失败, 返回值为:" + ret;
}
}
private void notifyIcon1_Click(object sender, EventArgs e)
{
if (base.Visible)
{
base.Hide();
return;
}
base.Show();
}
}
}
服务端指纹数据转图片:
using System;
using System.Runtime.InteropServices;
using System.IO;
namespace FP_Service
{
public class BitmapFormat
{
public struct BITMAPFILEHEADER
{
public ushort bfType;
public int bfSize;
public ushort bfReserved1;
public ushort bfReserved2;
public int bfOffBits;
}
public struct MASK
{
public byte redmask;
public byte greenmask;
public byte bluemask;
public byte rgbReserved;
}
public struct BITMAPINFOHEADER
{
public int biSize;
public int biWidth;
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public int biCompression;
public int biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public int biClrUsed;
public int biClrImportant;
}
/*******************************************
* 函数名称:RotatePic
* 函数功能:旋转图片,目的是保存和显示的图片与按的指纹方向不同
* 函数入参:BmpBuf---旋转前的指纹字符串
* 函数出参:ResBuf---旋转后的指纹字符串
* 函数返回:无
*********************************************/
public static void RotatePic(byte[] BmpBuf, int width, int height, ref byte[] ResBuf)
{
int RowLoop = 0;
int ColLoop = 0;
int BmpBuflen = width * height;
try
{
for (RowLoop = 0; RowLoop < BmpBuflen; )
{
for (ColLoop = 0; ColLoop < width; ColLoop++)
{
ResBuf[RowLoop + ColLoop] = BmpBuf[BmpBuflen - RowLoop - width + ColLoop];
}
RowLoop = RowLoop + width;
}
}
catch (Exception ex)
{
//ZKCE.SysException.ZKCELogger logger = new ZKCE.SysException.ZKCELogger(ex);
//logger.Append();
}
}
/*******************************************
* 函数名称:StructToBytes
* 函数功能:将结构体转化成无符号字符串数组
* 函数入参:StructObj---被转化的结构体
* Size---被转化的结构体的大小
* 函数出参:无
* 函数返回:结构体转化后的数组
*********************************************/
public static byte[] StructToBytes(object StructObj, int Size)
{
int StructSize = Marshal.SizeOf(StructObj);
byte[] GetBytes = new byte[StructSize];
try
{
IntPtr StructPtr = Marshal.AllocHGlobal(StructSize);
Marshal.StructureToPtr(StructObj, StructPtr, false);
Marshal.Copy(StructPtr, GetBytes, 0, StructSize);
Marshal.FreeHGlobal(StructPtr);
if (Size == 14)
{
byte[] NewBytes = new byte[Size];
int Count = 0;
int Loop = 0;
for (Loop = 0; Loop < StructSize; Loop++)
{
if (Loop != 2 && Loop != 3)
{
NewBytes[Count] = GetBytes[Loop];
Count++;
}
}
return NewBytes;
}
else
{
return GetBytes;
}
}
catch (Exception ex)
{
//ZKCE.SysException.ZKCELogger logger = new ZKCE.SysException.ZKCELogger(ex);
//logger.Append();
return GetBytes;
}
}
/*******************************************
* 函数名称:GetBitmap
* 函数功能:将传进来的数据保存为图片
* 函数入参:buffer---图片数据
* nWidth---图片的宽度
* nHeight---图片的高度
* 函数出参:无
* 函数返回:无
*********************************************/
public static void GetBitmap(byte[] buffer, int nWidth, int nHeight, ref MemoryStream ms)
{
int ColorIndex = 0;
ushort m_nBitCount = 8;
int m_nColorTableEntries = 256;
byte[] ResBuf = new byte[nWidth * nHeight*2];
try
{
BITMAPFILEHEADER BmpHeader = new BITMAPFILEHEADER();
BITMAPINFOHEADER BmpInfoHeader = new BITMAPINFOHEADER();
MASK[] ColorMask = new MASK[m_nColorTableEntries];
int w = (((nWidth + 3) / 4) * 4);
//图片头信息
BmpInfoHeader.biSize = Marshal.SizeOf(BmpInfoHeader);
BmpInfoHeader.biWidth = nWidth;
BmpInfoHeader.biHeight = nHeight;
BmpInfoHeader.biPlanes = 1;
BmpInfoHeader.biBitCount = m_nBitCount;
BmpInfoHeader.biCompression = 0;
BmpInfoHeader.biSizeImage = 0;
BmpInfoHeader.biXPelsPerMeter = 0;
BmpInfoHeader.biYPelsPerMeter = 0;
BmpInfoHeader.biClrUsed = m_nColorTableEntries;
BmpInfoHeader.biClrImportant = m_nColorTableEntries;
//文件头信息
BmpHeader.bfType = 0x4D42;
BmpHeader.bfOffBits = 14 + Marshal.SizeOf(BmpInfoHeader) + BmpInfoHeader.biClrUsed * 4;
BmpHeader.bfSize = BmpHeader.bfOffBits + ((((w * BmpInfoHeader.biBitCount + 31) / 32) * 4) * BmpInfoHeader.biHeight);
BmpHeader.bfReserved1 = 0;
BmpHeader.bfReserved2 = 0;
ms.Write(StructToBytes(BmpHeader, 14), 0, 14);
ms.Write(StructToBytes(BmpInfoHeader, Marshal.SizeOf(BmpInfoHeader)), 0, Marshal.SizeOf(BmpInfoHeader));
//调试板信息
for (ColorIndex = 0; ColorIndex < m_nColorTableEntries; ColorIndex++)
{
ColorMask[ColorIndex].redmask = (byte)ColorIndex;;
ColorMask[ColorIndex].greenmask = (byte)ColorIndex;
ColorMask[ColorIndex].bluemask = (byte)ColorIndex;
//ColorMask[ColorIndex].greenmask = (byte)ColorIndex;
//ColorMask[ColorIndex].bluemask = (byte)ColorIndex;
ColorMask[ColorIndex].rgbReserved = 0;
ms.Write(StructToBytes(ColorMask[ColorIndex], Marshal.SizeOf(ColorMask[ColorIndex])), 0, Marshal.SizeOf(ColorMask[ColorIndex]));
}
//图片旋转,解决指纹图片倒立的问题
RotatePic(buffer, nWidth, nHeight, ref ResBuf);
byte[] filter = null;
if (w - nWidth > 0)
{
filter = new byte[w - nWidth];
}
for (int i = 0; i < nHeight; i++)
{
ms.Write(ResBuf, i * nWidth, nWidth);
if (w - nWidth > 0)
{
ms.Write(ResBuf, 0, w - nWidth);
}
}
}
catch (Exception ex)
{
// ZKCE.SysException.ZKCELogger logger = new ZKCE.SysException.ZKCELogger(ex);
// logger.Append();
}
}
/*******************************************
* 函数名称:WriteBitmap
* 函数功能:将传进来的数据保存为图片
* 函数入参:buffer---图片数据
* nWidth---图片的宽度
* nHeight---图片的高度
* 函数出参:无
* 函数返回:无
*********************************************/
public static void WriteBitmap(byte[] buffer, int nWidth, int nHeight)
{
int ColorIndex = 0;
ushort m_nBitCount = 8;
int m_nColorTableEntries = 256;
byte[] ResBuf = new byte[nWidth * nHeight];
try
{
BITMAPFILEHEADER BmpHeader = new BITMAPFILEHEADER();
BITMAPINFOHEADER BmpInfoHeader = new BITMAPINFOHEADER();
MASK[] ColorMask = new MASK[m_nColorTableEntries];
int w = (((nWidth + 3) / 4) * 4);
//图片头信息
BmpInfoHeader.biSize = Marshal.SizeOf(BmpInfoHeader);
BmpInfoHeader.biWidth = nWidth;
BmpInfoHeader.biHeight = nHeight;
BmpInfoHeader.biPlanes = 1;
BmpInfoHeader.biBitCount = m_nBitCount;
BmpInfoHeader.biCompression = 0;
BmpInfoHeader.biSizeImage = 0;
BmpInfoHeader.biXPelsPerMeter = 0;
BmpInfoHeader.biYPelsPerMeter = 0;
BmpInfoHeader.biClrUsed = m_nColorTableEntries;
BmpInfoHeader.biClrImportant = m_nColorTableEntries;
//文件头信息
BmpHeader.bfType = 0x4D42;
BmpHeader.bfOffBits = 14 + Marshal.SizeOf(BmpInfoHeader) + BmpInfoHeader.biClrUsed * 4;
BmpHeader.bfSize = BmpHeader.bfOffBits + ((((w * BmpInfoHeader.biBitCount + 31) / 32) * 4) * BmpInfoHeader.biHeight);
BmpHeader.bfReserved1 = 0;
BmpHeader.bfReserved2 = 0;
Stream FileStream = File.Open("finger.bmp", FileMode.Create, FileAccess.Write);
BinaryWriter TmpBinaryWriter = new BinaryWriter(FileStream);
TmpBinaryWriter.Write(StructToBytes(BmpHeader, 14));
TmpBinaryWriter.Write(StructToBytes(BmpInfoHeader, Marshal.SizeOf(BmpInfoHeader)));
//调试板信息
for (ColorIndex = 0; ColorIndex < m_nColorTableEntries; ColorIndex++)
{
ColorMask[ColorIndex].redmask = (byte)ColorIndex;
ColorMask[ColorIndex].greenmask = (byte)ColorIndex;
ColorMask[ColorIndex].bluemask = (byte)ColorIndex;
ColorMask[ColorIndex].rgbReserved = 0;
TmpBinaryWriter.Write(StructToBytes(ColorMask[ColorIndex], Marshal.SizeOf(ColorMask[ColorIndex])));
}
//图片旋转,解决指纹图片倒立的问题
RotatePic(buffer, nWidth, nHeight, ref ResBuf);
//写图片
//TmpBinaryWriter.Write(ResBuf);
byte[] filter = null;
if (w - nWidth > 0)
{
filter = new byte[w - nWidth];
}
for (int i = 0; i < nHeight; i++)
{
TmpBinaryWriter.Write(ResBuf, i * nWidth, nWidth);
if (w - nWidth > 0)
{
TmpBinaryWriter.Write(ResBuf, 0, w - nWidth);
}
}
FileStream.Close();
TmpBinaryWriter.Close();
}
catch (Exception ex)
{
//ZKCE.SysException.ZKCELogger logger = new ZKCE.SysException.ZKCELogger(ex);
//logger.Append();
}
}
}
}
客户端,浏览器端代码:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>fp</title>
<meta name="description" content="fp">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="stylesheet" href="css/signature-pad.css">
<script src="/jquery.min.js" type="text/javascript"></script>
</head>
<body onselectstart="return false">
<div id="signature-pad" class="signature-pad">
<div>
</div>
<div class="signature-pad--body">
<table width="100%" border="0" cellspacing="0">
<tr align="center">
<td width="100%"><img src="https://img-blog.csdnimg.cn/2022010611375296516.png" alt="" width="256" height="288" id="imgDiv" align="middle" /></td>
</tr>
</table>
</div>
</div>
<script type="text/javascript">
var ws;
$(document).ready(function () {
// test if the browser supports web sockets
if ("WebSocket" in window) {
connect("ws://127.0.0.1:8891/");
} else {
$('#es').val('浏览器不支持此指纹仪!');
};
// function to send data on the web socket
function ws_send(str) {
try {
ws.send(str);
} catch (err) {
$('#es').val('error');
}
}
// connect to the specified host
function connect(host) {
$('#es').val('Connecting to " + host + " ...');
try {
ws = new WebSocket(host); // create the web socket
} catch (err) {
$('#es').val('error');
}
ws.onopen = function () {
// $('#es').val('设备连接成功!');
};
ws.onmessage = function (evt) {
var obj = evt.data;
var img = document.getElementById("imgDiv");
img.src = "data:image/png;base64," + obj;
};
ws.onclose = function () {
// document.getElementById("es").value = "Closed!";
};
};
});
</script>
</body>
</html>
以上就是全部代码,服务端运行后会自动注册服务到系统,下次开机可自启动,如果不想可在程序里关闭。(指纹识别采集的数据转图片后是黑色的,实际需要红色的,在这里通过判断图片像素点的色纸批量修改黑色到红色)。
我是一个为了做产品啥都学的程序员,希望这些文字能给你些许的帮助。